本示例使用 .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));
注意:
已知问题: