autofac 作用域_.Net Core3.1下使用Autofac实现依赖注入
前言
Autofac是.NET領(lǐng)域最為流行的IOC框架之一,傳說是速度最快的一個(gè)。它和C#語言的結(jié)合非常緊密,在使用過程中對(duì)你的應(yīng)用的侵入性幾乎為零,更容易與第三方的組件集成。主要優(yōu)點(diǎn)如下(此段描述為轉(zhuǎn)載):它是C#語言聯(lián)系很緊密,也就是說C#里的很多編程方式都可以為Autofac使用,例如可以用Lambda表達(dá)式注冊(cè)組件
較低的學(xué)習(xí)曲線,學(xué)習(xí)它非常的簡(jiǎn)單,只要你理解了IoC和DI的概念以及在何時(shí)需要使用它們
XML配置支持
自動(dòng)裝配
微軟的Orchad開源程序使用的就是Autofac,從該源碼可以看出它的方便和強(qiáng)大
準(zhǔn)備工作
本文演示的項(xiàng)目時(shí)基于.Net Core3.1的,同時(shí)需要通過nuget下載安裝以下幾個(gè)dll文件:
基本用法
在前面的《基于Dapper的擴(kuò)展方法來簡(jiǎn)單封裝WebApi接口》一文中介紹過在.net core2.1中使用Autofac的方式,在ASP.NET Core 1.1 - 2.2 中, 你可以調(diào)用 WebHostBuilder 的 services.AddAutofac().。但這不適用于ASP.NET Core 3+ 或 .NET Core 3+ ,在 ASP.NET Core 3+ 需要你直接指定一個(gè)service provider factory而不是把它加入進(jìn)service collection。基本用法的代碼如下:
首先修改Progam中的CreateHostBuilder方法,使用autofac的容器工廠替換系統(tǒng)默認(rèn)的容器:public?static?IHostBuilder?CreateHostBuilder(string[]?args)?=>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new?AutofacServiceProviderFactory())//使用autofac的容器工廠替換系統(tǒng)默認(rèn)的容器
.ConfigureWebHostDefaults(webBuilder?=>
{
webBuilder.UseStartup();
});
然后在Startup中增加一個(gè)方法ConfigureContainerpublic?void?ConfigureContainer(ContainerBuilder?containerBuilder)
{
//指定服務(wù)的注冊(cè)
containerBuilder.RegisterType().As().InstancePerLifetimeScope().AsImplementedInterfaces();
containerBuilder.RegisterType().As().InstancePerLifetimeScope().AsImplementedInterfaces();
var?container?=?containerBuilder.Build();
IUserService?userService?=?container.Resolve();
IProductService?productService?=?container.Resolve();
userService.Show();
productService.Show();
}
調(diào)試運(yùn)行,我們發(fā)現(xiàn)ConfigureContainer的方法并沒有被引用,但已經(jīng)可以進(jìn)到這個(gè)方法里并實(shí)現(xiàn)的服務(wù)的注冊(cè),這就是因?yàn)槲覀冎付薝seServiceProviderFactory:
Autofac生命周期
簡(jiǎn)單介紹,詳情請(qǐng)見參考資料://1、瞬時(shí)生命周期:注冊(cè)之后,每次獲取到的服務(wù)實(shí)例都不一樣(默認(rèn)的注冊(cè)方式)
containerBuilder.RegisterType().As().InstancePerDependency();
//2、單例生命周期:整個(gè)容器中獲取的服務(wù)實(shí)例都是同一個(gè)
containerBuilder.RegisterType().As().SingleInstance();
//3、作用域生命周期:在相同作用域下獲取到的服務(wù)實(shí)例是相同的
containerBuilder.RegisterType().As().InstancePerLifetimeScope();
//4、作用域生命周期:可以指定到某一個(gè)作用域,然后在相同作用域下共享服務(wù)實(shí)例
containerBuilder.RegisterType().As().InstancePerMatchingLifetimeScope("My");
//5、http請(qǐng)求上下文的生命周期:在一次Http請(qǐng)求上下文中,共享一個(gè)組件實(shí)例。僅適用于asp.net?mvc開發(fā)。
containerBuilder.RegisterType().As().InstancePerRequest();
//6、擁有隱式關(guān)系類型的創(chuàng)建新的嵌套生命周期的作用域,在一個(gè)生命周期域中所擁有的實(shí)例創(chuàng)建的生命周期中,
//??????每一個(gè)依賴組件或調(diào)用Resolve()方法創(chuàng)建一個(gè)單一的共享的實(shí)例,并且子生命周期域共享父生命周期域中的實(shí)例
containerBuilder.RegisterType().InstancePerOwned();
實(shí)際項(xiàng)目中用法
上面的代碼只是簡(jiǎn)單演示了下Autofac如何注冊(cè)服務(wù)實(shí)例的,在實(shí)際使用時(shí)我們不會(huì)這樣去寫代碼,每增加一個(gè)接口及其實(shí)現(xiàn),都需要手動(dòng)注冊(cè)一下,這樣的耦合度太高。因此我們需要進(jìn)行代碼優(yōu)化,下面將使用反射的方式來實(shí)現(xiàn)服務(wù)的注冊(cè),改造上面的代碼:public?void?ConfigureContainer(ContainerBuilder?containerBuilder)
{
Assembly?service?=?Assembly.Load("AspNetCore.Ioc.Service");
Assembly?iservice?=?Assembly.Load("AspNetCore.Ioc.Interface");
containerBuilder.RegisterAssemblyTypes(service,?iservice)
.Where(t?=>?t.FullName.EndsWith("Service")?&&?!t.IsAbstract)?//類名以service結(jié)尾,且類型不能是抽象的
.InstancePerLifetimeScope()?//生命周期,,
.AsImplementedInterfaces()
.PropertiesAutowired();?//屬性注入
}
運(yùn)行結(jié)果如下
一個(gè)接口多個(gè)實(shí)現(xiàn)的服務(wù)注冊(cè)
在實(shí)際應(yīng)用中有這樣一種場(chǎng)景,比如IUserService接口被多個(gè)類繼承并實(shí)現(xiàn),那么此時(shí)應(yīng)該如何注冊(cè)服務(wù)并實(shí)現(xiàn)調(diào)用呢?
其實(shí)上面Startup中的注冊(cè)方式就已經(jīng)滿足服務(wù)的注冊(cè),只是需要在相應(yīng)的Controller調(diào)用的地方修改即可,如:public?class?UserController?:?Controller
{
///?
///?IUserService服務(wù)實(shí)現(xiàn)的集合
///?
private?readonly?IEnumerable?_userServices?=?null;
public?UserController(IEnumerable?userServices)
{
_userServices?=?userServices;
}
public?IActionResult?Index()
{
foreach?(var?item?in?_userServices)
{
item.Show();
}
return?View();
}
}
調(diào)試運(yùn)行的結(jié)果如下
值得說明的是,一個(gè)接口有多個(gè)實(shí)現(xiàn)的情況,在注冊(cè)服務(wù)的時(shí)候,可以選擇一些策略來實(shí)現(xiàn)只注冊(cè)其中某幾個(gè)實(shí)例,示例代碼如下://一個(gè)接口有多個(gè)實(shí)現(xiàn):注冊(cè)所有實(shí)現(xiàn)的服務(wù)實(shí)例
builder.RegisterAssemblyTypes(Assembly.Load("AspNetCore.Ioc.Service")).As();
//一個(gè)接口有多個(gè)實(shí)現(xiàn):只注冊(cè)以A結(jié)尾的服務(wù)實(shí)例
builder.RegisterAssemblyTypes(Assembly.Load("AspNetCore.Ioc.Service")).Where(c=>c.Name.EndsWith("A")).As();
//一個(gè)接口有多個(gè)實(shí)現(xiàn):注冊(cè)所有實(shí)現(xiàn)的服務(wù)實(shí)例,并排除UserServiceA服務(wù)實(shí)例
builder.RegisterAssemblyTypes(Assembly.Load("AspNetCore.Ioc.Service")).Except().As();
隔離服務(wù)注冊(cè)的邏輯代碼
為了簡(jiǎn)化Startup中的代碼,還可以自定義一個(gè)MyAutofacModule的方式,將服務(wù)注冊(cè)的代碼抽離出來,放到單獨(dú)的文件中。這時(shí)我們就需要新建一個(gè)MyAutofacModule類,并繼承Autofac.Module,同時(shí)重寫其中的Load方法,具體代碼如下:using?System.Linq;
using?System.Reflection;
using?Autofac;
using?Autofac.Configuration;
using?Microsoft.Extensions.Configuration;
namespace?AspNetCore.Ioc.Web.Utility
{
public?class?MyAutofacModule?:?Autofac.Module
{
protected?override?void?Load(ContainerBuilder?builder)
{
//反射程序集方式服務(wù)注冊(cè)
Assembly?service?=?Assembly.Load("AspNetCore.Ioc.Service");
Assembly?iservice?=?Assembly.Load("AspNetCore.Ioc.Interface");
builder.RegisterAssemblyTypes(service,?iservice)
.Where(t?=>?t.FullName.EndsWith("Service")?&&?!t.IsAbstract)?//類名以service結(jié)尾,且類型不能是抽象的
.InstancePerLifetimeScope()?//作用域生命周期
.AsImplementedInterfaces()
.PropertiesAutowired();?//屬性注入
}
}
}
重寫Load方法中的邏輯其實(shí)就是將原本 寫在Startup中的注冊(cè)代碼遷移到MyAutofacModule中,然后將Startup中的ConfigureContainer方法修改成如下:public?void?ConfigureContainer(ContainerBuilder?containerBuilder)
{
containerBuilder.RegisterModule();
}
具體運(yùn)行結(jié)果這里就不展示,和前面的一樣。
配置文件的方式服務(wù)注冊(cè)
為了讓注冊(cè)服務(wù)的方式更靈活,我們還可以通過配置文件的方式來實(shí)現(xiàn),將所有的程序集信息放到配置文件中,這樣便于后期的程序擴(kuò)展。那么首先來看下配置文件應(yīng)該如何寫:
需要注意的是要將autofac.json文件的屬性改成始終復(fù)制
autofac.json文件:{
"defaultAssembly":?"AspNetCore.Ioc.Interface",?//接口所在的程序集名稱
"components":?[
{
"type":?"AspNetCore.Ioc.Service.UserService,AspNetCore.Ioc.Service",?//接口的實(shí)現(xiàn)?全名稱
"services":?[
{
"type":?"AspNetCore.Ioc.Interface.IUserService"?//?接口的全名稱
}
],
"instanceScope":?"single-instance",?//單例生命周期
"injectProperties":?true?//是否支持屬性注入
},
{
"type":?"AspNetCore.Ioc.Service.ProductService,AspNetCore.Ioc.Service",?//接口的實(shí)現(xiàn)?全名稱
"services":?[
{
"type":?"AspNetCore.Ioc.Interface.IProductService"?//?接口的全名稱
}
],
"instanceScope":?"single-instance",?//單例生命周期
"injectProperties":?true?//是否支持屬性注入
}
]
}
修改MyAutofacModule中的調(diào)用方法:protected?override?void?Load(ContainerBuilder?builder)
{
//Autofac?基于配置文件的服務(wù)注冊(cè)
IConfigurationBuilder?configurationBuilder?=?new?ConfigurationBuilder();
configurationBuilder.AddJsonFile("Config/autofac.json");
IConfigurationRoot?root?=?configurationBuilder.Build();
//開始讀取配置文件中的內(nèi)容
ConfigurationModule?module?=?new?ConfigurationModule(root);
//根據(jù)配置文件的內(nèi)容注冊(cè)服務(wù)
builder.RegisterModule(module);
}
運(yùn)行結(jié)果如下
總結(jié)
到這里基本就完成了.net core3.1下使用Autofac的基本用法,當(dāng)然還有其他的一些用法,比如Autofac中實(shí)現(xiàn)AOP等,本文暫時(shí)就到這里了。參考資料:
總結(jié)
以上是生活随笔為你收集整理的autofac 作用域_.Net Core3.1下使用Autofac实现依赖注入的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: EXCEL散点图改横轴坐标
- 下一篇: 干货 | 秒级上下线,携程服务注册中心架