本示例使用 .net core 5 rc-1 實現。html
使用 Autofac 固然要添加 Autofac 的 Nuget 包,主要涉及到兩個:git
dotnet add package Autofac.Extensions.DependencyInjection
首先須要須要配置 Autofac 的容器工廠。github
因爲須要使用 Autofac 的容器,因此在構建應用程序的時候,須要使用 Autofac 的服務工廠。主程序 Program 中的 CreateHostBuilder() 方法須要增長一行,修改以後以下所示:web
public static IHostBuilder CreateHostBuilder (string[] args) => Host.CreateDefaultBuilder (args) .UseServiceProviderFactory (new AutofacServiceProviderFactory ()) .ConfigureWebHostDefaults (webBuilder => { webBuilder.UseStartup<Startup> (); }); }
而後,須要在 Startup() 中配置服務註冊。api
Autofac 的服務工廠會在調用 ConfigureServices() 以後,自動調用名爲 ConfigureContainer() 的方法,通常狀況下,咱們會在這個方法裏面使用 Autofac 來註冊服務。bash
在 Startup 文件中,添加以下的 ConfigureContainer() 方法。ContainerBuilder 是定義在命名空間 Autofac 中的,注意添加對該命名空間的引用。async
using Autofac; public void ConfigureContainer (ContainerBuilder builder) { ...... }
Autofac 提供了各類註冊服務的方法,不是微軟的 Addxxx() 方式,而是 Registerxxx() 方式。
例如,若是咱們已經定義了一個 IDbService 接口,而它的實現類型是 DbService。那麼,註冊服務的形式以下所示:ide
// register type, and enable interceptor injection builder.RegisterType<DbService> ().As<IDbService> () .InstancePerLifetimeScope ();
DbService 是註冊在容器中的實現類型,而 As<IDbService> 是在容器中註冊的類型。注入的時候須要使用這個接口類型。InstancePerLifetimeScope() 則是說明它的生命週期是 Scope 類型的。
能夠看到,在 Autofac 中,使用鏈式調用的方式來完成服務註冊。函數
Autofac 提供了一個名爲 Module 的概念,它支持將一組相關的服務註冊過程進行打包,以簡化配置和部署。
Autofac 提供了名爲 Autofac.IModule 接口,以及一個它的抽象實現類型 Autofac.Module。它的核心是 Load() 方法,用來完成服務的註冊。咱們能夠重載它以實現自定義的服務註冊,該方法的簽名以下:性能
protected virtual void Load( ContainerBuilder builder )
能夠看到該方法提供一樣的 ContainerBuilder 參數來提供服務註冊的支持。
這樣的話,前面的服務註冊能夠轉移到一個 Autofac 的 Module 中來。
咱們能夠定義一個服務註冊類,以下所示:
using Autofac; using Microsoft.AspNetCore.Mvc; public class ServiceAutofacModule : Autofac.Module { protected override void Load (ContainerBuilder builder) { // register type, and enable interceptor injection builder.RegisterType<DbService> ().As<IDbService> () .InstancePerLifetimeScope (); } }
而後,將 Startup() 中的 ConfigureContainer() 調整爲以下形式,使用 Module 的方式完成服務註冊。
public void ConfigureContainer (ContainerBuilder builder) { // use autofac module builder.RegisterModule<ServiceAutofacModule>(); }
Module 的使用詳見:https://autofaccn.readthedocs.io/en/latest/configuration/modules.html
// register type, and enable interceptor injection builder.RegisterType<DbService> ().As<IDbService> () .InstancePerLifetimeScope ();
var assembly = assembly.Load ("Domain.Services"); builder.registerAssemblyType (assembly) .AsImplementedInterfaces () .InstancePerLifetimeScope ();
下面的代碼中,先取得了 ControllerBase 的類型,而後在當前程序集中查找全部派生自 ControllerBase 的 Api 控制器
builder.RegisterAssemblyTypes(typeof(Program).Assembly) .Where(t => t.Name.EndsWith("Service")) .AsImplementedInterfaces() .InstancePerLifetimeScope();
Autofac 除了支持構造函數注入,還支持屬性注入,屬性注入會在構造函數注入以後進行。
必需要注意的是,必須在使用屬性注入的服務上進行聲明,
例如,若是 DbService 須要支持屬性注入,那麼須要在註冊該服務的時候進行聲明。
builder.RegisterType<DbService> ().As<IDbService> () .PropertiesAutowired() .InstancePerLifetimeScope ();
默認狀況下,ASP.NET Core 對於控制器並非從容器中建立的,因此若是你檢查容器中的註冊,是看不到控制器的註冊的。
爲了支持屬性注入,須要讓 ASP.NET Core 將控制器也註冊到容器中。這能夠在 AddControllers() 方法以後,調用 AddControllersAsServices() 來實現。
public void ConfigureServices (IServiceCollection services) { services.AddControllers() .AddControllersAsServices(); }
而後,咱們須要對控制器添加支持屬性注入的聲明。
既能夠針對單個的控制器類
// make property autowire at one controller builder.RegisterType<WeatherForecastController>() .PropertiesAutowired();
也能夠針對全部的控制器。
// make property autowire at all api controller var controllerBaseType = typeof (ControllerBase); builder.RegisterAssemblyTypes (typeof (Program).Assembly) .Where (t => controllerBaseType.IsAssignableFrom (t) && t != controllerBaseType) .PropertiesAutowired ();
使用 AOP 須要以下的 4 個步驟。
攔截器的接口 IInterceptor 定義在命名空間 Castle.DynamicProxy 中,須要注意的是,它須要添加對 NuGet 包 Autofac.Extras.DynamicProxy 的引用。
dotnet add package Autofac.Extras.DynamicProxy
實現 IInterceptor 接口。
using Castle.DynamicProxy; using System; public class DbServiceInterceptor:IInterceptor { public virtual void Intercept(IInvocation invocation) { Console.WriteLine($"{DateTime.Now}: Before method execting. "); invocation.Proceed(); Console.WriteLine($"{DateTime.Now}: After method exected."); } }
攔截器也一樣須要註冊到容器中。
// register interceptor builder.RegisterType<DbServiceInterceptor> ();
須要支持攔截器的服務須要啓用攔截器,而後才能使用攔截器。
// register type, and enable interceptor injection builder.RegisterType<DbService> ().As<IDbService> () .EnableInterfaceInterceptors () .InstancePerLifetimeScope ();
可使用 EnableInterfaceInterceptors() 或者 EnableClassInterceptors() 擴展方法來啓用攔截器。
EnableInterfaceInterceptors() 建立接口代理來執行攔截,而 EnableClassInterceptors() 則建立目標組件的子類來執行攔截。
第一種方式是在使用攔截器的服務上,經過特性來聲明使用的攔截器。
using Autofac.Extras.DynamicProxy; using Castle.DynamicProxy; [Intercept (typeof (DbServiceInterceptor))] public class DbService : IDbService { public string Say () { return "Hello"; } }
當使用特性來關聯攔截器的時候,不須要在註冊服務的時候指定攔截器。你只須要啓用,實際的攔截器將被自動發現。
第二種方式是在註冊服務的時候指定,使用 InterceptedBy() 擴展方法。
builder.RegisterType<SomeType>() .EnableClassInterceptors() .InterceptedBy(typeof(CallLogger));
注意:
已知問題: