ASP.NET Core 6.0 關於Autofac 使用
本文第一節從基本的概念說起;
第二節以文字的方式,列出 Autofac 的使用步驟;
第三節,結合實際的代碼,展示如何對 Autofac 進行配置;
第四節(未完成),將展示如何使用 Autofac 注入的服務;
第五節開始,將常用的注入方式、生命周期等記錄下來,以便翻查;
最后將會有一節其他內容,比如:描述 Autofac 如何支持 AOP。
1 基本概念
1.1 相關名詞
依賴倒置(DIP)
控制反轉(IoC:Inversion of control)
注入(DI:Dependency injection)
1.2 個人理解
DIP 依賴倒置原則:程序要依賴於抽象,不要依賴於細節(具體實現)。其中抽象一般指接口(Interface),細節指類(Class)。
IoC 一般翻譯為控制反轉,主要是為了降低模塊與模塊之間代碼的耦合度,是一種理念,一種設計原則。
DI 是 IoC 的一種實現方式,為依賴注入的方式。具體做法就是通過一個統一的容器(DI 容器),來管理對象的創建和生命周期。
2 使用步驟
2.1 基本使用
- 引入 Autofac
- 在程序入口處:創建容器(Create a ContainerBuilder),注冊服務/組件(Register Components),構建並存儲容器(Build and store)
- 在程序執行過程中:從容器中創建擁有生命周期的實例(lifetime scope)
對應3.2基本使用
2.2 在ASP.NET Core 中使用(.NET6)
替換工廠方式:
- 引入 Autofac.Extensions.DependencyInjection
- 在程序入口處,替換 ServiceProviderFactory
- 調用 ConfigureContainer 方法,注冊自定義 Autofac 的 Module
3 實際配置
本節會提供多種配置方式,如基本配置方式(可應用於一般程序),.NET6配置方式(Web程序),配置文件等方式,選擇其中一種配置方式即可。
3.1 引入
方式一:界面 NuGet 包添加
方式二:控制台引入 NuGet 包
Install-package Autofac -Version 6.3.0
方式三:修改工程文件
<PackageReference Include="Autofac" Version="6.3.0" />
3.2 基本使用
//1、創建容器 Create a ContainerBuilder
ContainerBuilder containerBuilder = new ContainerBuilder();
//2、注冊服務(官方稱 Component)
containerBuilder.RegisterType<TestService>().As<ITestService>();
//3、構建容器,創建實例;需要把 container 存儲起來以便后續使用
IContainer container = containerBuilder.Build();
//4、使用 container 創建實例
var service = container.Resolve<ITestService>();
3.3 .NET6中使用
1)引入 Autofac.Extensions.DependencyInjection
2)代碼
//在 var app = builder.Build(); 前加入使用 Autofac 相關代碼
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
{
builder.RegisterModule<AutofacModule>();
});
其中,AutofacModule 為自定義的 Autofac 配置類,實現如下:
public class AutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
//把服務的注入規則寫在這里
builder.RegisterType<TestService>().As<ITestService>();
}
}
注:
工廠模式下,Autofac 在自己注冊服務之前,會先把 ServiceCollection 中注冊的服務全部接管過來,所以通過 .NET6 默認的 DI 容器方式注入的服務,也生效。
3.4 其他配置方式
3.4.1 配置文件方式
1)引入程序集:Autofac.Configuration
2)配置文件:
{
"defaultAssembly": "TestMiniAPI",
"components": [
{
"type": "TestMiniAPI.Services.TestService, TestMiniAPI",
"services": [
{
"type": "TestMiniAPI.Services.ITestService, TestMiniAPI"
}
],
"instanceScope": "single-instance",
"injectProperties": true
}
]
}
3)配置代碼
ContainerBuilder containerBuilder = new ContainerBuilder();
IConfigurationBuilder config = new ConfigurationBuilder();
IConfigurationSource autofacJsonConfigSource = new JsonConfigurationSource()
{
Path = "ConfigFile/autofac.json",
Optional = false, //默認是false
ReloadOnChange = true, //默認是true
};
config.Add(autofacJsonConfigSource);
ConfigurationModule module = new ConfigurationModule(config.Build());
containerBuilder.RegisterModule(module);
4 實際使用
本節主要展示如何使用注入的服務。
4.1 構造函數注入
這是最常見的方式,也是默認的注入方式。
//在 Program.cs 中注入服務
containerBuilder.RegisterType<TestService>().As<ITestService>();
//構造函數注入
public class TestController
{
private readonly ITestService _testService;
public TestController(ITestService testService)
{
_testService = testService;
}
}
5 注冊組件
官方文檔:https://autofac.readthedocs.io/en/latest/register/registration.html
5.1 多種注入方式
//注冊具體的類
containerBuilder.RegisterType<TestService>();
containerBuilder.RegisterType(typeof(TestService));
//注冊實例
var testService = new TestService();
containerBuilder.RegisterInstance(testService).As<ITestService>();
//注冊創建實例的表達式
containerBuilder.Register(c => new TestService("Parameters")).As<ITestService>();
//注冊公開接口
containerBuilder.RegisterType<TestService>().As<ITestService>();
//屬性注入
containerBuilder.RegisterType<TestService>().As<ITestService>().PropertiesAutowired();
//方法注入
containerBuilder.RegisterType<TestService>().OnActivated(e => e.Instance.SetService(e.Context.Resolve<ITestChildService>())).As<ITestService>();
5.2 將所有注冊的服務都暴漏
//使用 AsSelf();
containerBuilder.RegisterType<TestService>().AsSelf().As<ITestService>();
//這樣下面兩句都可以運行
container.Resolve<TestService>();
container.Resolve<ITestService>();
5.3 多例注入
獲取指定實例、或獲取所有實例
//Program.cs 注入
containerBuilder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(t => t.IsAssignableTo<ITestService>()));
//構造 TestService
container.Resolve<TestService>();
//構造函數時獲取所有注入實例 IEnumerable<ITestService>
public TestController(IEnumerable<ITestService> testServices){}
指定標識注入
//Program.cs
containerBuilder.RegisterType<TestService>().Named<ITestService>("TestService");
//獲取實例
ITestService testService = container.ResolveNamed<ITestService>("TestService");
//通過 IComponentContext 構建
//private readonly IComponentContext _componentContext;
ITestService testService = _componentContext.ResolveNamed<ITestService>("TestService");
5.4 程序集批量注入
Assembly assembly = Assembly.Load("AssemblyName");
//Assembly assembly = Assembly.GetExecutingAssembly();
containerBuilder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces().InstancePerDependency();
5.5 MVC控制器支持注入(屬性等注入)
控制器的實例是 IConrtollerActivator 來創建的,與一般的類不同,需要特殊處理。
6 生命周期
6.1 生命周期范圍
using(var scope = container.BeginLifetimeScope()){}
using(var scope = container.BeginLifetimeScope("ScopeName")){}
6.2 多種生命周期
//瞬態,對應 DI 容器的 Transient
InstancePerDependency();
//單例,對應 DI 容器的 Singleton
SingleInstance();
//每個生命周期范圍一個實例
InstancePerLifetimeScope();
//每個匹配生命周期范圍一個實例
InstancePerMatchingLifetimeScope("ScopeName");
//Web請求范圍一個實例
InstancePerRequest();
//
InstancePerOwned<MessageHandler>();
8 建議
具體請參考微軟官方文檔關於依賴關系注入的建議
-
避免使用服務定位器模式。例如,可以使用 DI 代替時,不要調用 GetService 來獲取服務實例。
-
要避免的另一個服務定位器變體是注入需在運行時解析依賴項的工廠。 這兩種做法混合了控制反轉策略。
-
避免靜態訪問 HttpContext。DI 是靜態/全局對象訪問模式的替代方法。
9 其他
9.1 Autofac 支持 AOP
9.1.1 接口方式
1)引入程序集
Castle.Core(獨立在另外一個工程)
Autofac.Extras.DynamicProxy
2)切面類實現
實現 IInterceptor 接口
public class AutofacAOP : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("執行前");
invocation.Proceed();
Console.WriteLine("執行后");
}
}
3)注入
containerBuilder.RegisterType<AutofacAOP>();
containerBuilder.RegisterType<Test>().As<ITest>().EnableInterfaceInterceptors();
4)標記接口
[Intercept(typeof(AutofacAOP))]
public interface ITest {}
9.1.2 類方式
1)引入程序集
2)切面類實現
3)注入
EnableClassInterceptors();
4)標記接口,且要實現 AOP 的方法標記為虛方法
[Intercept(typeof(AutofacAOP))]
public class Test : ITest
{
public virtual void Show()
{
Console.WriteLine("執行中");
}
}
參考來源
部分內容來自於朝夕教育的視頻
Autofac 官網:https://autofac.org
Autofac 官方示例代碼:https://github.com/autofac/Examples
微軟官方文檔-依賴關系注入(服務):https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-6.0