.NET Core 依賴注入 使用技巧
.NET Core 在使用IOC后,我們不必再浪費(fèi)精力在管理實(shí)例的生命周期上,交給IOC代替我們管理,減少我們成噸的代碼,面向接口編程更是靈活到了極致,而IOC的三種生命周期應(yīng)該怎么去使用呢,Transient(瞬態(tài))、Scoped(作用域)、Singleton(單例)。
Transient(瞬態(tài))
這個(gè)沒(méi)什么好說(shuō)的,就是每次注入的時(shí)候,容器自動(dòng) new 一個(gè)實(shí)例,用完就丟;
Scoped(作用域)
以Web來(lái)說(shuō),作用域的生命周期就是當(dāng)次請(qǐng)求,請(qǐng)求開(kāi)始后的第一次注入,就是它生命的開(kāi)始,直到請(qǐng)求結(jié)束;
我個(gè)人常用來(lái)減少數(shù)據(jù)獲取,提升請(qǐng)求響應(yīng),舉一個(gè)例子:A服務(wù)是獲取全國(guó)地級(jí)市信息的,以作用域的方式注冊(cè)到IOC容器中,B、C、D 都注入了A服務(wù)并使用了它;一個(gè)業(yè)務(wù)接口,剛好涉及到了B、C、D,當(dāng)接口被調(diào)用,代碼執(zhí)行到了B,第一次調(diào)用了 A 服務(wù)請(qǐng)求數(shù)據(jù)庫(kù)獲取了全國(guó)地級(jí)市數(shù)據(jù);然后執(zhí)行到了C,又一次使用了A服務(wù)獲取了數(shù)據(jù),最后D;一個(gè)請(qǐng)求下來(lái),A被使用了3次,獲取了3個(gè)同樣的數(shù)據(jù)結(jié)果,這完全是在浪費(fèi)資源;
public?class?AService
{
????public?async?CityData?GetCityDataAsync()
????{
????????return?await?GetDatasFromApi();
????}
}
public?class?BService
{
????private?readonly?AService?_aService;
????public?BService(AService?aService)
????{
????????_aService?=?aService;
????}
????
????public?async?Task?Execute()
????{
????????await?_aService.GetCityDataAsync();
????}
}
public?class?CService
{
????private?readonly?AService?_aService;
????public?CService(AService?aService)
????{
????????_aService?=?aService;
????}
????public?async?Task?Execute()
????{
????????await?_aService.GetCityDataAsync();
????}
}
public?class?DService
{
????private?readonly?AService?_aService;
????public?DService(AService?aService)
????{
????????_aService?=?aService;
????}
????public?async?Task?Execute()
????{
????????await?_aService.GetCityDataAsync();
????}
}
不是可以定義一個(gè)變量,請(qǐng)求數(shù)據(jù)前先判斷這個(gè)變量有沒(méi)有值,沒(méi)有就去獲取數(shù)據(jù),給它賦值,下次再調(diào)用的時(shí)候,直接返回這個(gè)變量的數(shù)據(jù),這樣不管這個(gè)服務(wù)被調(diào)用多少次,它也只是調(diào)用了一次數(shù)據(jù)庫(kù),大大節(jié)省了資源。
public?class?AService
{
????private?List?cityDatas;
????????
????public?async?List?GetCityDataAsync()
????{
????????if(cityDatas?==?null||?!cityDatas.Any())
????????{
????????????cityDatas?=?await?GetDatasFromApi();
????????}
????????
????????return?cityDatas;
????}
}
有人可能說(shuō)會(huì)說(shuō)了,不就是多調(diào)用幾次數(shù)據(jù)庫(kù),現(xiàn)在服務(wù)器的性能這么好,不在乎這一點(diǎn)的資源;確實(shí),如果只是多調(diào)用幾次數(shù)據(jù)庫(kù),對(duì)于一些小系統(tǒng)來(lái)說(shuō),跟撓癢癢一樣,那這里的調(diào)用數(shù)據(jù)庫(kù)換成調(diào)用 WebApi 呢?
如果還是調(diào)用第三方的 API 呢?一次Http請(qǐng)求,不往大的說(shuō),從請(qǐng)求到獲取到數(shù)據(jù),花個(gè)100ms很正常吧(網(wǎng)絡(luò)非常好的情況當(dāng)我沒(méi)說(shuō)),那這個(gè)接口不需要多,調(diào)用10次就1s了,還沒(méi)算上其它業(yè)務(wù)邏輯的耗時(shí)呢,如果還需要調(diào)用其它的api,那響應(yīng)時(shí)間就更長(zhǎng)咯,難道你讓用戶打開(kāi)一個(gè)頁(yè)面,或者點(diǎn)擊一個(gè)按鈕,需要等上兩三秒才有響應(yīng)嗎,這樣的用戶體驗(yàn)就非常糟糕了。
Singleton(單例)
來(lái)自依賴關(guān)系注入容器的服務(wù)實(shí)現(xiàn)的每一個(gè)后續(xù)請(qǐng)求都使用同一個(gè)實(shí)例。如果應(yīng)用需要單一實(shí)例行為,則允許服務(wù)容器管理服務(wù)的生存期。必須是線程安全的,并且通常在無(wú)狀態(tài)服務(wù)中使用。
在單例中,不要直接注入作用域的服務(wù),這會(huì)引起很多莫名其妙的錯(cuò)誤(經(jīng)過(guò)評(píng)論區(qū)大佬的指正,修正這個(gè)不恰當(dāng)?shù)挠迷~,這里引用大佬的一段話) 單例中引用Scoped,Scoped就會(huì)提升為單例,這就很容易發(fā)生錯(cuò)誤,一定要使用的話,就自己創(chuàng)建,自己管理它的生命周期:
public?class?Scope
{
????private?readonly?IServiceScopeFactory?_serviceScopeFactory;
????public?Scope(IServiceScopeFactory?serviceScopeFactory)
????{
????????_serviceScopeFactory?=?serviceScopeFactory;
????}
????public?async?Task?CreateScope()
????{
????????using?var?scope?=?_serviceScopeFactory.CreateScope();
????????var?service?=?scope.ServiceProvider.GetRequiredService();
????}
}
ActivatorUtilities
有些情況下,例如當(dāng)你不想把使用次數(shù)極低的類注冊(cè)到容器中,或者這個(gè)類的構(gòu)造函數(shù)需要傳入一些參數(shù),但是又需要用到容器中的服務(wù)的時(shí)候,你可以使用 ActivatorUtilities 中的 CreateInstance 去創(chuàng)建它,它會(huì)自動(dòng)給構(gòu)造函數(shù)注入所需的服務(wù),并且還可以給構(gòu)造函數(shù)傳參,滿足上面所說(shuō)情況的需求。
public?class?TestTask?:?ITask
{
????private?readonly?IServiceScopeFactory?_serviceScopeFactory;
????private?readonly?IRabbitMQService?_rabbitMQService;
????private?readonly?string?_name;
????public?TestTask(IServiceScopeFactory?serviceScopeFactory,?IRabbitMQService?rabbitMQService,?string?name)
????{
????????_serviceScopeFactory?=?serviceScopeFactory;
????????_rabbitMQService?=?rabbitMQService;
????????_name?=?name;
????}
????///?
????///?
????///?
????///?
????///?
????///?
????public?async?Task?Execute(CancellationToken?cancellationToken)
????{
????????try
????????{
????????????using?var?scope?=?_serviceScopeFactory.CreateScope();
????????????var?executionService?=?scope.ServiceProvider.GetService();
????????????if?(executionService?!=?null)
????????????{
????????????????await?_rabbitMQService.RabbitMQReceiveService.SingleAsync(executionService.ExecuteAsync);
????????????}
????????}
????????catch?(Exception?err)
????????{
????????????Console.WriteLine(err.Message);
????????}
????}
}
使用 ActivatorUtilities 創(chuàng)建:
var?testTask?=?ActivatorUtilities.CreateInstance(serviceProvider,?"test");
await?testTask.Execute(new?CancellationToken());
寫在最后
Bootstrap Blazor 官網(wǎng)地址:https://www.blazor.zone
希望大佬們看到這篇文章,能給項(xiàng)目點(diǎn)個(gè)star支持下,感謝各位!
Star流程:
1、訪問(wèn)點(diǎn)擊項(xiàng)目鏈接:https://gitee.com/LongbowEnterprise/BootstrapBlazor
2、點(diǎn)擊star,如下圖,即可完成star,關(guān)注項(xiàng)目不迷路:

另外還有兩個(gè)GVP項(xiàng)目,大佬們方便的話也點(diǎn)下star唄,非常感謝:
BootstrapAdmin:https://gitee.com/LongbowEnterprise/BootstrapAdmin
SliderCaptcha :https://gitee.com/LongbowEnterprise/SliderCaptcha
轉(zhuǎn)自:一事冇誠(chéng)
鏈接:cnblogs.com/ysmc/p/16240534.html
