天天看點

.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}");
        }
    }
           

注冊

這裡實作了基于接口的攔截,也可以實作基于類的攔截;基于類的攔截時,方法需要定義為虛方法。