ASP.NET Core - IStartupFilter 與 IHostingStartup

啊晚發表於2023-02-12

1. IStartupFilter

  上面講到的方式雖然能夠根據不同環境將Startup中的啟動邏輯進行分離,但是有些時候我們還會可以根據應用中的功能點將將一系列相關中介軟體的註冊封裝到一起,從 Startup 類中分離,單獨進行維護,以便更清晰地管理我們的程式碼。

  這時候我們可以實現 IStartupFilter 介面,然後將其注入到容器之中,在應用啟動的時候 IStartupFilter 實現類會被執行,從而完成對中介軟體的配置。

  在 IStartupFilter 中配置的中介軟體,總是比 Startup 類中 Configure 方法中的中介軟體先註冊;對於多個 IStartupFilter 實現,執行順序與服務註冊時的順序相反

  透過原始碼可以看到,ASP.NET Core 框架在建立應用的時候,會從容器中提取出所有的 IStartupFilter 的實現類,迴圈執行,然後再執行 Startup 類中的 Configure 方法。

image

下面是一個測試例子 :

點選檢視程式碼
public class FirstStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        Console.WriteLine("FirstStartupFilter");
        return app => next(app);
    }
}

public class SecondStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        Console.WriteLine("SecondStartupFilter");
        return app => next(app);
    }
}

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        Console.WriteLine("Startup: ConfigureServices");
        services.AddTransient<IStartupFilter, FirstStartupFilter>();
        services.AddTransient<IStartupFilter, SecondStartupFilter>();
        services.AddControllers();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        Console.WriteLine("Startup.Configure");
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        app.UseRouting
        app.UseAuthorization
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

執行結果如下:
image

2 IHostingStartup

  第一次接觸 IHostingStartup 的應用是在 Skywalking 的使用之中,當初覺得 Skywalking 僅僅透過配置一個環境變數就能整合相關的功能非常神奇,並不知道具體是怎麼實現的。後面出於這點好奇心,瞭解了一下相關的原理,才知道原來是使用了 IHostingStartup 在啟動時透過外部程式集嚮應用增加更多功能,它是 ASP.NETCore 框架原生提供的一種進行模組化開發的方式,使用它必須透過 Web 主機呼叫 ConfigureWebHost、ConfigureWebHostDefaults
配置方法。

透過原始碼可以看到,在呼叫 Build 方法構建主機的時候會獲取外部程式集名稱,然後將其載入,再透過HostingStartupAttribute 程式集特性找到配置的 HostingStartType,該類需要實現 IHostingStartup 解析,之後反射生成例項,呼叫其中的 Configure 方法,傳入的時候 IWebHostBuider 物件,因此在 IHostingStartup 實現類中一樣可以進行依賴注入、管道配置。

image

image

再看怎麼獲取外部程式集名稱的:
image

image

可以看到是從配置系統中獲取的,而 key 是 WebHostDefaults.HostingStartupAssembliesKey 常量,也就是 hostingStartupAssemblies,由於這裡是 主機配置,所以我們可以透過 ASPNETCORE_HOSTINGSTARTUPASSEMBLIES 進行設定,Web 主機在載入環境變數的時候會截去字首 ASPNETCORE_ ,配置系統中 key 不區分大小寫。

image

下面看看如何使用 IHostingStartup:

2.5.1 建立外部程式集

首先我們建立 HostingStartup 程式集,可以透過建立類庫專案或無入口點的控制檯應用來實現。

image
之後建立一個 IHostingStartup 介面的實現類

[assembly: HostingStartup(typeof(MyHostingStartup))]
namespace HostingStartupLib
{
    public class MyHostingStartup : IHostingStartup
    {
      public void Configure(IWebHostBuilder builder)
        {
            builder.ConfigureServices(services => { })
                .ConfigureAppConfiguration(app => { });
            Console.WriteLine("Init External Amsebly!");
        }
    }
}

該類的 Configure 方法中入參為 IWebHostBuilder ,透過 IWebHostBuilder 來新增增強功能,像 Program.cs 檔案中對主機進行配置一樣。

之後,需要配置 HostingStartup 特性,這是一個程式集特性,指定當前程式集的 IHostingStartup 實現類型別。

2.5.2 啟用外部程式集

有了一個這樣的 HostingStartup 外部程式集之後,我們在主體應用專案中可以這樣進行啟用。

首先,將該程式集應用進專案之中
image

然後,向配置系統中設定外部程式集的名稱,以實現在構建主機的時候進行載入,由於是主機配置,所以我們可以透過幾種方式進行設定:

(1) 在構建主機的時候進行配置

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseSetting(
                WebHostDefaults.HostingStartupAssembliesKey,
                "HostingStartupLib")
            .UseStartup<Startup>();
        });

其實這裡的 UseSetting 方法就是就是往配置系統中新增配置而已

image

(2) 透過環境變數進行設定

Web主機在啟動的時候會透過環境變數提供程式獲取環境變數作為主機配置,並且會在寫入配置系統的時候會擷取掉 ASPNET_ 字首,我們在配置的時候要用 ASPNETCORE_HOSTINGSTARTUPASSEMBLIES 作為 key。這種無需侵入程式程式碼,是更為推薦的方式。

我們可以直接在機器的環境變數列表中配置,但是如果只是開發環境的話也可以透過 launchSettings.json 。

image

無論是那種配置方式,如果需要同時可以用英文逗號 ; 分隔。除了 ASPNETCORE_HOSTINGSTARTUPASSEMBLIES 環境變數之外,和外部程式集有關的配置還有 ASPNETCORE_HOSTINGSTARTUPEXCLUDEASSEMBLIES,用於排除要啟用的程式集,ASPNETCORE_PREVENTHOSTINGSTARTUP,用於配置是否禁止外部程式集。



參考文章:

官方文件-託管啟動程式集
理解ASP.NET Core - Startup



ASP.NET Core 系列總結:

目錄:ASP.NET Core 系列總結
上一篇:ASP.NET Core—入口檔案

相關文章