客製化.NET 6.0的依賴注入

2022-06-08 12:02:05

大家好,我是張飛洪,感謝您的閱讀,我會不定期和你分享學習心得,希望我的文章能成為你成長路上的墊腳石,讓我們一起精進。

在本章中,我們將學習ASP.NET Core的依賴項注入(DI)以及如何自定義它。
我們將討論以下主題:

  • 使用不同的DI容器
  • 探索ConfigureServices方法
  • 使用其他的ServiceProvider
  • Scrutor簡介

技術準備

我們使用以下命令(你可以在console, shell,Bash終端),建立一個MVC應用:

dotnet new mvc -n DiSample -o DiSample

在Visual Studio中開啟專案,或在控制檯中鍵入以下命令,在Visual Studio Code中開啟專案:

cd DiSample
code .

使用不同的DI容器

在大多數專案中,我們其實不需要使用不同的DI容器。ASP.NET Core中的現有DI基本上滿足我們的需要。但是,你可能喜歡其他DI容器的其他功能:

  • 使用Ninject建立一個支援模組作為輕量級依賴項的應用程式。比如,您可能希望將模組放入特定目錄中,並在應用程式中自動註冊這些模組。
  • 在應用程式外部的組態檔中,比如,在XML或JSON檔案中,而不是僅在C#中設定服務。這是各種DI容器中的常見功能,但ASP.NET Core中尚不支援。
  • 在執行時新增服務,獲取動態的DI容器,這也是一些DI容器中的常見特性。

現在,讓我們看看ConfigureServices方法是如何操作的。

探索ConfigureServices方法

我們將當前的ConfigureServices方法與以前的長期支援版本(TLS)進行比較,看看有什麼變化。如果您使用版本3.1建立的ASP.NET Core專案,並開啟Startup.cs檔案,設定服務的方法如下所示:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {

         options.CheckConsentNeeded = context => true;
    });
    services.AddControllersWithViews();
    services.AddRazorPages();
}

相反,在 ASP.NET Core 6.0,沒有啟動Startup.cs,服務的設定在Startup.cs中進行,如下所示:

var builder = WebApplication.CreateBuilder(args); 
// Add services to the container. 
builder.Services.AddControllersWithViews(); 
var app = builder.Build(); 
// The rest of the file isn't relevant for this chapter

這兩種情況都可以獲得IServiceCollection,其中預設已經填充了ASP.NET Core所需的一組服務,比如宿主服務、ConfigureServices方法之前執行的相關服務。
以上方法中,新增了更多的服務。

  • 首先,將包含cookie策略選項的設定類新增到ServiceCollection
  • AddMvc()方法新增MVC框架所需的服務。
    到目前為止,我們有大約140個服務註冊到IServiceCollection
    但是,服務集合不是實際的DI容器,真實的DI容器被包裝在所謂的服務提供者中(ServiceProvider)。

那麼應該如何獲取DI容器呢?

IServiceCollection有了一個擴充套件方法,它用於從服務集合中建立IServiceProvider,程式碼如下:

IServiceProvider provider = services.BuildServiceProvider()

ServiceProvider包含不可變容器,即在執行時無法更改。在ConfigureServices方法執行後,會在後臺建立IServiceProvider
接下來,我們再看下如何在DI客製化過程中,替代IServiceProvider

使用其他IServiceProvider

如果其他容器已經支援ASP.NET Core,則更改為其他或自定義DI容器將變得非常容易。通常,第三方DI容器會使用IServiceCollection做為自己的容器,它通過迴圈集合將已註冊的服務移動到另一個容器。
我們用第三方容器Autofac舉個例子。在命令列中鍵入以下命令,載入NuGet包:

dotnet add package Autofac.Extensions.DependencyInjection

要註冊自定義IoC容器,通常需要註冊不同的IServiceProviderFactoryIServiceProviderFactory將建立一個ServiceProvider範例。如果第三方容器支援ASP.NET Core,則必須提供一個該工廠類。如果你要使用Autofac,則需要使用AutofacServiceProviderFactory

我們在Program.cs中給IHostBuilder編寫一個擴充套件方法,內部註冊一個AutofacServiceProviderFactory

using Autofac; 
using Autofac.Extensions.DependencyInjection; 
namespace DiSample; 

public static class IHostBuilderExtension {     
    public static IHostBuilder UseAutofacServiceProviderFactory(this IHostBuilder hostbuilder) 
     {         
        hostbuilder.UseServiceProviderFactory (new AutofacServiceProviderFactory());         
        return hostbuilder;     
    }
}

注意,不要忘記將引入名稱空間:AutofacAutofac.Extensions.DependencyInjection
要使用此擴充套件方法,可以在Program.cs中使用AutofacServiceProvider

var builder = WebApplication.CreateBuilder(args); 
builder.Host.UseAutofacServiceProviderFactory(); 
// Add services to the container. 
builder.Services.AddControllersWithViews();

以上通過擴充套件方法將AutofacServiceProviderFactory新增到IHostBuilder中,並啟用AutofacIoC容器。後續會轉而使用AutofacIServiceCollection新增服務。
再強調一下,除非必要。通常,我們不一定要替換現有的.NET CoreDI容器。

Scrutor簡介

在本章的開頭,我提到了服務的自動註冊,這裡可以通過其他DI容器完成。這裡介紹一個名為Scrutor的不錯的NuGet包來實現。
Scrutor通過向.NET Core DI容器向IServiceCollection新增一個擴充套件方法,用以自動註冊服務。

擴充套件閱讀
這裡介紹一篇關於Scrutor的非常詳細的部落格文章,建議您繼續閱讀這篇文章以瞭解更多資訊。

回顧

通過以上演示,我們將能夠使用任何.NET標準相容的DI容器替換現有容器。如果您選擇的容器不包括ServiceProvider,請自己實現一個IServiceProvider介面,並在其中使用DI容器。如果您選擇的容器沒有提供填充服務的方法,請自行建立自己的方法。迴圈已註冊的服務並將其新增到另一個容器中。
最後一步聽起來很簡單,實現起來比較費勁,因為需要將所有的IServiceCollection註冊轉換為其他容器的註冊,它的複雜性取決於其他DI容器的實現細節。
任何時候,我們都可以選擇使用任何與.NET標準相容的DI容器,替換ASP.NET Core中的許多預設實現。
在下一章我們將探討如何以不同的方式設定HTTPS,感謝您的閱讀。