溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

發(fā)布時(shí)間:2021-03-05 15:39:25 來(lái)源:億速云 閱讀:239 作者:TREX 欄目:開發(fā)技術(shù)

一.前言

這篇文章主要講解了“ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入”吧!

二.關(guān)于屬性注入

說(shuō)到屬性注入,我們就不得不提一下 DI(Dependency Injection),即依賴注入,用過(guò) ASP.NET Core 的同學(xué)相信對(duì)這個(gè)詞不會(huì)陌生。ASP.NET Core 自帶了一個(gè)IOC容器,且程序運(yùn)行也是基于這個(gè)容器建立起來(lái)的,在 Startup 里的 ConfigureServices 方法就是向容器注冊(cè)類型。最直白的講,我們?cè)?ASP.NET Core 中,想使用某個(gè)類型的時(shí)候可以不用自己去 new,可以由容器通過(guò)構(gòu)造方法來(lái)注入具體的實(shí)現(xiàn)類型,而我們一般在構(gòu)造方法上定義的依賴類型都是接口,而不是去依賴具體的實(shí)現(xiàn),這里就體現(xiàn)了 SOLID 原則中的依賴倒置原則(DIP)。這也是IOC(Inversion of Control),即控制反轉(zhuǎn),不直接依賴具體實(shí)現(xiàn),將依賴交給容器去控制。上述幾者是具有一定的關(guān)聯(lián)關(guān)系的,DIP 是一種軟件設(shè)計(jì)原則,IOC 是 DIP 的具體實(shí)現(xiàn)方式,DI 是 IOC 的一種實(shí)現(xiàn)方式。

在依賴注入時(shí),我們最常用的便是通過(guò)構(gòu)造方法注入,還有另一種方式那便是屬性注入。

關(guān)于屬性注入,如果在網(wǎng)上搜索,大部分內(nèi)容都是不推薦使用,或者說(shuō)慎重使用的,因?yàn)閷傩宰⑷霑?huì)造成類型的依賴關(guān)系隱藏,測(cè)試不友好等,我也同意這種說(shuō)法,屬性注入可以使用,但是要謹(jǐn)慎,不能盲目使用。我的原則:在封裝框架(搭架子)時(shí)可以使用,但不能大范圍使用,只有必須使用屬性注入來(lái)達(dá)到效果的地方才會(huì)使用,用來(lái)提高使用框架時(shí)的編碼效率,來(lái)達(dá)到一些便利,脫離框架層面,編寫業(yè)務(wù)代碼時(shí),不得使用。

在 ASP.NET Core 中,自帶的容器是不支持屬性注入的,但是可以通過(guò)替換容器,如:Autofac 等來(lái)實(shí)現(xiàn)。今天我分享的方法不是使用替換容器,而是通過(guò)幾行代碼來(lái)實(shí)現(xiàn)屬性注入的效果,我稱為“偽屬性注入”。

三.屬性注入解決的痛點(diǎn)

以下介紹的痛點(diǎn)是我在實(shí)際編碼過(guò)程中遇到的一些,如果還有其他的,歡迎在評(píng)論和我交流

我所遇到的痛點(diǎn),我歸納為三條:

1.減少常用的類型的重復(fù)注入代碼,使構(gòu)造方法看起來(lái)更為簡(jiǎn)潔,提高閱讀性。

2.減少或消除因構(gòu)造方法注入造成子類繼承后的 base 調(diào)用鏈。

3.并非是滿足第一條或第二條就需要使用屬性注入來(lái)解決,只有當(dāng)?shù)谝弧⒍l發(fā)生的情況到達(dá)一定的數(shù)量。

第一條:

以日志 ILogger<T> 為例,我們?cè)?Controller 或者 應(yīng)用服務(wù)層(Application Service)等編寫業(yè)務(wù)的地方可能會(huì)常用,那么我們可能會(huì)在大部分的 Controller 或者 Application Service 的構(gòu)造方法里寫一句注入,例:

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

這里只是以日志來(lái)舉例,我們還能遇到和日志這種相同的類型,每個(gè) Controller 等都要注入一堆這種共同的類型,代碼編寫起來(lái)也比較麻煩,如果多了以后還影響代碼閱讀。

有何解決辦法,那就是定義一個(gè)基類,然后通過(guò)屬性提供給子類,以 Controller 為例:

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

第二條:

在上面的Controller基類注入 ILogger,然后設(shè)置了 Logger 屬性,這樣子類就可以使用 Logger 屬性來(lái)使用日志。

這樣做每次都要調(diào)用 base 將依賴對(duì)象傳遞給基類,如果繼承關(guān)系有多層,將會(huì)造成更大的影響。

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

注意:本文演示只以日志來(lái)舉例,如果只有一個(gè)ILogger我覺得還可以忍受,實(shí)際情況中并非只有一個(gè),比如本地化等等。博主不提倡有上面演示情況的就用屬性注入,當(dāng)?shù)竭_(dá)一定數(shù)量才使用,比如在 Controller 或者應(yīng)用服務(wù)這種數(shù)量多的對(duì)象以及當(dāng)這些對(duì)象需要的共同的注入類型達(dá)到一定數(shù)量。

四. 偽屬性注入核心思想

依托于 ASP.NET Core 自帶的容器,在 Resolve Service 時(shí),為需要“屬性注入”的屬性進(jìn)行賦值,可以使用 自帶容器提供的 ImplementationFactory 來(lái)實(shí)現(xiàn)。

五. 為 Controller 實(shí)現(xiàn)偽屬性注入

Controller 的實(shí)現(xiàn)較為特殊,Controller 默認(rèn)是不會(huì)通過(guò)自帶容器來(lái) Resolve&Activate 的,是通過(guò)MVC自身管理的,但是微軟提供了這樣的方法:

services.AddControllers().AddControllersAsServices();

可以通過(guò)調(diào)用 AddControllersAsServices() 方法來(lái)讓 Controller 使用自帶容器,其主要源代碼如下

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

根據(jù)第四小節(jié)的思想,我們需要 Controller Resolve 時(shí),來(lái)對(duì)屬性進(jìn)行賦值,那么我們需要改造 Controller 激活器。

定義 Controller 基類

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

Controller 繼承基類

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

改造 Controller 激活器

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

可以看到我們改造的代碼也就幾行。

替換默認(rèn) Controller 激活器

services.AddControllers().AddControllersAsServices();
services.Replace(ServiceDescriptor.Transient<IControllerActivator, XcServiceBasedControllerActivator>()); 
//替換默認(rèn) Controller 激活器

運(yùn)行測(cè)試

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

測(cè)試正常,如需其他屬性的“屬性注入”,參考日志這樣做就行了。

六. 為 Application Service 實(shí)現(xiàn)偽屬性注入

只是以 Application Service 來(lái)作為講解,同理可舉一反三到其他地方。Application Service 屬于領(lǐng)域驅(qū)動(dòng)分層架構(gòu)中的一層,如不了解,可自行查找資料。

定義應(yīng)用服務(wù)基類接口

public interface IAppService
{
  ILogger Logger { get; set; }
}

public class AppService:IAppService
{
  public ILogger Logger { get; set; }
}

定義具體服務(wù),以 User 服務(wù)為例

public interface IUserAppService:IAppService
{
  void Create();
}

public class UserAppService : AppService,IUserAppService
{
  public void Create()
  {
    Logger.LogInformation("來(lái)自 Application Service 的日志");
  }
}

定義特殊的注冊(cè)服務(wù)的方法,以便實(shí)現(xiàn) Resolve 為 Logger 賦值

public static class ServiceExtensions
{
  public static IServiceCollection AddApplicationService<TService, TImpl>(this IServiceCollection services) where TService:IAppService where TImpl:AppService
  {
    services.AddApplicationService(typeof(TService), typeof(TImpl));
    return services;
  }
  // 可以反射程序集調(diào)用此方法實(shí)現(xiàn)批量自動(dòng)注冊(cè)應(yīng)用服務(wù)
  public static IServiceCollection AddApplicationService(this IServiceCollection services, Type serviceType,Type implType)
  {
    services.AddTransient(serviceType, sp =>
    {
      //獲取服務(wù)實(shí)現(xiàn)的實(shí)例
      var implInstance = ActivatorUtilities.CreateInstance(sp, implType); ;

      if (implInstance is AppService obj)
      {
        //為 Logger 賦值
        obj.Logger= sp.GetRequiredService<ILoggerFactory>().CreateLogger(implType);
      }
      
      return implInstance;
    });
    return services;
  }

注冊(cè)測(cè)試服務(wù)

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

Controller 注入測(cè)試服務(wù)

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

運(yùn)行測(cè)試

ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入

七.結(jié)束

其實(shí)到本文寫完,我都在想,要不要封裝一個(gè)組件,發(fā)布到 Nuget 來(lái)方便的使用文中我所描述的“偽屬性注入”,最后反復(fù)想了想,還是覺得不做。如果要使用完全的屬性注入可以替換使用第三方容器,本文所述旨在不想引入第三方容器,且想在部分地方來(lái)達(dá)到屬性注入的效果,因?yàn)閷傩宰⑷脒@個(gè)東西也不推薦大范圍使用。

感謝各位的閱讀,以上就是“ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)ASP.NET Core 怎么實(shí)現(xiàn)偽屬性注入這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI