构建ASP.NET Core应用程序的时候,依赖注入已成为了.NET Core的核心,这篇文章,我们理一理依赖注入的使用方法。

不使用依赖注入

首先,我们创建一个ASP.NET Core Mvc项目,定义个表达的爱服务接口,中国小伙类实现这个类如下:

public interface ISayLoveService
{
string SayLove();
} public class CNBoyService : ISayLoveService
{
public string SayLove()
{
return "安红,我喜欢你";
}
}

在LoveController 控制器中调用 ISayLoveService的SayLove方法。

public class LoveController : Controller

    {
private ISayLoveService loveService;
public IActionResult Index()
{
loveService = new CNBoyService(); //中国小伙对安红的表达
ViewData["SayLove"] = loveService.SayLove();
return View();
}
}

输出如图:

小结:LoveController控制器调用ISayLoveService服务的SayLove方法;我们的做法,直接在控制器去new CNBoyService()实例对象,也就是LoveController依赖ISayLoveService类。

思考:能不能有种模式,new实例不要在使用的时候进行创建,而是在外部或者有一个容器进行管理;这不就是ioc思想吗?好处,代码的解耦、代码更好的维护等等。

使用依赖注入

上面的疑惑,答案是肯定的,有!并且ASP.NET Core 支持依赖关系注入 (DI) 软件设计模式(当然也可以兼容第三方)。我们还使用上面的代码,

服务注册

在Startup类ConfigureServices方法中注册服务容器中的依赖关系

  public void ConfigureServices(IServiceCollection services)

        {
services.AddSingleton<ISayLoveService, CNBoyService>();
services.AddControllersWithViews();
}

在LoveControlle控制器中,通过构造函数注入

 private readonly  ISayLoveService loveService;  
public LoveController(ISayLoveService loveService)
{ this.loveService = loveService;
} public IActionResult Index()
{

ViewData["SayLove"] = loveService.SayLove(); return View();
}

LoveController 正在将ISayLoveService作为依赖项注入其构造函数中,然后在Index方法中使用它。

推荐:

  • 将注入的依赖项分配给只读字段/属性(以防止在方法内部意外为其分配另一个值)。

  • 使用接口或基类抽象化依赖关系实现。

小结:在控制器中,还有几种使用如:[FromServices] 标签 、 HttpContext.RequestServices.GetService<T>();我们发现可以使用ASP.NET Core 提供了一个内置的服务容器 IServiceProvider。服务只需要在Startup.ConfigureServices 方法中注册,然后在运行时将服务注入 到使用它的类的构造函数中。 框架负责创建依赖关系的实例,并在不再需要时对其进行处理。

思考:服务注册的时候使用的是 AddSingleton,如services.AddSingleton<ISayLoveService, CNBoyService>();还有其他的吗?

服务生命周期

服务注册的时候,ASP.NET Core支持指定三种生命周期如:

  1. Singleton 单例

  2. Scoped 范围

  3. Transient 短暂的

Singleton 仅创建一个实例。该实例在需要它的所有组件之间共享。因此始终使用同一实例。

Scoped 每个范围创建一个实例。在对应用程序的每个请求上都会创建一个范围,因此每个请求将创建一次注册为Scoped的任何组件。

Transient 在每次被请求时都会创建,并且永不共享。

为了能够更好的裂解生命周期的概念,我们把上面代码稍作改动,做一个测试:

ISayLoveService 新增个属性LoveId,类型为guid,

public interface ISayLoveService
{
Guid LoveId { get; }
string SayLove();
}
public interface ITransientSayLoveService : ISayLoveService
{
}
public interface IScopedSayLoveService : ISayLoveService
{
}
public interface ISingletonSayLoveService : ISayLoveService
{
}
public interface ISingletonInstanceSayLoveService : ISayLoveService
{
}

BoyService也很简单,在构造函数中传入一个Guid,并对它进行赋值。

public class BoyService : ITransientSayLoveService,
IScopedSayLoveService,
ISingletonSayLoveService,
ISingletonInstanceSayLoveService
{
public BoyService():this(Guid.NewGuid()) { }
public BoyService(Guid id)
{
LoveId = id;
}
public Guid LoveId { get; private set; } public string SayLove()
{
return LoveId.ToString();
}
}

每个实现类的构造函数中,我们都产生了一个新的guid,通过这个GUID,我们可以判断这个类到底重新执行过构造函数没有.

服务注册代码如下:

   public void ConfigureServices(IServiceCollection services)
{
//生命周期设置为Transient,因此每次都会创建一个新实例。
services.AddTransient<ITransientSayLoveService, BoyService>();
services.AddScoped<IScopedSayLoveService, BoyService>();
services.AddSingleton<ISingletonSayLoveService, BoyService>();
services.AddSingleton<ISingletonInstanceSayLoveService>(new BoyService(Guid.Empty)); services.AddControllersWithViews();
}

在LifeIndex方法中多次调用ServiceProvider的GetService方法,获取到的都是同一个实例。

  public IActionResult LifeIndex()
{
ViewData["TransientSayLove1"] = HttpContext.RequestServices.GetService<ITransientSayLoveService>().SayLove();
ViewData["ScopedSayLove1"] = HttpContext.RequestServices.GetService<IScopedSayLoveService>().SayLove();
ViewData["SingletonSayLove1"] = HttpContext.RequestServices.GetService<ISingletonSayLoveService>().SayLove();
ViewData["SingletonInstanceSayLove1"] = HttpContext.RequestServices.GetService<ISingletonInstanceSayLoveService>().SayLove();
//同一个HTTP请求 ,在从容器中获取一次
ViewData["TransientSayLove2"] = HttpContext.RequestServices.GetService<ITransientSayLoveService>().SayLove();
ViewData["ScopedSayLove2"] = HttpContext.RequestServices.GetService<IScopedSayLoveService>().SayLove();
ViewData["SingletonSayLove2"] = HttpContext.RequestServices.GetService<ISingletonSayLoveService>().SayLove();
ViewData["SingletonInstanceSayLove2"] = HttpContext.RequestServices.GetService<ISingletonInstanceSayLoveService>().SayLove(); return View();
}

我们编写view页面,来展示这些信息如下:

@{
ViewData["Title"] = "LifeIndex";
} <div class="row">
<div class="panel panel-default">
<div class="panel-heading">
<h2 class="panel-title">Operations</h2>
</div>
<div class="panel-body">
<h3>获取第一次</h3>
<dl>
<dt>Transient1</dt>
<dd>@ViewData["TransientSayLove1"] </dd>
<dt>Scoped1</dt>
<dd>@ViewData["ScopedSayLove1"]</dd>
<dt>Singleton1</dt>
<dd>@ViewData["SingletonSayLove1"] </dd>
<dt>Instance1</dt>
<dd>@ViewData["SingletonInstanceSayLove1"]</dd>
</dl>
<h3>获取第二次</h3>
<dl>
<dt>Transient2</dt>
<dd>@ViewData["TransientSayLove2"]</dd>
<dt>Scoped2</dt>
<dd>@ViewData["ScopedSayLove2"]</dd>
<dt>Singleton2</dt>
<dd>@ViewData["SingletonSayLove2"]</dd>
<dt>Instance2</dt>
<dd>@ViewData["SingletonInstanceSayLove2"]</dd>
</dl>
</div>
</div>
</div>

运行代码第一次输出:

我们发现,在一次请求中,发现单例、范围的生命周期的guid 没有变化,说明分别用的是同一个对象,而瞬态guid不同,说明对象不是一个。

刷新之后,查看运行效果

我们发现通过刷新之后,单例模式的guid还是跟首次看到的一样,其他的都不同;

总结:如果您将组件A注册为单例,则它不能依赖已注册“作用域”或“瞬态”生存期的组件。一般而言:组件不能依赖寿命短于其寿命的组件。如果默认的DI容器不能满足项目需求,可以替换成第三方的如功能强大的Autofac。

.Net Core3.0依赖注入DI的更多相关文章

  1. Yii2.0 依赖注入(DI)和依赖注入容器的原理

    依赖注入和依赖注入容器 为了降低代码耦合程度,提高项目的可维护性,Yii采用多许多当下最流行又相对成熟的设计模式,包括了依赖注入(Denpdency Injection, DI)和服务定位器(Serv ...

  2. 05、NetCore2.0依赖注入(DI)之Web应用启动流程管理

    05.NetCore2.0依赖注入(DI)之Web应用启动流程管理 在一个Asp.net core 2.0 Web应用程序中,启动过程都做了些什么?NetCore2.0的依赖注入(DI)框架是如何管理 ...

  3. 06、NetCore2.0依赖注入(DI)之整合Autofac

    06.NetCore2.0依赖注入(DI)之整合Autofac 除了使用NetCore2.0系统的依赖注入(DI)框架外,我们还可以使用其他成熟的DI框架,如Autofac.Unity等.只要他们支持 ...

  4. 07、NetCore2.0依赖注入(DI)之生命周期

    07.NetCore2.0依赖注入(DI)之生命周期 NetCore2.0依赖注入框架(DI)是如何管理注入对象的生命周期的?生命周期有哪几类,又是在哪些场景下应用的呢? -------------- ...

  5. ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下

    ADO.NET   一.ADO.NET概要 ADO.NET是.NET框架中的重要组件,主要用于完成C#应用程序访问数据库 二.ADO.NET的组成 ①System.Data  → DataTable, ...

  6. 控制反转(Ioc)和依赖注入(DI)

    控制反转IOC, 全称 “Inversion of Control”.依赖注入DI, 全称 “Dependency Injection”. 面向的问题:软件开发中,为了降低模块间.类间的耦合度,提倡基 ...

  7. 控制反转IOC与依赖注入DI【转】

    转自:http://my.oschina.net/1pei/blog/492601 一直对控制反转.依赖注入不太明白,看到这篇文章感觉有点懂了,介绍的很详细. 1. IoC理论的背景我们都知道,在采用 ...

  8. 依赖注入(DI)和Ninject

    [ASP.NET MVC 小牛之路]04 - 依赖注入(DI)和Ninject 本文目录: 1.为什么需要依赖注入 2.什么是依赖注入 3.使用NuGet安装库 4.使用Ninject的一般步骤 5. ...

  9. iOS控制反转(IoC)与依赖注入(DI)的实现

    背景 最近接触了一段时间的SpringMVC,对其控制反转(IoC)和依赖注入(DI)印象深刻,此后便一直在思考如何使用OC语言较好的实现这两个功能.Java语言自带的注解特性为IoC和DI带来了极大 ...

随机推荐

  1. Android Studio [Toast]

    ToastActivity.java package com.xdw.a122; import android.support.v7.app.AppCompatActivity; import and ...

  2. Android Studio [水平布局LinearLayout]

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  3. pikachu-数字型注入(post)#手工注入

    1, 因为是post型,所以需要抓取数据包 2, 测试结果为数字型注入 提交恒等的语句可以查询到所有的数据信息 3, 使用UNION联合查询法 判断字段数,测试为2个字段时没有报错,所以可以判断字段数 ...

  4. 电脑链接WiFi有网络不能上网问题

    刚刚入手了一个小米book pro笔记本突然发现网络链接了,但是却上不了网.找了n种方法,最后发现问题在于电脑的网络适配器中的无线模式出现了问题,下面开始解决方案的详细步骤说明. 一 . 打开电脑管理 ...

  5. 使用gtest(googletest)进行c++单元测试

    这是系列文章的第三篇,前两篇https://www.cnblogs.com/gaopang/p/11243367.html和https://www.cnblogs.com/gaopang/p/1158 ...

  6. YiShaAdmin,基于.NET Core Web开源的后台快速开发框架

    YiShaAdmin YiShaAdmin 基于.NET Core Web开发,借鉴了很多开源项目的优点,让你开发Web管理系统和移动端Api更简单,所以我也把她开源了. 她可以用于所有的Web应用程 ...

  7. python爬虫—— 抓取今日头条的街拍的妹子图

    AJAX 是一种用于创建快速动态网页的技术. 通过在后台与服务器进行少量数据交换,AJAX 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新. 近期在学习获取j ...

  8. 浅拷贝&深拷贝的对比

    js中两种数据类型 浅拷贝:拷贝就是拷贝指向对象的指针,意思就是说:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间,浅拷贝只是一种简单的拷贝,让几个对象公用一个内存,然而当内存销毁的 ...

  9. Jetpack系列:Paging组件帮你解决分页加载实现的痛苦

    相信很多小伙伴们在项目实战中,经常会用到界面的分页显示.加载更多等功能.需要针对具体功能做针对性开发和调试,耗时耗力. Paging组件的使用将这部分的工作简化,从而让开发者更专注于业务的具体实现.下 ...

  10. MongoDB 学习笔记之 $push,$each,$slice组合使用

    $push使用: 使用$push给数组添加2个新成员 db.ArrayTest.updateOne({ "name" : "Bill"},{$push: {&q ...