.NET Core中的一个接口多种实现的依赖注入与动态选择
最近有個需求就是一個抽象倉儲層接口方法需要SqlServer以及Oracle兩種實現(xiàn)方式,為了靈活我在依賴注入的時候把這兩種實現(xiàn)都給注入進(jìn)了依賴注入容器中,但是在服務(wù)調(diào)用的時候總是獲取到最后注入的那個方法的實現(xiàn),這時候就在想能不能實現(xiàn)動態(tài)的選擇使用哪種實現(xiàn)呢?如果可以的話那么我只需要在配置文件中進(jìn)行相應(yīng)的配置即可獲取到正確的實現(xiàn)方法的調(diào)用,這樣的話豈不快哉!今天我們就來一起探討下實現(xiàn)這種需求的幾種實現(xiàn)方式吧。
作者:依樂祝
原文地址:https://www.cnblogs.com/yilezhu/p/10236163.html
代碼演示
在開始實現(xiàn)的方式之前,我們先模擬下代碼。由于真實系統(tǒng)的結(jié)構(gòu)比較復(fù)雜,所以這里我就單獨建一個類似的項目結(jié)構(gòu)代碼。項目如下圖所示:
接下來我來詳細(xì)說下上面的結(jié)果作用及代碼。
MultiImpDemo.I 這個項目是接口項目,里面有一個簡單的接口定義ISayHello,代碼如下:
? ?public interface ISayHello{ ? ? ? ?string Talk();}很簡單,就一個模擬講話的方法。
MultiImpDemo.A 這個類庫項目是接口的一種實現(xiàn)方式,里面有一個SayHello類用來實現(xiàn)ISayHello接口,代碼如下:
MultiImpDemo.B 這個類庫項目是接口的另一種實現(xiàn)方式,里面也有一個SayHello類用來實現(xiàn)ISayHello接口,代碼如下:
MultiImpDemo.Show 這個就是用來顯示我們模擬效果的API項目,首選我們在ConfigureServices中加入如下的代碼來進(jìn)行上述兩種實現(xiàn)方式的注入:
在api實現(xiàn)里面獲取服務(wù)并進(jìn)行模擬調(diào)用:
代碼很簡單對不對?你應(yīng)該看的懂吧,這時候我們運行起來項目,然后訪問API'api/values'這個接口,結(jié)果總是顯示如下的結(jié)果:
兩種需求對應(yīng)兩種實現(xiàn)
這里有兩種業(yè)務(wù)需求!第一種業(yè)務(wù)中只需要對其中一種實現(xiàn)方式進(jìn)行調(diào)用,如:業(yè)務(wù)需要SqlServer數(shù)據(jù)庫的實現(xiàn)就行了。第二種是業(yè)務(wù)中對這兩種實現(xiàn)方式都有用到,如:業(yè)務(wù)急需要用到Oracle的數(shù)據(jù)庫實現(xiàn)同時也有用到SqlServer的數(shù)據(jù)庫實現(xiàn),需要同時往這兩個數(shù)據(jù)庫中插入相同的數(shù)據(jù)。下面分別對這兩種需求進(jìn)行解決。
業(yè)務(wù)中對這兩種實現(xiàn)方式都有用到
針對這種情況有如下兩種實現(xiàn)方式:
第二種實現(xiàn)方式
其實,在ASP.NET Core中,當(dāng)你對一個接口注冊了多個實現(xiàn)的時候,構(gòu)造函數(shù)是可以注入一個該接口集合的,這個集合里是所有注冊過的實現(xiàn)。
下面我們先改造下ConfigureServices,分別注入下這兩種實現(xiàn)
接著繼續(xù)改造下注入的方式,這里我們直接注入IEnumerable<ISayHello>如下代碼所示:
然后運行起來看下效果吧
利用AddTransient的擴(kuò)展方法public static IServiceCollection AddTransient<TService>(this IServiceCollection services, Func<IServiceProvider, TService> implementationFactory) where TService : class;然后根據(jù)我們的配置的實現(xiàn)來進(jìn)行服務(wù)實現(xiàn)的獲取。下面就讓我們利用代碼來實現(xiàn)一番吧:
然后我們具體調(diào)用的依賴注入的方式需要變化一下:
然后運行看下效果吧:
可以看到A跟B的實現(xiàn)都獲取到了!效果實現(xiàn)!
業(yè)務(wù)只需要對其中一種實現(xiàn)方式的調(diào)用
這時候我們可以根據(jù)我們預(yù)設(shè)的配置來動態(tài)獲取我們所需要的實現(xiàn)。這段話說的我自己都感覺拗口。話不多少,開魯吧!這里我將介紹三種實現(xiàn)方式。
根據(jù)我們的配置文件中設(shè)置的key來進(jìn)行動態(tài)的注入。
這種方式實現(xiàn)之前首先得進(jìn)行相應(yīng)的配置,如下所示:
?"CommonSettings": { ? ?"ImplementAssembly": "MultiImpDemo.A"}然后在注入的時候根據(jù)配置進(jìn)行動態(tài)的進(jìn)行注入:
services.AddTransient<ISayHello, A.SayHello>(); ? ? ? ? ? ?services.AddTransient<ISayHello, B.SayHello>();然后在服務(wù)調(diào)用的時候稍作修改:
OK,到這里運行一下看下效果吧!然后改下配置文件再看下效果!
第二種實現(xiàn)方式,即接口參數(shù)的方式這樣可以避免上個方法中反射所帶來的性能損耗。
這里我們改造下接口,接口中加入一個程序集的屬性,如下所示:
public interface ISayHello{ ? ? ? ?string ImplementAssemblyName { get; } ? ? ? ?string Talk();}對應(yīng)的A跟B中的實現(xiàn)代碼也要少做調(diào)整:
A:
public string ImplementAssemblyName => "MultiImpDemo.A"; ? ? ? ?public string Talk(){ ? ? ? ? ? ?return "Talk from A.SayHello";}
B:
public string ImplementAssemblyName => "MultiImpDemo.B"; ? ? ??public string Talk(){ ? ? ? ? ? ?return "Talk from B.SayHello";}
然后,在實現(xiàn)方法調(diào)用的時候稍微修改下:
效果自己運行下看下吧!
第三種實現(xiàn)是根據(jù)配置進(jìn)行動態(tài)的注冊
首先修改下ConfigureServices方法:
這樣的話就會根據(jù)我們的配置文件來進(jìn)行動態(tài)的注冊,然后我們像往常一樣進(jìn)行服務(wù)的調(diào)取即可:
?private readonly ISayHello _sayHello; ? ? ? ?public ValuesController(ISayHello sayHello) ? ? ? ?{_sayHello = sayHello;} ? ? ? ?// GET api/values[] ? ? ? ?public ActionResult<IEnumerable<string>> Get(){ ? ? ? ? ? ?return new string[] { _sayHello.Talk() };}運行即可得到我們想要的效果!
總結(jié)
本文從具體的業(yè)務(wù)需求入手,根據(jù)需求來或動態(tài)的進(jìn)行對應(yīng)服務(wù)的獲取,或同時使用兩個不同的實現(xiàn)!希望對您有所幫助!如果您有更多的實現(xiàn)方法可以在下方留言,或者加入.NET Core實戰(zhàn)千人群跟637326624大伙進(jìn)行交流,最后感謝您的閱讀!
總結(jié)
以上是生活随笔為你收集整理的.NET Core中的一个接口多种实现的依赖注入与动态选择的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何测试 ASP.NET Core We
- 下一篇: .Net Core分布式部署中的Data