ASP.NET Core依賴註入系統學習教程:關於服務註冊使用到的方法

来源:https://www.cnblogs.com/green-jcx/archive/2022/08/11/16576653.html
-Advertisement-
Play Games

在.NET Core的依賴註入框架中,服務註冊的信息將會被封裝成ServiceDescriptor對象,而這些對象都會存儲在IServiceCollection介面類型表示的集合中,另外,IServiceCollection介面類型預設使用的實現類型為ServiceCollection。這樣來看,實 ...


在.NET Core的依賴註入框架中,服務註冊的信息將會被封裝成ServiceDescriptor對象,而這些對象都會存儲在IServiceCollection介面類型表示的集合中,另外,IServiceCollection介面類型預設使用的實現類型為ServiceCollection。這樣來看,實際上服務註冊這回事,它就是一個將創建的ServiceDescriptor對象添加到IServiceCollection介面類型集合中的過程。

通常一個項目,都是由大量的對象相互協作而構建成的應用程式。所以對於使用依賴註入框架的應用程式而言,需要進行大量的服務註冊,並且其中會存在不同形式的註冊需求。.NET Core為此提供了大量不同形式的服務註冊方法,為了方便使用,它將這些方法都定義為了IServiceCollection介面的擴展方法,這些擴展方法主要分佈在

ServiceCollectionServiceExtensions和ServiceCollectionDescriptorExtensions這兩個類中。這兩個類型都可以實現服務的註冊,但是具有如下不同的側重點:

  1. ServiceCollectionServiceExtensions:提供以生命周期模式命名,無需指定生命周期參數的註冊方法;
  2. ServiceCollectionDescriptorExtensions:主要以ServiceDescriptor對作為參數進行服務註冊,並包含避免同一類型服務重覆註冊的方法和維護IServiceCollection集合的方法;

個人覺得前者更加簡單易用,後者則配置靈活且功能豐富,下麵將圍繞這兩個類型中的服務註冊方法進行介紹。


1.ServiceCollectionServiceExtensions

該類型中關於服務註冊方法的命名,通常是以固定字元“Add”作為首碼,“Add”後面則是會加上不同的生命周期模式名稱。該類型中的註冊方法也屬於實際開發場景中較為常用的一種,因為使用這種方式的好處是:無需在服務註冊時傳入一個具體的生命周期,而是根據服務對生命周期模式的需求,選擇與模式名稱相同的方法即可。

例如,需要創建生命周期模式為Singleton的服務,那麼與之對應的註冊方法就是AddSingleton。並且可以根據AddSingleton方法的重載選擇任意一種提供服務實例的方式。一般最常用的重載形式是,使用對應泛型方法傳入服務類型和實現類型,例如下麵的使用方式:

1    var collection = new ServiceCollection();
2    collection.AddSingleton<IFooBar, FooBar>(); 

該類型的註冊方法主要都是根據3種生命周期模式而設計,並結合ServiceDescriptor類型中3種提供服務實例的方式進行擴展,從而延申出了很多重載形式,更加方便的為應用程式提供服務註冊。如果想要具體瞭解每個生命周期模式的不同重載可以參考官方說明:

https://docs.microsoft.com/zh-cn/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectionserviceextensions?view=dotnet-plat-ext-6.0


2.ServiceCollectionDescriptorExtensions

相比ServiceCollectionServiceExtensions類型中的方法而言,雖然ServiceCollectionDescriptorExtensions類型從名稱上只有一詞之差,但是它的方法涉及範圍更加豐富。該類型不僅具備服務的註冊,還具備了對服務註冊信息的“增刪改”,並且包含針對服務註冊重覆性判斷的方法,接下來則針對該類型中的方法進行一個介紹。

2.1.Add

該方法需要我們將服務註冊的信息創建為一個ServiceDescriptor對象,並將該對象作為參數傳入Add方法,以此形式作為服務註冊。該方法有兩種重載形式,一種是添加單個ServiceDescriptor對象,另一種是可以添加多個ServiceDescriptor對象的集合,對於該方法的調用示例可以參考如下代碼:

 1             //服務註冊信息集合
 2             var serviceCollection = new ServiceCollection();
 3 
 4             //添加“單個”服務註冊信息對象
 5             ServiceDescriptor descriptor = new ServiceDescriptor(typeof(IFooBar),typeof(FooBar), ServiceLifetime.Singleton);
 6             serviceCollection.Add(descriptor);
 7 
 8             //添加“多個”服務註冊信息對象
 9             List<ServiceDescriptor> descriptorList = new List<ServiceDescriptor>()
10             {
11                     new ServiceDescriptor(typeof(IAnimal),typeof(Dog), ServiceLifetime.Singleton),
12                     new ServiceDescriptor(typeof(IEmployee),typeof(Programmer), ServiceLifetime.Singleton)
13             };
14             serviceCollection.Add(descriptorList);

2.2.服務重覆註冊

.NET Core依賴註入框架中支持對同一服務類型進行多次註冊。因為後續介紹的某些方法會針對這種重覆多次的註冊方式有相應的處理邏輯,所以在介紹那些方法之前,首先來介紹下服務重覆註冊這個行為有哪些特點。

1.對於同一個服務類型進行多次註冊,使用GetService獲取實例時,只會獲取一個最近註冊的服務實例。例如下圖的代碼示例中,分別針對同一服務類型IAnimal進行了多次註冊,其中實現類型包含:Dog、Cat、Pig,但最後獲取的實例只有Pig一個。

2.對於同一個服務類型進行多次註冊,如果要獲取該服務類型註冊的所有服務實例,則可以使用GetServices方法來獲取。例如下圖的代碼示例中,分別針對同一服務類型Base進行了多次註冊,在通過調用GetServices方法後,將服務類型Base註冊的所有服務實例都存儲到了一個集合中。

 2.3.TryAdd形式的方法

之所以在在此處介紹的標題為TryAdd形式的方法,是因為除了TryAdd方法本身之外,還有以TryAdd作為方法名稱首碼的方法,分別是:TryAdd{生命周期模式}和TryAddEnumerable,並且3個方法都是圍繞同一個主題,即避免服務重覆註冊。它們在調用的時候都會去檢查服務類型是否已經註冊過,如果已經註冊了,則放棄當前方法的註冊。TryAdd方法本身和TryAdd{生命周期模式}處理的邏輯基本是一致的,TryAddEnumerable處理會略有不同,下麵針對這3類TryAdd形式的方法進行逐一介紹。

TryAdd

該方法需要我們將服務註冊的信息創建為一個ServiceDescriptor對象,類似於Add方法,只不過在Add的基礎上加了服務重覆註冊的判斷邏輯,使用方式如下圖示例:

該示例執行的結果:最終只會獲取到第一次註冊的服務示例,因為當第二次調用TryAdd時就發現了已經存在相同服務類型的註冊,此時它會放棄註冊行為。

TryAdd{生命周期模式}

TryAdd{生命周期模式}類型的方法可以看作是TryAdd方法的一種延申形式,處理邏輯和TryAdd方法一致。但是使用起來更加的便捷,因為它是根據3種生命周期模式擴展而來的版本,使用該類型方法註冊時無需指定生命周期模式參數,而是根據生命周期需求選擇對應的方法名來決定生命周期模式。

 

以上是TryAdd{生命周期模式}類方法的使用示例,可以看出相比TryAdd方法而言,該方法更加方便,我們無需創建ServiceDescriptor對象和指定生命周期模式。該示例以Singleton模式為例,其他兩種模式的調用與此一致,此處就不一一演示了。

TryAddEnumerable

對於TryAddEnumerable方法判斷服務重覆性的邏輯而言,不在是和前兩者的方法一樣:僅僅使用服務類型這一個條件來判斷重覆性。TryAddEnumerable方法在檢查重覆性時會同時考慮“服務類型”和“實現類型”。如果發現某個服務註冊信息對象的“服務類型”和“實現類型”,與當前即將要註冊服務信息的“服務類型”和“實現類型”相同時,TryAddEnumerable方法會放棄當前的註冊,以避免出現對於這種情況的重覆註冊。下麵基於這個邏輯通過代碼示例來證明這一點。

對於上面的示例而言,都是針對同一服務類型使用TryAddEnumerable方法的註冊。其中對於第三次進行的Dog的註冊而言,此時的ServiceCollection服務註冊集合中已經存在了一個相同服務類型的註冊,並且已存在的這個服務註冊的實現類型也與之相同,所以第三次進行的註冊被TryAddEnumerable方法認定為一個重覆性的註冊,故沒有添加到ServiceCollection集合中。而Cat註冊時雖然已經存在了相同服務類型的IAnimal,但是沒有服務類型和實現類型同時相同的Cat註冊,即不滿足TryAddEnumerable的重覆性判斷條件,所以該服務註冊會被添加到ServiceCollection服務註冊集合中。


3.維護性方法

.NET Core依賴註入框架對於服務註冊的行為,實際上就是將ServiceDescriptor(服務註冊信息描述對象)添加到IServiceCollection集合中的過程。所以對於一個集合而言除了用於服務註冊的添加方法之外,還有一些維護性的方法,用於對IServiceCollection中的服務註冊進行:刪除、替換、清空等操作,這些方法的來源主要來自兩點:

  1. 由IList<ServiceDescriptor>介面繼承而來;
  2. ServiceCollectionDescriptorExtensions類定義的擴展方法;

下麵通過代碼示例對一些常用的方法進行演示,並通過註釋對方法使用的細節進行強調:

 1            var serviceCollection = new ServiceCollection();
 2             serviceCollection.AddSingleton<IAnimal, Dog>();
 3             serviceCollection.AddSingleton<Base, Pig>();
 4 
 5             //替換:將舊的ServiceDescriptor對象刪除,在新增一個新的ServiceDescriptor對象
 6             var catDescriptor = ServiceDescriptor.Scoped<IAnimal, Cat>();
 7             serviceCollection.Replace(catDescriptor);
 8 
 9             //刪除:刪除指定服務類型的註冊
10             serviceCollection.RemoveAll<Base>();
11 
12             //清空ServiceCollection集合中所有的服務註冊信息對象
13             serviceCollection.Clear();

4.自動註冊

.NET Core依賴註入框架雖然為我們提供了豐富的服務註冊方法,但是對於大型的項目而言,服務註冊將成為一種高頻次且重覆性的枯燥工作,那麼對於這樣的一種情形而言,有沒有一種自動化的註冊方式呢?答案是有的,就是藉助使用一個第三方開源的NetCore.AutoRegisterDi組件來實現服務的自動註冊。下麵將通過一個示例來演示如何使用NetCore.AutoRegisterDi組件。

1.從NuGet下載NetCore.AutoRegisterDi

通過NuGet下載組件的方式有很多,你可以用不同的下載,本示例通過利用VS中可視化的NuGet界面進行下載。

2.建立特征

NetCore.AutoRegisterDi組件自動化註冊的前提是,要求服務註冊的實現類型具有某一種特征,該組件會基於這種特征查找出與該特征匹配的所有類型,然後對這些符合特征的類型進行服務註冊,最終註入到依賴它的類型中。本示例中服務註冊的實現類型所採用的特征是:所有服務實現類型名稱都是以“Service”結尾。

 1 using System;
 2 
 3 namespace DependencyInjectionDemo
 4 {
 5     //服務類型
 6     public interface IComputer 
 7     {
 8         string SayHi(); //打招呼
 9     }
10 
11     //服務實現類型
12     public class ComputerService : IComputer
13     {
14         public string SayHi()
15         {
16             return "你好,我是戴爾電腦。";
17         }
18     }
19 
20 }

3.定義註入形式

本示例中是將註冊的服務提供給MVC中的控制器對象,控制器對象對依賴的服務提供以構造函數形式的註入方式,如下代碼所示。

 1  public class HomeController : Controller
 2     {
 3         private IComputer _computer;
 4 
 5         public HomeController(IComputer computer)
 6         {
 7             _computer = computer;
 8         }
 9 
10         public IActionResult Index()
11         {
12             ViewBag.Msg = _computer.SayHi();
13             return View();
14         }
15 
16     }

4.配置自動註冊

以ASP.NET Core的項目為例,我們需要在Startup類的ConfigureServices方法中添加如下的代碼:

1            //獲取服務實現類型所在的程式集,一般都在實體層
2            var modelAssembly = Assembly.Load("DependencyInjectionDemo");
3 
4             //服務自動註冊
5             services.RegisterAssemblyPublicNonGenericClasses(modelAssembly)
6                         .Where(c => c.Name.EndsWith("Service"))  
7                         .AsPublicImplementedInterfaces(ServiceLifetime.Scoped);

其中RegisterAssemblyPublicNonGenericClasses方法用於獲取某個程式集中的所有類型(在實際的項目中我們的服務實現類型一般都定義在實體層),在RegisterAssemblyPublicNonGenericClasses方法調用之後,根據為“服務實現類型”定義的特征來獲取相應的類型,此處我們使用Where方法結合特征(以Service結尾的類)篩選出相應的類型。AsPublicImplementedInterfaces方法表示,將針對前面兩個方法篩選出的所有公共實現類型,使用指定的生命周期模式結合服務類型進行服務註冊。

在完成以上的步驟後,後續對於應用程式的服務註冊,都將由NetCore.AutoRegisterDi組件自動完成,那麼這樣一來,對於後續使用依賴註入框架而言,我們僅僅只需要為依賴的服務定義構造函數的註入形式即可。


 

學習感悟:學習就像是燒開水,燒到30度、60度、90度,燒的次數在多,沒有燒到100度沸點則都是白費。

 

知識改變命運
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • “什麼是IO的多路復用機制?” 這是一道年薪50W的面試題,很遺憾,99%的人都回答不出來。 大家好,我是Mic,一個工作了14年的Java程式員。 今天,給大家分享一道網路IO的面試題。 這道題目的文字回答已經整理到了15W字的面試文檔裡面,大家可以S我領取。 下麵看看高手的回答。 高手: IO多 ...
  • 多商戶商城系統,也稱為B2B2C(BBC)平臺電商模式多商家商城系統。可以快速幫助企業搭建類似拼多多/京東/天貓/淘寶的綜合商城。 多商戶商城系統支持商家入駐加盟,同時滿足平臺自營、旗艦店等多種經營方式。平臺可以通過收取商家入駐費,訂單交易服務費,提現手續費,簡訊通道費等多手段方式,實現整體盈利。 ...
  • 原文連接:https://www.zhoubotong.site/post/67.html Go 標準庫的net/url包提供的兩個函可以直接檢查URL合法性,不需要手動去正則匹配校驗。 下麵可以直接使用ParseRequestURI()函數解析URL,當然這個只會驗證url格式,至於功能變數名稱是否存在或 ...
  • Python帶我起飛——入門、進階、商業實戰_ 免費下載地址 內容簡介 · · · · · · 《Python帶我起飛——入門、進階、商業實戰》針對Python 3.5 以上版本,採用“理論+實踐”的形式編寫,通過大量的實例(共42 個),全面而深入地講解“Python 基礎語法”和“Python ...
  • 1、應用場景 1.1 kafka場景 ​ Kafka最初是由LinkedIn公司採用Scala語言開發,基於ZooKeeper,現在已經捐獻給了Apache基金會。目前Kafka已經定位為一個分散式流式處理平臺,它以 高吞吐、可持久化、可水平擴展、支持流處理等多種特性而被廣泛應用。 ​ Apache ...
  • Redis是大規模互聯網應用常用的記憶體高速緩存資料庫,它的讀寫速度非常快,據官方 Bench-mark的數據,它讀的速度能到11萬次/秒,寫的速度是8.1萬次/秒。 1. 認識Spring Cache 在很多應用場景中通常是獲取前後相同或更新不頻繁的數據,比如訪問產品信息數據、網頁數據。如果沒有使用 ...
  • .NET nanoFramework 安裝教程 準備材料​ esp32單片機(支持wifi藍牙) 安卓數據線(需要支持傳輸) 註意!請先安裝esp32驅動程式​ ESP32驅動鏈接 安裝 .NET nanoFramework固件快閃記憶體​ 安裝工具 dotnet tool install -g nano ...
  • 如果業務邏輯比較簡單的話,一條主管道就夠了,確實用不到分支管道。不過當業務邏輯比較複雜的時候,有時候我們可能希望根據情況的不同使用特殊的一組中間件來處理 HttpContext。這種情況下如果只用一條管道,處理起來會非常麻煩和混亂。此時就可以使用 Map/MapWhen/UseWhen 建立一個分支 ...
一周排行
    -Advertisement-
    Play Games
  • 一:背景 1.講故事 在分析的眾多dump中,經常會遇到各種奇葩的問題,僅通過dump這種快照形式還是有很多問題搞不定,而通過 perfview 這種粒度又太粗,很難找到問題之所在,真的很頭疼,比如本篇的 短命線程 問題,參考圖如下: 我們在 t2 時刻抓取的dump對查看 短命線程 毫無幫助,我根 ...
  • 在日常後端Api開發中,我們跟前端的溝通中,通常需要協商好入參的數據類型,和參數是通過什麼方式存在於請求中的,是表單(form)、請求體(body)、地址欄參數(query)、還是說通過請求頭(header)。 當協商好後,我們的介面又需要怎麼去接收這些數據呢?很多小伙伴可能上手就是直接寫一個實體, ...
  • 許多情況下我們需要用到攝像頭獲取圖像,進而處理圖像,這篇博文介紹利用pyqt5、OpenCV實現用電腦上連接的攝像頭拍照並保存照片。為了使用和後續開發方便,這裡利用pyqt5設計了個相機界面,後面將介紹如何實現,要點包括界面設計、邏輯實現及完整代碼。 ...
  • 思路分析 註冊頁面需要對用戶提交的數據進行校驗,並且需要對用戶輸入錯誤的地方進行提示! 所有我們需要使用forms組件搭建註冊頁面! 平時我們書寫form是組件的時候是在views.py裡面書寫的, 但是為了接耦合,我們需要將forms組件都單獨寫在一個地方,需要用的時候導入就行! 例如,在項目文件 ...
  • 思路分析 登錄頁面,我們還是採用ajax的方式提交用戶數據 唯一需要學習的是如何製作圖片驗證碼! 具體的登錄頁面效果圖如下: 如何製作圖片驗證碼 推導步驟1:在img標簽的src屬性里放上驗證碼的請求路徑 補充1.img的src屬性: 1.圖片路徑 2.url 3.圖片的二進位數據 補充2:字體樣式 ...
  • 哈嘍,兄弟們! 最近有許多小伙伴都在吐槽打工好難。 每天都是執行許多重覆的任務 例如閱讀新聞、發郵件、查看天氣、打開書簽、清理文件夾等等, 使用自動化腳本,就無需手動一次又一次地完成這些任務, 非常方便啊有木有?! 而在某種程度上,Python 就是自動化的代名詞。 今天就來和大家一起學習一下, 用 ...
  • 作者:IT王小二 博客:https://itwxe.com 前面小二介紹過使用Typora+PicGo+LskyPro打造舒適寫作環境,那時候需要使用水印功能,但是小二在升級LskyPro2.x版本發現有很多不如人意的東西,遂棄用LskyPro使用MinIO結合代碼實現自己需要的圖床功能,也適合以後 ...
  • OpenAI Gym是一款用於研發和比較強化學習演算法的工具包,本文主要介紹Gym模擬環境的功能和工具包的使用方法,並詳細介紹其中的經典控制問題中的倒立擺(CartPole-v0/1)問題。最後針對倒立擺問題如何建立控制模型並採用爬山演算法優化進行了介紹,並給出了相應的完整python代碼示例和解釋。要... ...
  • python爬蟲瀏覽器偽裝 #導入urllib.request模塊 import urllib.request #設置請求頭 headers=("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, l ...
  • 前端代碼搭建 主要利用的是bootstrap3中js插件里的模態框版塊 <li><a href="" data-toggle="modal" data-target=".bs-example-modal-lg">修改密碼</a></li> <div class="modal fade bs-exam ...