.NET?Core使用Autofac容器的DI依賴注入,IOC控制反轉(zhuǎn)及AOP切面編程
Autofac 容器
Autofac 是一款.NET IoC 容器 . 它管理類之間的依賴關(guān)系, 從而使 應(yīng)用在規(guī)模及復(fù)雜性增長的情況下依然可以輕易地修改 . 它的實現(xiàn)方式是將常規(guī)的.net類當做組件
處理.
- 安裝 NuGet 程序包:
Autofac 6.0.0
- 創(chuàng)建一個 ContainerBuiler
- 注冊接口和實現(xiàn)關(guān)系
- 通過 ContainerBuiler 的 Build 方法,得到 IContainer 容器
- 通過 IContainer 容器獲取實例
- 使用服務(wù)
ITestServiceA
和TestServiceA
public interface ITestServiceA { void Show(); } public class TestServiceA : ITestServiceA { public TestServiceA() { Console.WriteLine($"{this.GetType().Name} 被構(gòu)造了..."); } public void Show() { Console.WriteLine($"This is a {this.GetType().Name} Instance..."); } }
- Program 中的
Main
方法
var builder = new ContainerBuilder(); builder.RegisterType<TestServiceA>().As<ITestServiceA>(); var container = builder.Build(); // 獲取服務(wù)實例 var testService = container.Resolve<ITestServiceA>(); testService.Show();
Autofac 多種注入方式
ITestServiceB
和TestServiceB
public interface ITestServiceB { void Show(); } public class TestServiceB : ITestServiceB { private ITestServiceA _testServiceA; public void SetService(ITestServiceA testServiceA) { _testServiceA = testServiceA; } public TestServiceB() { Console.WriteLine($"{this.GetType().Name} 被構(gòu)造了..."); } public void Show() { // _testServiceA.Show(); Console.WriteLine($"This is a {this.GetType().Name} Instance..."); } }
ITestServiceC
和TestServiceC
public interface ITestServiceC { void Show(); } public class TestServiceC : ITestServiceC { public TestServiceC() { Console.WriteLine($"{this.GetType().Name} 被構(gòu)造了..."); } public void Show() { Console.WriteLine($"This is a {this.GetType().Name} Instance..."); } }
ITestServiceD
和TestServiceD
public interface ITestServiceD { void Show(); } public class TestServiceD : ITestServiceD { public ITestServiceA TestServiceA { get; set; } public ITestServiceB TestServiceB { get; set; } public ITestServiceC TestServiceC { get; set; } public TestServiceD() { Console.WriteLine($"{this.GetType().Name} 被構(gòu)造了..."); } public void Show() { // TestServiceA.Show(); // TestServiceB.Show(); // TestServiceC.Show(); Console.WriteLine($"This is a {this.GetType().Name} Instance..."); } }
- 構(gòu)造函數(shù)注入
var builder = new ContainerBuilder(); builder.RegisterType<TestServiceA>().As<ITestServiceA>(); builder.RegisterType<TestServiceB>().As<ITestServiceB>(); builder.RegisterType<TestServiceC>().As<ITestServiceC>(); builder.RegisterType<TestServiceD>().As<ITestServiceD>(); var container = builder.Build(); // 獲取服務(wù)實例 var testService = container.Resolve<ITestServiceA>(); testService.Show();
- 屬性注入
var builder = new ContainerBuilder(); builder.RegisterType<TestServiceA>().As<ITestServiceA>(); builder.RegisterType<TestServiceB>().As<ITestServiceB>(); builder.RegisterType<TestServiceC>().As<ITestServiceC>(); builder.RegisterType<TestServiceD>().As<ITestServiceD>().PropertiesAutowired(); var container = builder.Build(); // 獲取服務(wù)實例 var testService = container.Resolve<ITestServiceD>(); testService.Show();
- 方法注入
var builder = new ContainerBuilder(); builder.RegisterType<TestServiceA>().As<ITestServiceA>(); builder.RegisterType<TestServiceB>().OnActivated(e => e.Instance.SetService(e.Context.Resolve<ITestServiceA>()) ).As<ITestServiceB>(); builder.RegisterType<TestServiceC>().As<ITestServiceC>(); builder.RegisterType<TestServiceD>().As<ITestServiceD>(); var container = builder.Build(); // 獲取服務(wù)實例 var testService = container.Resolve<ITestServiceB>(); testService.Show();
Autofac 生命周期
- InstancePerDependency :默認模式,每次調(diào)用,都會重新實例化對象;每次請求都創(chuàng)建一個新的對象;
var builder = new ContainerBuilder(); builder.RegisterType<TestServiceA>().As<ITestServiceA>().InstancePerDependency(); var container = builder.Build(); var testServiceA = container.Resolve<ITestServiceA>(); var testServiceA1 = container.Resolve<ITestServiceA>(); Console.WriteLine(object.ReferenceEquals(testServiceA,testServiceA1));
- SingleInstance :單例模式,每次調(diào)用,都會使用同一個實例化的對象;每次都用同一個對象;
var builder = new ContainerBuilder(); builder.RegisterType<TestServiceA>().As<ITestServiceA>().SingleInstance(); var container = builder.Build(); var testServiceA = container.Resolve<ITestServiceA>(); var testServiceA1 = container.Resolve<ITestServiceA>(); Console.WriteLine(object.ReferenceEquals(testServiceA,testServiceA1));
- InstancePerLifetimeScope : 同一個生命周期域中,每次調(diào)用,都會使用同一個實例化的對象;每次都用同一個對象;且每個不同的生命周期域中的實例是唯一的,不共享的。
var builder = new ContainerBuilder(); builder.RegisterType<TestServiceA>().As<ITestServiceA>().InstancePerLifetimeScope(); var container = builder.Build(); ITestServiceA testServiceA15; ITestServiceA testServiceA16; using (var scope1 = container.BeginLifetimeScope()) { var testServiceA11 = scope1.Resolve<ITestServiceA>(); var testServiceA12 = scope1.Resolve<ITestServiceA>(); Console.WriteLine(object.ReferenceEquals(testServiceA11,testServiceA12)); testServiceA15 = testServiceA12; } using (var scope1 = container.BeginLifetimeScope()) { var testServiceA13 = scope1.Resolve<ITestServiceA>(); var testServiceA14 = scope1.Resolve<ITestServiceA>(); Console.WriteLine(object.ReferenceEquals(testServiceA13,testServiceA14)); testServiceA16 = testServiceA14; } Console.WriteLine(object.ReferenceEquals(testServiceA15,testServiceA16));
- InstancePerMatchingLifetimeScope : 同一個匹配的生命周期域中,每次調(diào)用,都會使用同一個實例化的對象;每次都用同一個對象;且每個不匹配的生命周期域中的實例是唯一的,不共享的。
var builder = new ContainerBuilder(); builder.RegisterType<TestServiceA>().As<ITestServiceA>() .InstancePerMatchingLifetimeScope("Run2948"); var container = builder.Build(); ITestServiceA testServiceA15; ITestServiceA testServiceA16; using (var scope1 = container.BeginLifetimeScope("Run2948")) { var testServiceA11 = scope1.Resolve<ITestServiceA>(); using (var scope2 = container.BeginLifetimeScope()) { var testServiceA12 = scope2.Resolve<ITestServiceA>(); Console.WriteLine(object.ReferenceEquals(testServiceA11,testServiceA12)); } testServiceA15 = testServiceA11; } using (var scope1 = container.BeginLifetimeScope("Run2948")) { var testServiceA13 = scope1.Resolve<ITestServiceA>(); using (var scope2 = container.BeginLifetimeScope()) { var testServiceA14 = scope2.Resolve<ITestServiceA>(); Console.WriteLine(object.ReferenceEquals(testServiceA13,testServiceA14)); } testServiceA16 = testServiceA13; } Console.WriteLine(object.ReferenceEquals(testServiceA15,testServiceA16));
InstancePerOwned : 在一個所擁有的實例創(chuàng)建的生命周期中,每次調(diào)用,都會使用同一個實例化的對象;每次都用同一個對象;(較少使用)
InstancePerHttpRequest : 同一次Http請求上下文中,每次調(diào)用,都會使用同一個實例化的對象;每次都用同一個對象;僅適用于 ASP.NET (CORE) MVC 或 WebForm 應(yīng)用程序
Autofac 支持配置文件
- 安裝 NuGet 程序包:
Autofac.Extensions.DependencyInjection 7.1.0
、Autofac.Configuration 6.0.0
- 新建配置文件(指定接口和實現(xiàn)的對應(yīng)關(guān)系)
autofac.json
:
{ "components":[ { "type: "One.Services.TestServiceA,One", "services": [ { "type": "One.Services.ITestServiceA,One" } ], "instanceScope": "single-instance", "injectProperties": true }, { "type: "One.Services.TestServiceB,One", "services": [ { "type": "One.Services.ITestServiceB,One" } ], "instanceScope": "single-instance", "injectProperties": true }, { "type: "One.Services.TestServiceC,One", "services": [ { "type": "One.Services.ITestServiceC,One" } ], "instanceScope": "single-instance", "injectProperties": true }, { "type: "One.Services.TestServiceD,One", "services": [ { "type": "One.Services.ITestServiceD,One" } ], "instanceScope": "single-instance", "injectProperties": true } ] }
- 讀取配置文件,完成服務(wù)對應(yīng)關(guān)系的注冊
var builder = new ContainerBuilder(); var config = new ConfigurationBuilder(); var configSource = new JsonConfigurationSource() { Path = "Config/autofac.json", Optional = false, ReloadOnChange = true }; config.Add(configSource); var configModule = new ConfigurationModule(config.Build()); builder.RegisterModule(configModule); var container = builder.Build(); // 獲取服務(wù)實例 var testServiceA = container.Resolve<ITestServiceA>(); var testServiceD = container.Resolve<ITestServiceD>(); testServiceD.Show();
- 新建 ITestServiceA 的新版實現(xiàn)類
TestServiceUpdate
public class TestServiceUpdate : ITestServiceA { public TestServiceUpdate() { Console.WriteLine($"{this.GetType().Name} 被構(gòu)造了..."); } public void Show() { Console.WriteLine($"This is a {this.GetType().Name} Instance..."); } }
- 通過修改配置文件
autofac.json
來實現(xiàn)快速實現(xiàn) ITestServiceA 的實現(xiàn)的重新定義:
{ "components":[ { "type: "One.Services.TestServiceUpdate,One", "services": [ { "type": "One.Services.ITestServiceA,One" } ], "instanceScope": "single-instance", "injectProperties": true }, // ...
Autofac 整合 .NET 5 MVC
安裝 NuGet 程序包:
Autofac.Extensions.DependencyInjection 7.1.0
Program文件中指定 Autofac 工廠替換默認工廠:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); }).UseServiceProviderFactory(new AutofacServiceProviderFactory());
- 在 Startup 類中增加 ConfigureContainer 方法:
public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterType<TestServiceA>().As<ITestServiceA>(); }
- 通過控制器構(gòu)造函數(shù)注入,獲取實例
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { private readonly ITestServiceA _serviceA; public ValuesController(ITestServiceA serviceA { _serviceA = serviceA; } [HttpGet] public IActionResult Get() { _serviceA.Show(); return Ok(); } }
- 使用 IServiceCollection 注冊的服務(wù),將來也會交給 Autofac 管理
public void ConfigureServices(IServiceCollection services) { #region IServiceCollection 注冊的服務(wù),將來也會交給 Autofac 處理 services.AddTransient<ITestServiceA, TestServiceA>(); services.AddTransient<ITestServiceB, TestServiceB>(); services.AddTransient<ITestServiceC, TestServiceC>(); #endregion } public void ConfigureContainer(ContainerBuilder builder) { // builder.RegisterType<TestServiceA>().As<ITestServiceA>(); // builder.RegisterType<TestServiceB>().As<ITestServiceB>(); // builder.RegisterType<TestServiceC>().As<ITestServiceC>(); builder.RegisterType<TestServiceD>().As<ITestServiceD>(); }
Autofac 支持控制器屬性注入
控制器本身是一個類,它的實例其實是有 IControllerActivator 來創(chuàng)建的。
- 指定控制器的實例由容器來創(chuàng)建
public void ConfigureServices(IServiceCollection services) { // ... #region 指定控制器的實例由容器來創(chuàng)建 services.Replace(ServiceDescriptor.Transient<IControllerActivator, ServiceBasedControllerActivator>()); #endregion }
- 注冊控制器的抽象和具體的關(guān)系
public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterType<TestServiceA>().As<ITestServiceA>().PropertiesAutowired(); builder.RegisterType<TestServiceB>().As<ITestServiceB>(); #region 注冊所有控制器的關(guān)系及控制器實例化所需要的組件 var controllersTypesInAssembly = typeof(Startup).Assembly.GetExportedTypes() .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray(); builder.RegisterTypes(controllersTypesInAssembly) .PropertiesAutowired(); #endregion }
- 在控制器內(nèi)定義屬性
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { public ITestServiceA TestServiceA { get; set; } public ITestServiceB TestServiceB { get; set; } [HttpGet] public IActionResult Get() { TestServiceA.Show(); TestServiceB.Show(); return Ok(); } }
- 擴展:自己控制哪些屬性需要做依賴注入(默認是讓控制器中的屬性都依賴注入)
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public class AutowaredAttribute : Attribute { } public class PropertySelector : IPropertySelector { public bool InjectProperty(PropertyInfo propertyInfo, object instance) { return propertyInfo.CustomAttributes.Any(ca => ca.AttributeType == typeof(AutowaredAttribute)); } }
public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterType<TestServiceA>().As<ITestServiceA>(); builder.RegisterType<TestServiceB>().As<ITestServiceB>(); #region 注冊所有控制器的關(guān)系及控制器實例化所需要的組件 var controllersTypesInAssembly = typeof(Startup).Assembly.GetExportedTypes() .Where(type => typeof(ControllerBase).IsAssignableFrom(type)).ToArray(); builder.RegisterTypes(controllersTypesInAssembly) .PropertiesAutowired(new PropertySelector()); #endregion }
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { [Autowared] public ITestServiceA TestServiceA { get; set; } public ITestServiceB TestServiceB { get; set; } [HttpGet] public IActionResult Get() { TestServiceA.Show(); TestServiceB.Show(); return Ok(); } }
Autofac 單實例多實現(xiàn)
public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterType<TestServiceA>().As<ITestServiceA>(); builder.RegisterType<TestServiceUpdate>().As<ITestServiceA>(); }
- 如果多個實現(xiàn)同時注冊,則后注冊的實現(xiàn)就會覆蓋先注冊的實現(xiàn),最后將返回最后一個注冊的實現(xiàn)。
- 如果多個實現(xiàn)同時注冊,可以通過一個 IEnumerable<實例> 來獲取到所有的實現(xiàn)。
private readonly IEnumerable<ITestServiceA> _testServiceAs; public ValuesController(IEnumerable<ITestServiceA> testServiceAs) { _testServiceAs = testServiceAs; }
- 當多個實現(xiàn)同時注冊后,可以通過以下方式繼續(xù)注冊 實例 的所有實現(xiàn)。從而可以在控制器中直接使用具體實現(xiàn)類作為實現(xiàn)。
public void ConfigureContainer(ContainerBuilder builder) { builder.RegisterType<TestServiceA>().As<ITestServiceA>(); builder.RegisterType<TestServiceUpdate>().As<ITestServiceA>(); builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(type => type.IsAssignableTo<ITestServiceA>())); }
private readonly TestServiceA _testServiceA; private readonly TestServiceUpdate _testServiceUpdate; public ValuesController(TestServiceA testServiceA,TestServiceUpdate testServiceUpdate) { _testServiceA = testServiceA; _testServiceUpdate = testServiceUpdate; }
- 擴展:Autofac 的注冊邏輯可以通過 Module 來拆分管理。
public class AutofacModule : Autofac.Module { protected override void Load(ContainerBuilder builder) { // base.Load(builder); builder.RegisterType<TestServiceA>().As<ITestServiceA>(); builder.RegisterType<TestServiceUpdate>().As<ITestServiceA>(); builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource(type => type.IsAssignableTo<ITestServiceA>())); } }
public void ConfigureContainer(ContainerBuilder builder) { // builder.RegisterModule(new AutofacModule()); builder.RegisterModule<AutofacModule>(); }
Autofac 支持 AOP
AOP 面向切面編程,通過預(yù)編譯方式和運行期動態(tài)代理實現(xiàn)程序功能的統(tǒng)一維護的一種技術(shù)。Autofac 的AOP是通過 Castle(也是一個容器)項目的名為 Autofac.Extras.DynamicProxy 核心部分實現(xiàn)的,顧名思義其實現(xiàn)方式為動態(tài)代理。
安裝 NuGet 程序包:
Castle.Core 4.4.1
、Autofac.Extras.DynamicProxy 6.0.0
新建自定義 AOP 攔截器
public class CustomAutofacAop : IInterceptor { public void Intercept(IInvocation invocation) { { Console.WriteLine("方法執(zhí)行前..."); } invocation.Proceed(); { Console.WriteLine("方法執(zhí)行后..."); } } }
- 在接口上標記需要使用的攔截器
[Intercept(typeof(CustomAutofacAop))] public interface ITestServiceA { void Show(); }
- 注冊自定義攔截器,并允許實例接口使用攔截器
public void ConfigureContainer(ContainerBuilder builder) { //builder.RegisterType<CustomAutofacAop>(); builder.RegisterType(typeof(CustomAutofacAop)); builder.RegisterType<TestServiceA>().As<ITestServiceA>(); builder.RegisterType<TestServiceUpdate>().As<ITestServiceA>().EnableInterfaceInterceptors(); }
- 在控制器中調(diào)用實例,即可成功執(zhí)行 AOP 攔截器
[Route("api/[controller]")] [ApiController] public class ValuesController : ControllerBase { private readonly TestServiceA _testServiceA; private readonly TestServiceUpdate _testServiceUpdate; public ValuesController(TestServiceA testServiceA,TestServiceUpdate testServiceUpdate) { _testServiceA = testServiceA; _testServiceUpdate = testServiceUpdate; } public IActionResult Get() { _testServiceA.Show(); _testServiceUpdate.Show(); return Ok(); } }
到此這篇關(guān)于.NET Core使用Autofac容器的DI依賴注入,IOC控制反轉(zhuǎn)及AOP切面編程的文章就介紹到這了。希望對大家的學(xué)習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
asp.net AutoCompleteExtender的一個簡單例子代碼
asp.net AutoCompleteExtender的一個簡單例子代碼2009-12-12asp.net下用js實現(xiàn)鼠標移至小圖,自動顯示相應(yīng)大圖
asp.net下用js實現(xiàn)鼠標移至小圖,自動顯示相應(yīng)大圖...2007-03-03如何利用HttpClientFactory實現(xiàn)簡單的熔斷降級
這篇文章主要給大家介紹了關(guān)于如何利用HttpClientFactory實現(xiàn)簡單的熔斷降級的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2018-07-07關(guān)于dotnet?替換?ASP.NET?Core?的底層通訊為命名管道的?IPC?庫的問題
這篇文章主要介紹了dotnet?替換?ASP.NET?Core?的底層通訊為命名管道的?IPC?庫,本文給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-02-02ASP.NET GridView中加入RadioButton不能單選的解決方案
這篇文章主要介紹了ASP.NET GridView中加入RadioButton不能單選的解決方案,希望大家閱讀完本文有所收獲。2015-09-09