前言
當前引入了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
}
當我們不期望對象在根容器創建時,
又希望它在某一定範圍內是單例模式的情況下,可以使用 子容器。