本文章介绍在 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增强容器能力 - 肖伟宇
评论