文章

.NET 依赖注入

ASP.NET Core 支持依赖项注入(DI)软件设计模式,这是一种用于在类及其依赖项之间实现控制反转(IoC)的技术。

引用nuget包

.net core 使用了接口与实现分离的设计模式,这样的好处是第三方的 Ioc 容器只需要引用 Microsoft.Extensions.DependencyInjection.Abstractions 包,并实现其中的接口,就可以与 .net core 框架完美兼容了。

1
2
Microsoft.Extensions.DependencyInjection.Abstractions
Microsoft.Extensions.DependencyInjection

简单示例 

声明接口及其实现类

1
2
3
4
5
6
//声明一个接口
public interface IVipService    
{}
//声明IVipService接口的实现类
public class VipService : IVipService 
{}

Startup.csConfigureServices 方法中将接口实现添加到 Ioc 容器

1
2
3
4
5
public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IVipService, VipService>();
    services.AddControllers();
}

通过构造函数注入: 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private readonly IVipService _vipService;

    public WeatherForecastController( IVipService vipService)  //在构造函数中注入IVipService接口
    {
        _vipService = vipService;
    }

    [HttpGet]
    public string Get( )
    {
        return _vipService.GetHashCode().ToString();
    }
}

通过方法注入:

1
2
3
4
5
6
7
8
9
10
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{

    [HttpGet]
    public string Get([FromServices]IVipService vipService)  // 在方法入参中使用[FromServices]特性注入IVipService接口
    {
        return vipService.GetHashCode().ToString();
    }
}

这样我们就完成了一个依赖注入的简单示例,当有请求路由到 WeatherForecastController 控制器时,依赖注入框架会自动将Ioc容器中的实现类创建好注入到 WeatherForecastController 中,这样 WeatherForecastController 也就不在依赖于 IVipService 的具体实现类,如果需要更换 IVipService 的实现,那么只需要修改 services.AddScoped<IVipService, VipService>(); 这一段代码就可以了。

生命周期  

.net core 的依赖注入框架支持创建三种不同生命周期的服务。

1
2
3
4
5
6
7
8
9
public enum ServiceLifetime
{
    // 单例模式
    Singleton = 0,
    // 作用域模式
    Scoped = 1,
    // 瞬时模式
    Transient = 2
}
  • Singleton :单例模式,在整个应用程序的生命周期内,每次调用都使用同一个实例。
  • Scoped :作用域模式,在同一个作用域内,每次调用都使用同一个实例。
  • Transient:瞬时模式,每次调用都会创建一个新的实例。

三种生命周期,使用下面三种不同的方法注入

1
2
3
services.AddSingleton<IVipService, VipService>();
services.AddScoped<IVipService, VipService>();
services.AddTransient<IVipService, VipService>();

实现了 IDisposable 接口并且由容器创建的实例由容器主动释放,其他的实例生命周期结束后由 GC 释放。

泛型模板注入

1
services.AddSingleton(typeof(IVipService<>),typeof(VipService<>)); 

工厂注入(用以处理一些特殊的情况)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//一个接口 两个实现类 
public interface IVipService
{
}

public class ErpVipService : IVipService
{
}

public class WxVipService : IVipService
{
}
//将工厂包装一层
public class VipServiceFactory
{
    private readonly Func<int, IVipService> _func;
    public VipServiceFactory(Func<int, IVipService> func)
    {
        _func = func;
    }
    public IVipService GetInstence(int type)
    {
        return _func(type);
    }
}
//注入扩展类
public static class VipServiceExtensions
{
    public static IServiceCollection AddVipService(this IServiceCollection services)
    {
        services.AddScoped<ErpVipService>();
        services.AddScoped<WxVipService>();
        //通过工厂方式根据类型条件决定创建哪个实现类   //该方法在所线程情况下,可能会遇到serviceProvider已被释放的问题。 
        services.AddScoped(serviceProvider =>
        {
            Func<int, IVipService> func = type =>
            {
                if (type == 0) return (IVipService)serviceProvider.GetService<ErpVipService>();
                else
                    return (IVipService)serviceProvider.GetService<WxVipService>();
            };
            return func;
        });

        services.AddScoped<VipServiceFactory>();
        return services;
    }
}

ConfigureServices 中注入

1
2
3
4
5
public void ConfigureServices(IServiceCollection services)
{
    services.AddVipService();
    services.AddControllers();
}

控制器中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private readonly VipServiceFactory _vipServiceFactory;
    
    //将工厂类注入到构造函数
    public WeatherForecastController(VipServiceFactory vipServiceFactory)
    {
        _vipServiceFactory = vipServiceFactory;
    }

    [HttpGet]
    public string Get( )
    {
      return   _vipServiceFactory.GetInstence(0).GetHashCode().ToString();
    }
}

开源框架推荐

  • Scrutor: Kristian Hellang 大神写的一个基于 Microsoft.Extensions.DependencyInjection 的一个扩展库,主要是为了简化我们对DI的操作。
  • Autofac: .NET 领域最为流行的 IoC 框架之一,功能多,性能好,易学习。 

参考资源

源码地址

官方文档

本文由作者按照 CC BY 4.0 进行授权