前言
当前引入了NuGet包
$ Install-Package Autofac.Extras.DynamicProxy -Version 4.5.0
$ Install-Package Autofac.Extensions.DependencyInjection -Version 5.0.1
一、什么情况需要引入第三方容器组件
- 基于名称的注入 - 按照名称来区分它不同的实现的时候
- 属性注入 - 直接把服务注册到某一个类的属性中
- 子容器
- 基于动态代理的AOP
二、用Autofac覆盖默认的Ioc
在引入两个 Autofac 的包后
在 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后
1) 普通注册
使用 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>();
}
2) 基于名称注册
当我们需要将一个服务注册多次,并用不同命名来区分时
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")
}
3) 属性注入
属性注入使用 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>();
}
4) 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();
}
4) 子容器
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
}
当我们不期望对象在根容器创建时,
又希望它在某一定范围内是单例模式的情况下,可以使用 子容器。