天天看点

.Net Core 依赖注入为什么要使用依赖注入框架.Net Core DIAutofac

.Net Core 依赖注入

  • 为什么要使用依赖注入框架
  • .Net Core DI
    • 核心类
    • 三种生命周期
    • 服务注册
      • 单例注册
      • 作用域注册
      • 瞬时注册
      • 直接注入实例
      • 工厂模式注册
      • 注册不同实例
      • 尝试注册
      • 移除和替换注册
      • 注册泛型模板
    • 使用依赖注入注意点
    • 实现 IDisposable 接口类型的释放
  • Autofac
    • 基于名称的注入
    • 属性注入
    • 子容器
    • 基于动态代理的 AOP

为什么要使用依赖注入框架

  • 借助依赖注入框架,将对象的创建交由容器管理,确保代码的可维护性和可扩展性。
  • .NET Core 的整个架构中,依赖注入框架提供了对象创建和生命周期管理的核心能力,各个组件相互协作,也是由依赖注入框架的能力来实现的。

.Net Core DI

.Net Core实现依赖注入两个包:

Microsoft.Extensions.DependencyInjection.Abstractions
Microsoft.Extensions.DependencyInjection 
           

Microsoft.Extensions.DependencyInjection.Abstractions 为抽象包,Microsoft.Extensions.DependencyInjection 为具体实现包

核心类

IServiceCollection
ServiceDescriptor
IServiceProvider
IServiceScope
           

IServiceCollection 负责注册,作为Startup类中ConfigureServices方法的参数,使用其对对象进行注册。

ServiceDescriptor 负责注入服务元素的描述

IServiceProvider 负责提供实例

IServiceScope 负责实例的生命周期

三种生命周期

  • 瞬时 Transient:每次请求,都获取一个新的实例;即使同一个请求获取多次也会是不同的实例。
  • 作用域 Scoped: 每次请求,都获取一个新的实例;同一个请求获取多次会得到相同的实例,即一个http请求内唯一。
  • 单例 Singleton:每次都获取同一个实例。

服务注册

单例注册

作用域注册

瞬时注册

直接注入实例

工厂模式注册

services.AddScoped<IMyService>(serviceProvider =>
 {
    return new MyService();
 });
           

注册不同实例

services.AddScoped<IMyService>(new MyService());
 services.AddScoped<IMyService>(new MyService2());
           

MyService和MyService2均实现了IMyService接口,并且进行了注册;使用的时候,默认是用的最后注册的(MyService2);如果要使用MyService, 需要遍历,根据实际类型来判断。

[HttpGet]
public async Tash GetServiceList([FromServices] IEnumerable<IMyService> services)
{
    foreach (var service in services)
    {
        if (service is MyService) //  if (service.GetType() == typeof(MyService))
        {
			// do sth
        }      
    }
}
           

尝试注册

services.TryAddScoped<IMyService>(new MyService());
 services.TryAddEnumerable(ServiceDescriptor.Scoped<IMyService, MyService>());
           

尝试注册会先判断实例是否已经注册,若注册了则不再进行注册;尝试注册可以有效的避免服务重复注册。

移除和替换注册

services.AddScoped<IMyService, MyService>();
 services.Replace(ServiceDescriptor.Singleton<IMyService, MyService2>());
 services.RemoveAll<IMyService>();
           

替换注册可以替换原有实例注册MyService为MyService2,RemoveAll则是移除所以实现了IMyService的注册实例。

注册泛型模板

使用依赖注入注意点

  • 避免通过静态属性的方式访问容器对象
  • 避免在服务内部使用 GetService 方式来获取实例
  • 避免使用静态属性存储单例,应该使用容器管理单例对象
  • 避免在服务中实例化依赖对象,应该使用依赖注入来获得依赖对象
  • 避免向单例的类型注入范围的类型

实现 IDisposable 接口类型的释放

  • DI 只负责释放由其创建的对象实例
  • DI 在容器或子容器释放时,释放由其创建的对象实例
  • 避免手动创建实现了 IDisposable 对象,应该使用容器来管理其生命周期

Autofac

Autofac的功能比.Net Core 的原生依赖注入更丰富,具体表现在:

  • 基于名称的注入
  • 属性注入
  • 子容器
  • 基于动态代理的 AOP

基于名称的注入

public void ConfigureContainer(ContainerBuilder builder)
{
    builder.RegisterType<MyService>().Named<IMyService>("s1");
    builder.RegisterType<MyService2>().Named<IMyService>("s1");
}
           

从IoC容器中使用ResolveNamed获取:

var s1 = container.ResolveNamed<IMyService>("s1");
var s2 = container.ResolveNamed<IMyService>("s2");
           

属性注入

使用PropertiesAutowired方法支持属性注入:

子容器

使用

var autofacContainer = app.ApplicationServices.GetAutofacRoot();
using (var myscope = autofacContainer.BeginLifetimeScope("myscope"))
{
    var service1 = myscope.Resolve<MyService>();
    using (var scope = myscope.BeginLifetimeScope())
    {
        var service2 = scope.Resolve<MyService>();
        Console.WriteLine($"service1=service2:{service1 == service2}");
    }
}
           

基于动态代理的 AOP

需要引用包:Autofac.Extras.DynamicProxy

先实现一个拦截器继承 IInterceptor

public class MyInterceptor : IInterceptor
    {
        public void Intercept(IInvocation invocation)
        {
            Console.WriteLine($"Intercept before,Method:{invocation.Method.Name}");
            invocation.Proceed();
            Console.WriteLine($"Intercept after,Method:{invocation.Method.Name}");
        }
    }
           

注册

这里实现了基于接口的拦截,也可以实现基于类的拦截;基于类的拦截时,方法需要定义为虚方法。