.Net Core官方DI框架

NetCore提供了方法的DI框架,并在AspNetCore中大量使用了该注入框架。它是通过扩展包的形式提供出来,使用时通过Nuget包Microsoft.Extensions.DependencyInjection来使用。相对与其他DI框架,它比较轻量,且只支持构造器注入,不支持属性注入、以及方法注入。

使用起来比较简单,一般步骤如下所示:

// 1. 注册服务
var serviceCollection = new ServiceCollection();
   .AddSingleton()
   .AddTransient()
   .BuildServiceProvider())

// 2. 构建服务提供者
ServiceProvider serviceProvider serviceCollection.BuildServiceProvider();

// 3.然后其他地方都可以通过这个Provider.GetService()方法来获取服务
var IFoo = serviceProvider.GetService();

服务的注册方式

服务一般有以下几种方式:

  • serviceCollection.Add(ServiceDescriptor item)
  • serviceCollection.AddXXX()
  • serviceCollection.AddXXX(Func implementationFactory)

下面几句作用相同

serviceCollection.AddTransient();
serviceCollection.Add(new ServiceDescriptor(typeof(IFoo),typeof(Foo), ServiceLifetime.Transient));
serviceCollection.AddTransient(provider => new Foo());

服务提供者 ServiceProvider

服务实例的创建、销毁均由ServiceProvider负责维护,生成的服务实例一般不要执行对象的Dispose方法(如果有的话),因为服务实例有可能被其他地方使用。

当释放ServiceProvider时,该Provider将会释放由它生成的对象。

在生成实例时,如果对象实现了Dispose接口,它会把该对象保存在_disposables列表中,当Provider释放时,当即会自动调用_disposables元素对象的Dispose方法

而ServiceProvider本身又可以创建新的ServiceProvider,这样就相当生成了一个作用域 Scope。

服务的生命周期

生命周期分为三种:

  • 瞬态 Transient: 每一次从ServiceProvider取得,均返回一个新的实例。
  • 作用域 Scope:在同一作用域下生成的实例相同,即同一个ServiceProvider下取得的实例相同
  • 单例 Singleton: 任意一个ServiceProvider下取得的实例都相同

作用域主要针对特定ServiceProvider的,即在同一个ServiceProvider下,注册为Scope类型的对象为单例

示例

using (ServiceProvider rootProvider = new ServiceCollection()
   .AddTransient()
   .AddScope()
   .AddSingleton()
   .BuildServiceProvider())
{
    IFoo foo = rootProvider.GetService();
    IFoo foo2 = rootProvider.GetService();

    IBar bar = rootProvider.GetService();
    IBar bar2 = rootProvider.GetService();

    IFoobar foobar = rootProvider.GetService();
    IFoobar foobar2 = rootProvider.GetService();

    IFoo foo3 = null;
    IBar bar3 = null;
    IFoobar foobar3 = null;
    using(var scope = rootProvider.CreateScope())
    {
        var childProvider = scope.ServiceProvider;
        foo3 = childProvider.GetService();
        bar3 = childProvider.GetService();
        foobar3 = childProvider.GetService();
    }

    var childProvider2 = rootProvider.CreateScope().ServiceProvider;
    IFoo foo3 = childProvider2.GetService();
    
    // 执行点1
}

// 执行点2

实例对象说明

  • IFoo 注册为Transient,则 foo foo2,foo3 均不等
  • IBar 注册为Scope,则 bar==bar2(因为他们都是同一个rootProvider提供),bar2 <> bar2(因为他们是不同的Provider提供,一个为rootProvider,一个为childProvider)
  • IFoobar 注册为Singleton,所以 foobar == foobar2 == foobar3

释放实例时机

  • 执行到【执行点1】时,释放:
    • childProvider本身,childProvider再释放由其创建的 bar3、foo3
    • bar3
    • foo3
  • 执行到【执行点2】时,释放:
    • rootProvider本身
    • foo
    • foo2
    • bar, (没有bar2,因为bar2就是bar)
    • childProvider2,以及由childProvider2创建的foo3

在ASP.Net Core中使用

在asp.net core中主要有两个ServiceProvider,可以通过它们手动取到对应的服务实例

  • WebHost中的ServiceProvider,即 webHost.Services
  • Http请求中HttpContext的ServiceProvider,即 HttpContext.RequestServices

它们的关系是父子关系:Http请求中ServiceProvider是中间件RequestServicesContainerMiddleware根据WebHost的ServiceProvider生成。

Http请求结束后,将会释放Http请求中ServiceProvider,并释放掉该作用域下的实例对象

注入方式

public class SampleController ControllerBase
{
    // 1.第一种:构造函数注入
    private IService _service = null;
    public SampleController(IService service)
    {
        this._service = service;
    }

    // 2.第二种:通过方法注入
    [HttpPost]
    public IActionResult Method1([FromServices] IService service) => service.DoSomething()
    
    // 3.第三种:通过HttpContext,手动取得
    [HttpGet]
    public IActionResult Method2() 
    {
        IService service = HttpContext.RequestServices.GetService<>(IService);
        ...
    }
    ...
}

使用其他第三成熟的Ioc框架(不推荐使用)

官方DI框架它可以被其他成熟的Ioc框架所代替,但是可以把.NetCore DI框架作为一个“包装器”,可以插入其他DI框架(例如 Autofac、Unity等)
插入其他DI框架的目的,主要是想利用其它框架一些优点,比如批量注册、属性注入等。

替换的方法,主要是再注册服务方法ConfigureServices的时候,用第三方DI扩展实现的IServiceProvider替换掉官方DI的IServiceProvider。

目前实现了官方DI扩展的第三方框架有 AspectCore、Autofac、Unity,虽然使用第三方DI框架带来了一些便利,但同时带来了对于第三方DI容器特性的依赖

在Asp.net Core中使用 Autofac

public IServiceProvider ConfigureServices(IServiceCollection services)
{
     services.AddApplicationInsightsTelemetry(Configuration);
     services.AddMvc();
     return RegisterAutofac(services);
}

private IServiceProvider RegisterAutofac(IServiceCollection services)
{
     var builder = new ContainerBuilder();
     builder.Populate(services);
     var assembly = this.GetType().GetTypeInfo().Assembly;
     builder.RegisterType();
     builder.RegisterAssemblyTypes(assembly)
                  .Where(type =>
                   typeof(IDependency).IsAssignableFrom(type) && !type.GetTypeInfo().IsAbstract)
                  .AsImplementedInterfaces()
                  .InstancePerLifetimeScope().EnableInterfaceInterceptors().InterceptedBy(typeof(AopInterceptor));
      this.ApplicationContainer = builder.Build();
      return new AutofacServiceProvider(this.ApplicationContainer);
}

你可能感兴趣的:(.NET)