本文章介绍在 ASP.NET Core 中引入 Autofac 来增强容器能力
先决条件
.NET 8 SDK
介绍
Autofac 提供了一种灵活和可扩展的方式来管理对象的生命周期、解决依赖关系以及进行属性注入
Autofac 有一些强大的功能,例如
基于名称的注入 - 按照名称来区分它不同的实现的时候
属性注入 - 直接把服务注册到某一个类的属性中
子容器
基于动态代理的 AOP
用 Autofac 覆盖默认的 Ioc
在引入 Autofac Nuget 包后
在 Program 中注册 Autofac ,使用 UseServiceProviderFactory 方法
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) // 重写用于创建服务提供程序的工厂 // 把AutofacServiceProviderFactory注册进去 .UseServiceProviderFactory(new AutofacServiceProviderFactory()) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
复制代码
然后在 Startup 中添加一个 ConfigureContainer 方法
原本存在的 ConfigureServices 方法是注入默认的容器
服务注册进默认的容器以后会被 Autofac 接替
然后执行 ConfigureContainer 方法
使用方式
用 Autofac 覆盖默认的 Ioc 后
普通注册
使用 Autofac 的注册方式和 默认的 Ioc 框架注册方式略有不同
public void ConfigureContainer(ContainerBuilder builder) { // 先注册具体实现,然后是标记为哪个服务类型 builder.RegisterType<T>().As<IT>(); }
复制代码
使用时
public void Configure(IApplicationBuilder app) { // 也可以直接在构造函数中请求 ILifetimeScope ILifetimeScope AutofacContainer = app.ApplicationServices.GetAutofacRoot(); IT t = AutofacContainer.Resolve<IT>(); }
复制代码
基于名称注册
当我们需要将一个服务注册多次,并用不同命名来区分时
public void ConfigureContainer(ContainerBuilder builder) { // 使用Named builder.RegisterType<T>().Named<IT>("service2"); }
复制代码
使用时
public void Configure(IApplicationBuilder app) { // 也可以直接在构造函数中请求 ILifetimeScope ILifetimeScope AutofacContainer = app.ApplicationServices.GetAutofacRoot(); IT t = AutofacContainer.ResolveNamed<IT>("service2") }
复制代码
属性注入
属性注入使用 PropertiesAutowired 方法
#region Class public class T: IT { public Attribute Attr { get; set; } } public class Attribute { } #endregion public void ConfigureContainer(ContainerBuilder builder) { // 属性注入 builder.RegisterType<Attribute>(); builder.RegisterType<T>().As<IT>().PropertiesAutowired() }
复制代码
使用时 Attr 属性不为 NULL
public void Configure(IApplicationBuilder app) { // 也可以直接在构造函数中请求 ILifetimeScope ILifetimeScope AutofacContainer = app.ApplicationServices.GetAutofacRoot(); // t 的 Attr 属性不为 null IT t = AutofacContainer.Resolve<IT>(); }
复制代码
AOP
我们在不期望改变原有类的情况下,在方法执行时嵌入一下逻辑
让我们可以在方法执行的切面上任意插入我们的逻辑
#region Class public class MyInterceptor : IInterceptor { public void Intercept(IInvocation invocation) { Console.WriteLine($"intercept before");i // 不执行该语句 就不执行原有的方法 invocation.Proceed(); Console.WriteLine($"intercept after"); } }
public class T: IT { public void Write() { Console.WriteLine($"T_Write()"); } } #endregion
public void ConfigureContainer(ContainerBuilder builder) { #region AOP // 注册拦截器到容器中 builder.RegisterType<MyInterceptor>(); // builder.RegisterType<MyNameService>(); builder.RegisterType<T>().As<IT>() // 允许属性注册 .PropertiesAutowired() // 指定拦截器 .InterceptedBy(typeof(MyInterceptor)) // 实现接口拦截器 // (如果用类拦截器,方法需要设置为虚方法,允许继承类重载的情况下,才可以拦截到具体方法) .EnableInterfaceInterceptors(); #endregion }
复制代码
使用时
public void Configure(IApplicationBuilder app) { // 也可以直接在构造函数中请求 ILifetimeScope ILifetimeScope AutofacContainer = app.ApplicationServices.GetAutofacRoot(); // t 的 Attr 属性不为 null IT t = AutofacContainer.Resolve<IT>(); // 可以看到方法的执行顺序 t.Write(); }
复制代码
子容器
Autofac 具备给子容器命名的特性
public void ConfigureContainer(ContainerBuilder builder) { #region 子容器 builder.RegisterType<T>() // 将一个服务注入到特定命名为 myscope 的子容器中 .InstancePerMatchingLifetimeScope("myscope"); #endregion }
复制代码
使用时
public void Configure(IApplicationBuilder app) { // 也可以直接在构造函数中请求 ILifetimeScope ILifetimeScope AutofacContainer = app.ApplicationServices.GetAutofacRoot(); #region 子容器 // 创建了一个叫 myscope 的子容器 using (var myscope = AutofacContainer.BeginLifetimeScope("myscope")) { var t1= myscope.Resolve<T>(); using (var scope = myscope.BeginLifetimeScope()) { var t2= scope.Resolve<T>(); var t3= scope.Resolve<T>(); // 得到的都是同一个对象 var co1 = t1 == t2; // true var co2 = t1 == t3; // true } } #endregion }
复制代码
当我们不期望对象在根容器创建时,
又希望它在某一定范围内是单例模式的情况下,可以使用 子容器
参考文档
用Autofac增强容器能力 - 肖伟宇
评论