日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

Dependency injection in .NET Core的最佳实践

發(fā)布時間:2023/12/4 asp.net 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Dependency injection in .NET Core的最佳实践 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

我們知道依賴注入(DI)是一種實現(xiàn)對象及其協(xié)作者或依賴關(guān)系之間松散耦合的技術(shù)。 ASP.NET Core包含一個簡單的內(nèi)建容器來支持構(gòu)造器注入。
我們試圖將DI的最佳實踐帶到.NET Core應(yīng)用程序中,這表現(xiàn)在以下方面:

  • 構(gòu)造器注入

  • 注冊組件

  • DI in testing


  • 構(gòu)造器注入

    我們可以通過方法注入、屬性注入、構(gòu)造器注入的方式來注入具體的實例,一般來說構(gòu)造器注入的方式被認(rèn)為是最好的方式,所以在應(yīng)用程序中將使用構(gòu)造器注入,請避免使用別的注入方式。一個構(gòu)造器注入的例子如:


    public?class?CharacterRepository : ICharacterRepository{????private?readonly?ApplicationDbContext _dbContext;????public?CharacterRepository(ApplicationDbContext dbContext)????{????????_dbContext = dbContext;????}}


    注冊組件到容器

    在使用DI之前,需要告訴容器組件之間的對應(yīng)關(guān)系,例如:


    container.Register<IAService, AService>();

    所以當(dāng)你使用構(gòu)造器注入的時候,你告訴構(gòu)造函數(shù)需要注入IAService類型的實例,容器會根據(jù)你之前注冊的對應(yīng)關(guān)系創(chuàng)建AService的實例。
    看起來一切都很簡單,但在實際應(yīng)用過程中并沒有這么簡單,試想在一個項目中,組件有成千上萬個,這成千上萬個組件之間的對應(yīng)關(guān)系怎么樣維護?
    一個稍微改進點的策略根據(jù)這些組件的職責(zé)分類,把某一類組件的對應(yīng)關(guān)系抽取成方法:


    private?void?RegisterApplicationServices(Container container){????container.Register<IAApplicationService, AApplicationService>();????container.Register<IBApplicationService, BApplicationService>();????//...}private?void?RegisterDomainServices(Container container){????container.Register<IADomainService, ADomainService>();????container.Register<IBDomainService, BDomainService>();????//...}private?void?RegisterOtherServices(Container container){????container.Register<IDataTimeSource, DataTimeSource>();????container.Register<IUserFetcher, UserFetcher>();????//...}

    這兩個分類有什么特點呢?第一個方法試圖把所有的ApplicationService的組件對應(yīng)關(guān)系匯總在一起,第二個方法試圖把所有的DomainService的組件對應(yīng)關(guān)系匯總在一起,比起之前已經(jīng)有了很大的進步。不過隨著組件的增加,你需要不斷修改這幾個方法。

    基于公共接口來注冊組件

    第一個方法已經(jīng)找到了同一類的組件,既然這些組件的性質(zhì)是一樣的,就可以用同樣的接口來表示,定義一個空接口用來表示ApplicationService:


    public?interface?IApplicationService {}public?interface?IAApplicationService : IApplicationService { //.. }public?interface?IBApplicationService : IApplicationService { //.. }

    一旦這些組件有了公共特點,嘗試創(chuàng)建下面的擴展:


    container.Register(Classes.FromAssembly().BaseOn<IApplicationService>().WithDefaultInterface());

    這句代碼的意思是顯而易見的,掃描某個程序集,找到所有實現(xiàn)了IApplicationService的類進而把組件的對照關(guān)系注冊到了容器中。

    當(dāng)組件擁有多個接口

    類是可以擁有多個接口的,在實際開發(fā)中,這樣的設(shè)計也是很常見的:


    public?interface?IOptions { //... }public?interface?IAlipayOptions : IOptions { //... }public?class?AlipayOptions: IAlipayOptions { //... }

    利用上面介紹的擴展注冊所有Options:


    container.Register(Classes.FromAssembly().BaseOn<IOptions>().WithDefaultInterface());

    嘗試通過下面的構(gòu)造器注入:


    public?AlipayPayment(IAlipayOptions alipayOptions) { //... }

    工作的很好,沒有問題。但是當(dāng)我們試圖從容器里拿到所有的IOptions類型:


    container.ResolveAll<IOptions>();

    你得不到任何IOptions類型的實例,原因在于向容器注冊對應(yīng)關(guān)系的過程是一對一的,我們之前的擴展.WithDefaultInterface()只注冊了AlipayOptions和IAlipayOptions的關(guān)系,如果想通過上面的方式拿到所有繼承了IOptions的實例,則需要使用另一個擴展:


    container.Register(Classes.FromAssembly().BaseOn<IOptions>().WithAllInterfaces());

    把注冊文件放在正確的位置

    我們通過分層的方式隔離了不同職責(zé)的程序集,最終Web/API項目將會引用這些低層的程序集。要想把 Web/API啟動起來,需要把所有程序集定義的組件注冊在Web/API項目的容器中。我們把Web/API這種能夠啟動的程序集叫做客戶端。所以一個典型的客戶端需要通過下面代碼來注冊DI容器:


    container.Register(Classes.FromAssembly().BaseOn<IApplicationService>().WithDefaultInterface());container.Register(Classes.FromAssembly().BaseOn<IDomainService>().WithDefaultInterface());//...// 還有其他無法用公共接口表示的組件,這些組件可能來自于低層服務(wù)container.Register<IDateTimeSource, DateTimeSource>();container.Register<IUserFetcher, UserFetcher>();//...

    這段代碼描述了一個現(xiàn)象,Web/API客戶端對低層的組件對應(yīng)關(guān)系一清二楚,違反了Tell, Don't Ask Priciple. 正確的做法是:
    Web/API客戶端告訴低層組件,幫我安裝你所在的程序集中所有的組件對應(yīng)關(guān)系。


    // 安裝所有services.Install(FromAssembly.Contains<IApplicationService>());services.Install(FromAssembly.Contains<IDomainService>());services.Install(FromAssembly.Contains<IOtherService>());

    具體的組件對應(yīng)關(guān)系應(yīng)該定義在相應(yīng)的程序集中。
    這一節(jié)的思想都來源于Windsor Castle。

    DI in testing

    人們在不斷討論單元測試的各種風(fēng)格和差異,類似于通過Mock來管理依賴的單元測試被認(rèn)為是一種反模式。見:To Kill a Mockingtest, 而DI的另一個功能在于便于寫出有價值和有效的單元測試。
    當(dāng)你選擇測試一個組件時,實際上要花很多的時間來準(zhǔn)備依賴數(shù)據(jù),這是顯而易見的,因為組件并不是獨立存在的。試想如果你能從容器中拿到這個組件,容器就會將所有的依賴關(guān)系創(chuàng)建好。
    但是問題來了,比如說你的被測試組件依賴了一個能夠給第三方發(fā)送請求的組件,這顯然并不是你所期望的,你只需要注冊一個假的事先準(zhǔn)備好的組件即可。
    對ApplicationServiceTests的組件注冊如下:


    container.Install(FromAssembly.Contains<FakedComponentsInstaller>());//..Register other components that ApplicationService depend on

    一個對SearchService的測試如下:


    [Fact]public?async void?WhenInputDataIsValidShouldGetSearchResult(){????//Arrage????var?searchService = _container.Resolve<ISearchService>();????var?searchModel = SearchModelBuilder.Default().Build();????//Act????var?result = await searchService.Search(searchModel);????//Assert????result.Count.Should().BeGreaterThan(0);}

    原文地址https://www.cnblogs.com/xiandnc/p/9407856.html

    .NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com

    總結(jié)

    以上是生活随笔為你收集整理的Dependency injection in .NET Core的最佳实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。