.Net Core 之AutoFac的使用
本文不介紹IoC和DI的概念,如果你對(duì)Ioc之前沒有了解的話,建議先去搜索一下相關(guān)的資料
這篇文章將簡(jiǎn)單介紹一下AutoFac的基本使用以及在asp .net core中的應(yīng)用
Autofac介紹
組件的三種注冊(cè)方式
1.反射
2.現(xiàn)成的實(shí)例(new)
3.lambda表達(dá)式 (一個(gè)執(zhí)行實(shí)例化對(duì)象的匿名方法)
下面是一些簡(jiǎn)短的示例,我盡可能多的列出來一些常用的注冊(cè)方式,同時(shí)在注釋中解釋下“組件”、“服務(wù)”等一些名詞的含義
// 創(chuàng)建注冊(cè)組件的builder var builder = new ContainerBuilder(); //根據(jù)類型注冊(cè)組件 ConsoleLogger 暴漏服務(wù):ILogger builder.RegisterType<ConsoleLogger>().As<ILogger>(); //根據(jù)類型注冊(cè)組件 ConsoleLogger,暴漏其實(shí)現(xiàn)的所有服務(wù)(接口) builder.RegisterType<ConsoleLogger>().AsImplementedInterfaces(); // 根據(jù)實(shí)例注冊(cè)組件 output 暴漏服務(wù):TextWriter var output = new StringWriter(); builder.RegisterInstance(output).As<TextWriter>(); //表達(dá)式注冊(cè)組件,這里我們是在構(gòu)造函數(shù)時(shí)傳參->"musection" 暴漏服務(wù):IConfigReader builder.Register(c =new ConfigReader("mysection")).As<IConfigReader>(); //表達(dá)式注冊(cè)組件,解析時(shí)傳參 var service = scope.Resolve<IConfigReader>( new NamedParameter("section", "mysection")); //反射注冊(cè)組件,直接注冊(cè)了ConsoleLogger類(必須是具體的類),如果ConsoleLogger有多個(gè)構(gòu)造函數(shù),將會(huì)取參數(shù)最多的那個(gè)構(gòu)造函數(shù)進(jìn)行實(shí)例化 builder.RegisterType<ConsoleLogger>(); //反射注冊(cè)組件,手動(dòng)指定構(gòu)造函數(shù),這里指定了調(diào)用 MyComponent(ILogger log,IConfigReader config)的構(gòu)造函數(shù)進(jìn)行注冊(cè) builder.RegisterType<MyComponent>() .UsingConstructor(typeof(ILogger), typeof(IConfigReader)); //注冊(cè)MySingleton類中的靜態(tài)變量"Instance",ExternallyOwned()函數(shù)指定自己控制實(shí)例的生命周期,而不是由autofac自動(dòng)釋放 builder.RegisterInstance(MySingleton.Instance).ExternallyOwned(); //一個(gè)組件暴漏兩個(gè)服務(wù) builder.RegisterType<CallLogger>().As<ILogger>().As<ICallInterceptor>(); //注冊(cè)當(dāng)前程序集中以“Service”結(jié)尾的類 builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces(); //注冊(cè)"MyApp.Repository"程序集中所有的類 builder.RegisterAssemblyTypes(GetAssembly("MyApp.Repository")).AsImplementedInterfaces(); //構(gòu)建一個(gè)容器完成注冊(cè) var rootcontainer = builder.Build(); //可以通過下面這種方式手動(dòng)獲取IConfigReader 的實(shí)現(xiàn)類 //這種手動(dòng)解析的方式需要 從生命周期作用域內(nèi)獲取組件,以保證組件最終被釋放 //不要直接從根容器rootcontainer中解析組件,很有可能會(huì)導(dǎo)致內(nèi)存泄漏 using(var scope = rootcontainer.BeginLifetimeScope()) { var reader = scope.Resolve<IConfigReader>(); }
如果不止一個(gè)組件暴露了相同的服務(wù), Autofac將使用最后注冊(cè)的組件作為服務(wù)的提供方。 想要覆蓋這種行為, 在注冊(cè)代碼后使用 PreserveExistingDefaults()
方法修改
生命周期
using(var scope = rootcontainer.BeginLifetimeScope())
上面的這段代碼創(chuàng)建了一個(gè)生命周期作用域
生命周期作用域是可釋放的,在作用域內(nèi)解析的組件一定要保證在using之內(nèi)使用或者最后手動(dòng)調(diào)用組件的Dispose()函數(shù)
避免引用類的生命周期大于被引用類的生命周期 :如service 引用 repository 如果service的生命周期為單例,repository的生命周期為perrequest。service不會(huì)釋放,所以最終會(huì)造成相關(guān)的repository始終無法釋放的情況(Captive Dependencies)
雖然我們需要盡可能的避免直接從根容器解析組件,但總有例外的情況,對(duì)于非單例的組件,一定不要忘記調(diào)用組件的Dispose函數(shù),實(shí)際上對(duì)于非單例的組件,從項(xiàng)目架構(gòu)上來說,理論上應(yīng)該是從構(gòu)造函數(shù)注入進(jìn)去的而不是手動(dòng)解析。 需要手動(dòng)解析的應(yīng)該為一些配置幫助類等
對(duì)于一個(gè)具體組件(類)的生命周期分為以下幾種(后面的函數(shù)是autofac對(duì)應(yīng)的函數(shù)):
- 每個(gè)依賴一個(gè)實(shí)例(Instance Per Dependency) (默認(rèn)) ----InstancePerDependency()
- 單一實(shí)例(Single Instance) 單例 ----SingleInstance()
- 每個(gè)生命周期作用域一個(gè)實(shí)例(Instance Per Lifetime Scope)----InstancePerLifetimeScope()
- 每個(gè)匹配的生命周期作用域一個(gè)實(shí)例(Instance Per Matching Lifetime Scope)----InstancePerMatchingLifetimeScope()
- 每個(gè)請(qǐng)求一個(gè)實(shí)例(Instance Per Request) asp.net web請(qǐng)求----InstancePerRequest()
- 每次被擁有一個(gè)實(shí)例(Instance Per Owned) ----InstancePerOwned()
如果你以前在傳統(tǒng)的ASP.NET MVC項(xiàng)目中用過autofac,需要注意一些區(qū)別:
- .net Core中需要使用
InstancePerLifetimeScope
替代之前(傳統(tǒng)asp.net)的InstancePerRequest
,保證每次HTTP請(qǐng)求只有唯一的依賴實(shí)例被創(chuàng)建。InstancePerRequest
請(qǐng)求級(jí)別已經(jīng)不存在了- .net Core中Web Api與Mvc的注冊(cè)方式一樣
- .net Core中不再需要注冊(cè)控制器,控制器由.net core創(chuàng)建,不歸autofac管理(除了控制器的構(gòu)造函數(shù)),這也解釋了為什么不再使用
InstancePerRequest
生命周期,但是可以通過AddControllersAsServices()
函數(shù)改變,想要深入了解的可以查看:https://www.strathweb.com/2016/03/the-subtle-perils-of-controller-dependency-injection-in-asp-net-core-mvc/
AutoFac 在asp .net core中的使用
在.net core 中使用autofac還是比較簡(jiǎn)單的,相比于傳統(tǒng)的asp.net web 項(xiàng)目,省去了很多步驟
引入nuget程序包:
- Autofac
- Autofac.Extensions.DependencyInjection
startup 中代碼:
public static IContainer AutofacContainer; // This method gets called by the runtime. Use this method to add services to the container. public IServiceProvider ConfigureServices(IServiceCollection services) { //注冊(cè)服務(wù)進(jìn) IServiceCollection services.AddMvc(); ContainerBuilder builder = new ContainerBuilder(); //將services中的服務(wù)填充到Autofac中. builder.Populate(services); //新模塊組件注冊(cè) builder.RegisterModule<DefaultModuleRegister>(); //創(chuàng)建容器. AutofacContainer = builder.Build(); //使用容器創(chuàng)建 AutofacServiceProvider return new AutofacServiceProvider(AutofacContainer); }
上面代碼調(diào)用了builder的
RegisterModule
函數(shù),這個(gè)函數(shù)需要傳入一個(gè)TModule
的泛型,稱之為autofac的模塊模塊的功能就是把所有相關(guān)的注冊(cè)配置都放在一個(gè)類中,使代碼更易于維護(hù)和配置,下面展示了
DefaultModuleRegister
中的代碼
DefaultModuleRegister:
public class DefaultModuleRegister : Module { protected override void Load(ContainerBuilder builder) { //注冊(cè)當(dāng)前程序集中以“Ser”結(jié)尾的類,暴漏類實(shí)現(xiàn)的所有接口,生命周期為PerLifetimeScope builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Ser")).AsImplementedInterfaces().InstancePerLifetimeScope(); builder.RegisterAssemblyTypes(System.Reflection.Assembly.GetExecutingAssembly()).Where(t => t.Name.EndsWith("Repository")).AsImplementedInterfaces().InstancePerLifetimeScope(); //注冊(cè)所有"MyApp.Repository"程序集中的類 //builder.RegisterAssemblyTypes(GetAssembly("MyApp.Repository")).AsImplementedInterfaces(); } public static Assembly GetAssembly(string assemblyName) { var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(AppContext.BaseDirectory + $"{assemblyName}.dll"); return assembly; } }
Configure函數(shù)中可以選擇性的加上程序停止時(shí)Autofac的釋放函數(shù):
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifetime) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseBrowserLink(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseStaticFiles(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); //程序停止調(diào)用函數(shù) appLifetime.ApplicationStopped.Register(() => { AutofacContainer.Dispose(); }); }
Controller中代碼:
private IUserSer _user; private IUserSer _user2; public HomeController(IUserSer user, IUserSer user2) { _user = user; _user2 = user2; } public IActionResult Index() { using (var scope = Startup.AutofacContainer.BeginLifetimeScope()) { IConfiguration config = scope.Resolve<IConfiguration>(); IHostingEnvironment env = scope.Resolve<IHostingEnvironment>(); } string name = _user.GetName(); string name2 = _user2.GetName(); return View(); }
可以看到,因?yàn)槲覀儗ServiceCollection中的服務(wù)填充到了autofac中了,所以現(xiàn)在可以在任何位置通過AutoFac解析出來.net core默認(rèn)注入的服務(wù)(IConfiguration,IHostingEnvironment等)了
正常項(xiàng)目使用中,我們應(yīng)該將
AutofacContainer
放在一個(gè)公共的類庫中以便各個(gè)工程均可調(diào)用
到此這篇關(guān)于.Net Core 之AutoFac的使用的文章就介紹到這了,更多相關(guān).Net Core AutoFac內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
水晶易表調(diào)用C#的WebService,返回?cái)?shù)據(jù)集合的應(yīng)用分析
本篇文章介紹了,水晶易表調(diào)用C#的WebService,返回?cái)?shù)據(jù)集合的應(yīng)用分析。需要的朋友參考下2013-04-04.NET項(xiàng)目在k8s中運(yùn)行的Dapr持續(xù)集成流程
這篇文章主要介紹了.NET項(xiàng)目在k8s中運(yùn)行的Dapr持續(xù)集成流程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04簡(jiǎn)單實(shí)現(xiàn).NET?Hook與事件模擬實(shí)例
這篇文章主要為大家介紹了簡(jiǎn)單實(shí)現(xiàn).NET?Hook與事件模擬實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10.Net?Core?配置文件讀取IOptions,IOptionsMonitor,IOptionsSnapshot
這篇文章主要介紹了.Net?Core配置文件讀取IOptions,IOptionsMonitor,IOptionsSnapshot,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09