.Net Core 依賴注入(IOC) 一些簡單的使用技巧
.Net Core 在使用IOC後,我們不必再浪費精力在管理例項的生命週期上,交給IOC代替我們管理,減少我們成噸的程式碼,面向介面程式設計更是靈活到了極致,而IOC的三種生命週期應該怎麼去使用呢,Transient(瞬態)、Scoped(作用域)、Singleton(單例)。
Transient(瞬態)
這個沒什麼好說的,就是每次注入的時候,容器自動 new 一個例項,用完就丟;
Scoped(作用域)
以Web來說,作用域的生命週期就是當次請求,請求開始後的第一次注入,就是它生命的開始,直到請求結束;
我個人常用來減少資料獲取,提升請求響應,舉一個例子:A服務是獲取全國地級市資訊的,以作用域的方式註冊到IOC容器中,B、C、D 都注入了A服務並使用了它;一個業務介面,剛好涉及到了B、C、D,當介面被呼叫,程式碼執行到了B,第一次呼叫了 A 服務請求資料庫獲取了全國地級市資料;然後執行到了C,又一次使用了A服務獲取了資料,最後D;一個請求下來,A被使用了3次,獲取了3個同樣的資料結果,這完全是在浪費資源;
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 }
那我們應該怎麼做呢,首先我們回顧一下 Scoped 的生命週期,可以說是一個例項,貫穿了整一個請求,那我們是不是可以定義一個變數,請求資料前先判斷這個變數有沒有值,沒有就去獲取資料,給它賦值,下次再呼叫的時候,直接返回這個變數的資料,這樣不管這個服務被呼叫多少次,它也只是呼叫了一次資料庫,大大節省了資源。
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 }
有人可能說會說了,不就是多呼叫幾次資料庫,現在伺服器的效能這麼好,不在乎這一點的資源;確實,如果只是多呼叫幾次資料庫,對於一些小系統來說,跟撓癢癢一樣,那這裡的呼叫資料庫換成呼叫 WebApi 呢?如果還是呼叫第三方的 API 呢?一次Http請求,不往大的說,從請求到獲取到資料,花個100ms很正常吧(網路非常好的情況當我沒說),那這個介面不需要多,呼叫10次就1s了,還沒算上其它業務邏輯的耗時呢,如果還需要呼叫其它的api,那響應時間就更長咯,難道你讓使用者開啟一個頁面,或者點選一個按鈕,需要等上兩三秒才有響應嗎,這樣的使用者體驗就非常糟糕了。
Singleton(單例)
來自依賴關係注入容器的服務實現的每一個後續請求都使用同一個例項。 如果應用需要單一例項行為,則允許服務容器管理服務的生存期。必須是執行緒安全的,並且通常在無狀態服務中使用。
在單例中,不要直接注入作用域的服務,這會引起很多莫名其妙的錯誤,一定要使用的話,就自己建立,自己管理它的生命週期:
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
有些情況下,例如當你不想把使用次數極低的類註冊到容器中,或者這個類的建構函式需要傳入一些引數,但是又需要用到容器中的服務的時候,你可以使用 ActivatorUtilities 中的 CreateInstance 去建立它,它會自動給建構函式注入所需的服務,並且還可以給建構函式傳參,滿足上面所說情況的需求。
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 建立:
1 var testTask = ActivatorUtilities.CreateInstance<TestTask>(serviceProvider, "test"); 2 3 await testTask.Execute(new CancellationToken());
寫在最後
Bootstrap Blazor 官網地址: https://www.blazor.zone
希望大佬們看到這篇文章,能給專案點個star支援下,感謝各位!
star流程:
1、訪問點選專案連結: BootstrapBlazor
2、點選star,如下圖,即可完成star,關注專案不迷路:
另外還有兩個GVP專案,大佬們方便的話也點下star唄,非常感謝:
https://gitee.com/LongbowEnterprise/BootstrapAdmin
SliderCaptcha 專案地址: https://gitee.com/LongbowEnterprise/SliderCaptcha交流群(QQ)歡迎加群討論
BA & Blazor ①(795206915) BA & Blazor ②(675147445)
- 分享自己平時使用的socket多客戶端通訊的程式碼技術點和軟體使用
- iNeuOS工業網際網路作業系統,增加2154個檢視建模(WEB組態)行業向量圖元、大屏背景及相關圖元
- 多臺雲伺服器的 Kubernetes 叢集搭建
- Elasticsearch學習系列四(聚合搜尋)
- 關於swiper外掛在vue2的使用
- 使用 Abp.Zero 搭建第三方登入模組(一):原理篇
- LVGL庫入門教程 - 顏色和影象
- 物聯網?快來看 Arduino 上雲啦
- SpringBoot JWT Redis 開源知識社群系統
- CVPR2022 | 可精簡域適應
- Spring框架系列(3) - 深入淺出Spring核心之控制反轉(IOC)
- 面試突擊59:一個表中可以有多個自增列嗎?
- CVPR2022 | 弱監督多標籤分類中的損失問題
- JDBC、ORM、JPA、Spring Data JPA,傻傻分不清楚?一文帶你釐清箇中曲直,給你個選擇SpringDataJPA的...
- Spring Security:使用者和Spring應用之間的安全屏障
- Mybatisi和Spring整合原始碼分析
- 前端學習 linux —— 第一篇
- call apply bind的作用及區別? 應用場景?
- Bika LIMS 開源LIMS集——實驗室檢驗流程概述及主頁、面板
- 軟體專案管理 7.5.專案進度模型(SPSP)