《ASP.NET Core 6框架揭秘》實例演示[04]:自定義依賴注入框架

ASP.NET Core框架建立在一個依賴注入框架之上,已注入的方式消費服務已經成為了ASP.NET Core基本的編程模式。為了使讀者能夠更好地理解原生的注入框架框架,我按照類似的設計創建了一個簡易版本的依賴注入框架,并它命名為“Cat”。本篇提供的四個實例主要體現了針對Cat的用法,《一個Mini版的依賴注入框架》提供了針對設計和實現原理的介紹。[本文節選《ASP.NET Core 6框架揭秘》第2章]

[201]模擬容器Cat-普通服務的注冊和提取(源代碼)
[202]模擬容器Cat-針對泛型服務類型的支持(源代碼)
[203]模擬容器Cat-為同一類型提供多個服務注冊(源代碼)
[204]模擬容器Cat-服務實例的生命周期(源代碼)

[201]模擬容器Cat-普通服務的注冊和提取

我們定義了如下所示的接口和對應的實現類型來演示針對Cat的服務注冊。Foo、Bar、Baz和Qux分別實現了對應的接口IFoo、IBar、IBaz和IQux,其中Qux類型上標注的MapToAttribute特性注冊了與對應接口IQux之間的映射。四個類型派生于的基類Base實現了IDisposable接口,我們在其構造函數和實現的Dispose方法中輸出相應的文本,以確定對應的實例何時被創建和釋放。我們還定義了一個泛型的接口IFoobar<T1, T2>和對應的實現類Foobar<T1, T2>,用來演示Cat針對泛型服務實例的提供。

public?interface?IFoo?{}
public?interface?IBar?{}
public?interface?IBaz?{}
public?interface?IQux?{}
public?interface?IFoobar<T1,?T2>?{}public?class?Base?:?IDisposable
{public?Base()???=>?Console.WriteLine($"Instance?of?{GetType().Name}?is?created.");public?void?Dispose()??=>?Console.WriteLine($"Instance?of?{GetType().Name}?is?disposed.");
}public?class?Foo?:?Base,?IFoo{?}
public?class?Bar?:?Base,?IBar{?}
public?class?Baz?:?Base,?IBaz{?}
[MapTo(typeof(IQux),?Lifetime.Root)]
public?class?Qux?:?Base,?IQux?{?}
public?class?Foobar<T1,?T2>:?IFoobar<T1,T2>
{public?T1?Foo?{?get;?}public?T2?Bar?{?get;?}public?Foobar(T1?foo,?T2?bar){Foo?=?foo;Bar?=?bar;}
}

Lifetime是一個代表服務實例生命周期的枚舉,它代表的三種生命周期模式定義如下。

public?enum?Lifetime
{Root,Self,Transient
}

如下所示的代碼片段創建了一個Cat對象,并采用上面提到的方式針對接口IFoo、IBar和IBaz注冊了對應的服務,它們采用的生命周期模式分別為Transient、Self和Root。另外,我們還調用了另一個將當前入口程序集作為參數的Register方法,該方法會解析指定程序集中標注了MapToAttribute特性的類型并進行批量服務注冊。對于我們演示的程序來說,該方法會完成針對IQux/Qux類型的服務注冊。接下來我們利用Cat對象創建了它的兩個子容器,并調用子容器的GetService<T>方法來提供相應的服務實例。

using?App;var?root?=?new?Cat().Register<IFoo,?Foo>(Lifetime.Transient).Register<IBar>(_?=>?new?Bar(),?Lifetime.Self).Register<IBaz,?Baz>(Lifetime.Root).Register(typeof(Foo).Assembly);
var?cat1?=?root.CreateChild();
var?cat2?=?root.CreateChild();void?GetServices<TService>(Cat?cat)?
where?TService?:?class
{cat.GetService<TService>();cat.GetService<TService>();
}GetServices<IFoo>(cat1);
GetServices<IBar>(cat1);
GetServices<IBaz>(cat1);
GetServices<IQux>(cat1);
Console.WriteLine();
GetServices<IFoo>(cat2);
GetServices<IBar>(cat2);
GetServices<IBaz>(cat2);
GetServices<IQux>(cat2);

上面的程序運行之后會在控制臺上輸出圖1所示的結果。由于服務IFoo被注冊為Transient服務,所以Cat針對四次請求都會創建一個全新的Foo對象。IBar服務的生命周期模式為Self,對于同一個Cat只會創建一個Bar對象,所以整個過程中會創建兩個Bar對象。IBaz和IQux服務采用Root生命周期,所以同根的兩個Cat對象提供的其實是同一個Baz/Qux對象。

f2edf5bfa391b99e5eb1b9f8ed7fb39d.png

圖1Cat按照服務注冊對應的生命周期模式提供服務實例

[202]模擬容器Cat-針對泛型服務類型的支持

Cat同樣可以提供泛型服務實例。如下面的代碼片段所示,在為創建的Cat對象添加了針對IFoo和IBar接口的服務注冊之后,我們調用Register方法注冊了針對泛型定義IFoobar<,>的服務注冊,具體的實現類型為Foobar<,>。當我們利用Cat對象提供一個類型為IFoobar<IFoo, IBar>的服務實例時,它會創建并返回一個Foobar<Foo, Bar>對象。

using?App;using?System.Diagnostics;var?cat?=?new?Cat().Register<IFoo,?Foo>(Lifetime.Transient).Register<IBar,?Bar>(Lifetime.Transient)????.Register(typeof(IFoobar<,>),?typeof(Foobar<,>),?Lifetime.Transient);
var?foobar?=?(Foobar<IFoo,?IBar>?)cat.GetService<IFoobar<IFoo,?IBar>>();
Debug.Assert(foobar?.Foo?is?Foo);
Debug.Assert(foobar?.Bar?is?Bar);

[203]模擬容器Cat-為同一類型提供多個服務注冊

我們可以為同一個類型提供多個服務注冊。雖然添加的所有服務注冊均是有效的,但由于GetService<TService>擴展方法總是返回一個服務實例,我們對該方法應用了“后來居上”的策略,即采用最近添加的服務注冊創建服務實例。另一個GetServices<TService>擴展方法將返回根據所有服務注冊提供的服務實例。下面的代碼片段為創建的Cat對象添加了三個針對Base類型的服務注冊,對應的實現類型分別為Foo、Bar和Baz。我們調用了Cat對象的GetServices<Base>方法返回包含三個Base對象的集合,集合元素的類型分別為Foo、Bar和Baz。

using?App;
using?System.Diagnostics;var?services?=?new?Cat().Register<Base,?Foo>(Lifetime.Transient).Register<Base,?Bar>(Lifetime.Transient).Register<Base,?Baz>(Lifetime.Transient).GetServices<Base>();
Debug.Assert(services.OfType<Foo>().Any());
Debug.Assert(services.OfType<Bar>().Any());
Debug.Assert(services.OfType<Baz>().Any());

[204]模擬容器Cat-服務實例的生命周期

如果提供服務實例的類型實現了IDisposable接口,我們必須在適當的時候調用其Dispose方法釋放它。由于服務實例的生命周期完全由作為依賴注入容器的Cat對象來管理,所以通過調用Dispose方法針對服務實例的釋放也由它負責。Cat對象針對提供服務實例的釋放策略取決于采用的生命周期模式,具體的策略如下。

  • TransientSelf:所有實現了IDisposable接口的服務實例會被當前Cat對象保存起來,當Cat對象自身的Dispose方法被調用的時候,這些服務實例的Dispose方法會隨之被調用。

  • Root:由于服務實例保存在作為根容器的Cat對象上,所以當作為根的Cat對象的Dispose方法被調用的時候,這些服務實例的Dispose方法會隨之被調用。

上述釋放策略可以通過如下演示實例來印證。如下代碼片段所示,我們創建了一個Cat對象并添加了相應的服務注冊。我們調用它的CreateChild方法創建了代表子容器的Cat對象,并用它提供了四個注冊服務對應的實例。

using?App;
using?(var?root?=?new?Cat().Register<IFoo,?Foo>(Lifetime.Transient).Register<IBar>(_?=>?new?Bar(),?Lifetime.Self).Register<IBaz,?Baz>(Lifetime.Root).Register(typeof(IFoo).Assembly))
{????using?(var?cat?=?root.CreateChild()){cat.GetService<IFoo>();cat.GetService<IBar>();cat.GetService<IBaz>();cat.GetService<IQux>();Console.WriteLine("Child?cat?is?disposed.");}Console.WriteLine("Root?cat?is?disposed.");
}

由于兩個Cat對象的創建都是在using塊中進行的,所以它們的Dispose方法都會在using塊結束的地方被調用。該程序運行之后會在控制臺上輸出圖2所示的結果,我們可以看到當作為子容器的Cat對象的Dispose方法被調用時,由它提供的兩個生命周期模式分別為Transient和Self的服務實例(Foo和Bar)被正常釋放。而生命周期模式為Root的服務實例(Baz和Qux對象)的Dispose方法會延遲到作為根容器的Cat對象的Dispose方法被調用的時候。

d0ddb466fbbb3ca7368ee235730a24b2.png
圖2 服務實例的釋放

《ASP.NET Core 6框架揭秘》實例演示[01]:編程初體驗
《ASP.NET Core 6框架揭秘》實例演示[02]:基于路由、MVC和gRPC的應用開發
《ASP.NET Core 6框架揭秘》實例演示[03]:Dapr初體驗

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284600.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284600.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284600.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【QGIS入門實戰精品教程】4.8:QGIS如何下載SRTM數字高程模型DEM?

本文講解QGIS中下載SRTM數字高程模型DEM,以黑龍江省塔河縣為例。 圖幅效果: 最終效果: 文章目錄 1. 下載安裝STRM Download插件2. 加載矢量數據,讀取范圍3. 下載STRM4. DEM拼接5. DEM裁剪1. 下載安裝STRM Download插件 點擊【插件】→【管理并安裝插件】。 在搜索框中輸入…

Win11 恢復設置Win10任務欄、快速啟動欄及右鍵菜單(Win11 22000.100版本測試通過)

恢復方法 按下邊路徑添加 UndockingDisabled項&#xff0c;DWORD (32-bit)值為1&#xff1a; [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Shell\Update\Packages] "UndockingDisabled"dword:00000001顯示效果 已知問題 開始按鈕點擊無反應&a…

Redis數據類型應用場景及具體方法總結

StringsStrings 數據結構是簡單的key-value類型&#xff0c;value其實不僅是String&#xff0c;也可以是數字。使用Strings類型&#xff0c;你可以完全實現目前 Memcached 的功能&#xff0c;并且效率更高。還可以享受Redis的定時持久化&#xff0c;操作日志及 Replication等功…

幾種距離的計算

http://www.tinysoft.com.cn/TSDN/HelpDoc/display.tsl?id12831 http://www.3566t.com/news/kvqa/1172028.html轉載于:https://www.cnblogs.com/wangduo/p/5526003.html

vue vue-router vuex element-ui axios 寫一個代理平臺的學習筆記(十一)構思商品頁面...

在寫商品頁面product.vue之前&#xff0c;我應該思考一下&#xff0c;商品頁面要實現那些功能&#xff0c;該不如布局&#xff1f;要實現的功能 1、所有商品列表的展示2、分類商品的列表展示 3、搜索商品或得列表展示4、單一商品的詳細頁面5、商品列表分頁功能6、還沒想到的...…

【ArcGIS Pro微課1000例】0019:ArcGIS Pro從海洋的視角看世界---海洋投影(Spilhaus Projection)

從海洋的視角看世界: 世界地圖大多是以陸地為主要載體,如果以海洋為主角,就需要使用一種海洋投影。該投影以Spilhaus博士的名稱命名。ArcGIS Pro自2.5版本以來提供了Spilhaus Projection。 投影效果預覽: 接下來演示ArcGIS Pro 2.8中海洋投影的轉換方法: 1. 新建一個工程…

有人擼了個網頁版win11,驚艷!

演示地址&#xff1a;https://win11.blueedge.me/ Github地址&#xff1a;https://github.com/blueedgetechno/windows11

Vue3+.NET6+C#10,最近優質前后端分離項目匯總

據說80%的WEB開發都是管理后臺&#xff0c;一套開源的優秀管理后臺開發模板堪稱福音&#xff01;分享一套Vue3 Axios TS Vite Element Plus .NET 6 WebAPI JWT SqlSugar的前后端分離架構的通用管理后臺源碼數據庫腳本&#xff0c;還有與之配套錄制的一組視頻教程&#xff0c;全…

九九乘法表

問題描述&#xff1a;打印乘法表如圖&#xff1a;1*112*12 2*243*13 3*26 3*394*14 4*28 4*312 4*4165*15 5*210 5*315 5*420 5*5256*16 6*212 6*318 6*424 6*530 6*6367*17 7*214 7*321 7*428 7*535 7*642 7…

C++ 對象的內 存布局(下)

原文地址&#xff1a;http://blog.csdn.net/haoel/article/details/3081385 (注:看本文的時候由于宿舍快斷電了,來不及細看,所以怕自己忘記,先貼出來.不排除文章有錯誤,大家自己測試一下.) 重復繼承 下面我們再來看看&#xff0c;發生重復繼承的情況。所謂重復繼承&#xff0c;…

用python快速合并代碼(方便軟著申請)

Title: This is a file for …… Author: JackieZheng Date: 2021-09-08 09:43:58 LastEditTime: 2021-09-08 21:14:22 LastEditors: Please set LastEditors Description: FilePath: \\pythonCode\\mergeCodeFile.py import os# 允許提取的文件類型 include_file_types[.php,…

【GIS風暴】一文徹底弄懂數字地形(DEM、DOM、TDOM、DSM)的區別與聯系

在2021自然資源部發布的《實景三維中國建設技術大綱(2021版)》中,空間數據部分包括“數字高程模型(DEM)、數字表面模型(DSM)、數字正射影像(DOM)、真正射影像(TDOM)、傾斜攝影三維模型、激光點云等。” 那么到底什么是DEM、DOM、TDOM、DSM,它們之間又有什么用的區別…

na+mb與gcd

蒜頭君和花椰妹在玩一個游戲&#xff0c;他們在地上將 nn 顆石子排成一排&#xff0c;編號為 11 到 nn。開始時&#xff0c;蒜頭君隨機取出了 22 顆石子扔掉&#xff0c;假設蒜頭君取出的 22 顆石子的編號為 aa, bb。游戲規則如下&#xff0c;蒜頭君和花椰妹 22 人輪流取石子&a…

什么是“異步 Request-Reply”模式?編程如何實現?

在某些情況下&#xff0c;WEB API 可能需要很長時間來處理請求&#xff0c;而客戶端如果一直等待工作完成是不可行的&#xff0c;比如連接超時等。這時&#xff0c;可以使用“異步 Request-Reply 模式”。異步 Request-Reply 模式異步 Request-Reply 模式是指&#xff1a;在后端…

【測繪程序設計】Excel度分秒(° ‘ “)轉換度(°)模板附代碼超實用版

在實際工作中,無論是ArcGIS中,還是CASS中,作圖時需要將GPS實測的經緯度度分秒( ’ ")坐標轉換為度(),在前面的文章中介紹了C#中將度分秒轉為度的轉換程序,本文講解在Excel中快速度分秒( ’ ")轉換度(),提高工作效率。 文章目錄 準備工作編寫代碼注意事…

IO擴展控件(System.IO.Abstractions)

剛看到這個Namespace的時候還以為是.Net Framework里自帶的包&#xff0c;結果查了一圈無任何結果。果斷上Github搜索&#xff0c;一擊即中 https://github.com/tathamoddie/System.IO.Abstractions先翻譯下開發者給出的簡單說明&#xff0c;今后再慢慢使用類似于System.Web.Ab…

從零開始學_JavaScript_系列(21)——dojo(8)(手把手教你封裝一個widget)

&#xff08;73&#xff09;封裝一個widget 醒目&#xff1a;必須在web環境下使用&#xff0c;無論是python的web.py或者是通過http訪問網站環境&#xff0c;都可以&#xff0c;但純本地是不可行的。 首先&#xff0c;什么是widget&#xff1f; 簡單來說&#xff0c;就是一個do…

[轉]面向對象(1、三大特征;2、六大原則)

目錄 一、面向對象的概述&#xff1a; 二、封裝&#xff1a; 1、封裝概述 2、封裝原則 3、封裝好處 4、封裝壞處 5、封裝代碼展示 三、繼承&#xff1a; 1、概念&#xff1a; 2、實現格式&#xff1a; 3、特點&#xff1a; 4、好處&#xff1a; 5、弊端&#xff1…

Python的MySQLdb模塊安裝

在配置Django時&#xff0c;選擇的是mysql數據庫&#xff0c;要安裝MySQLdb模塊&#xff0c;不過安裝過程中&#xff0c;遇到了很多errors&#xff0c;記錄一下。 系統:ubuntu 11.10 mysql:直接apt-get安裝的&#xff0c;version:5.1.62 到官方下載MySQL for Python 然后解壓&a…

【測繪程序設計】C#將度分秒(° ‘ “)轉換度(°)程序實現(附源碼)

在實際工作中,無論是ArcGIS中,還是CASS中,作圖時需要將GPS實測的經緯度度分秒( ’ ")坐標轉換為度(),在前面的文章中介紹了Excel中將度分秒轉為度的轉換程序,本文講解在Visual Studio中,采用C#語言實現快速度分秒( ’ ")轉換度(),提高工作效率。 案例…