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

另外還有兩個GVP項目,大佬們方便的話也點(diǎn)下star唄,非常感謝:
BootstrapAdmin 項目地址:
https://gitee.com/LongbowEnterprise/BootstrapAdmin
SliderCaptcha 項目地址:
https://gitee.com/LongbowEnterprise/SliderCaptcha
交流群(QQ)歡迎加群討論
BA & Blazor ①(795206915) BA & Blazor ②(675147445)


本文來自博客園,作者:一事冇誠,轉(zhuǎn)載請注明原文鏈接:http://www.rzrgm.cn/ysmc/p/16240534.html

浙公網(wǎng)安備 33010602011771號