1. 程式人生 > 實用技巧 >HostingStartupAttribute託管啟動程式集.md

HostingStartupAttribute託管啟動程式集.md

HostingStartupAttribute託管啟動程式集

IHostingstartup實現在應用程式啟動時從外部程式集中新增功能到應用程式中。

HostingStartup屬性

HostingStartup屬性指示存在要在執行時啟用的託管啟動程式集。

自動掃描條目程式集或包含Startup類的程式集以查詢HostingStartup屬性。在執行時從WebHostDefaults.HostingStartupAssembliesKey中的配置載入用於查詢HostingStartup屬性的程式集列表。在WebHostDefaults.HostingStartupExcludeAssembliesKey

中載入用於排除的程式集列表。

在下面示例中,託管啟動程式集名稱空間為StartupEnhancement,託管啟動程式碼類為StartupEnhancementHostingStartup:

[assembly:Hostingstartup(typeof(StartupEnhancement.StartupEnhancementHostingStartup))]

HostingStartup屬性通常位於託管啟動程式集的IHostingStartup實現類檔案中。

發現已載入的託管啟動程式集

要發現載入的託管啟動程式集,請啟用日誌記錄並檢查應用程式的日誌。當載入程式集時出現錯誤,異常會被記錄,已載入的託管啟動程式集會在Debug級別被記錄,並會記錄所有異常。

禁用自定載入託管啟動程式集

使用以下任何一種方法都可以禁用自動載入託管啟動程式集:

  • 阻止所有託管啟動程式集載入,請設定以下任何一個為ture1
    • 阻止託管啟動主機配置設定:

          public static IHostBuilder CreateHostBuilder(string[] args)=>{
              Host
              .CreatedefaultBuilder(args)
              .ConfigureWebHostDefaults(webBuilder=>{
                  webBuilder
                  .Usesetting(WebHostDefaults.PreventHostingStartupKey,"true"
      ) .UseStartup<Startup>(); }); }
    • ASPNETCORE_PREVENTHOSTINGSTARTUP環境變數

  • 阻止指定的託管啟動程式集載入,以下任何一個設定為已分號分割的託管啟動程式集,以阻止啟動:
    • 主機配置阻止特定的託管啟動程式集

          public static IhostBuilder createHostBuilder(string[] args)=>{
              Host
              .CreateDefaultBuilder(args)
              .ConfigureWebHostDefaults(webBuilder=>{
                  webBuilder
                  .UseSetting(
                      WebHostDefaults.HostingStartupExcludeAssembliesKey,"{ASSEMBLY1;ASSEMBLY2;...}"
                  )
              });
          }
      • ASPNETCORE_HOSTINGSTARTUPEXCLUDEASSEMBLIES環境變數

如果在主機配置中和環境變數中都設定了,則主機設定控制載入行為。

使用主機設定或環境變數禁用託管啟動程式集將全域性禁用該程式集,並可能禁用應用程式的一些特性。

類庫

託管啟動增強可以在類庫中提供,庫包含一個HostingStartup屬性。

示例程式碼包含一個Razor頁面應用HostingStartupApp 和一個類庫HostingStartupLibrary。類庫:

  • 包含一個實現了IHostingStartup介面的託管啟動類ServiceKeyInjectionServiceKeyInjection使用記憶體配置提供程式(AddInMemoryCollection)新增一對服務字串到應用程式的配置中。
  • 包含一個HostingStartup屬性,它定義了託管啟動的名稱空間和類。

ServiceKeyInjection類的Configure方法使用IWebHostBuilder新增增強功能到應用程式中。

HostingStartupLibrary/ServiceKeyInjection.css:

[assembly:HostingStartup(typeof(HostingStartupLibrary.ServiceKeyInjection))]

namespace HostingStartupLibrary{
    public class ServiceKeyInjection:IHostingStartup{
        public void Configure(IWebHostBuilder builder){
            builder
            .ConfigureAppConfiguration(config=>{
                var dict = new Dictionary<string,string>{
                    {"DevAccount_FromLibrary","Dev_1111111-1111"},
                    {"ProdAcction_FromLibrary","PROD_2222222-2222"}
                };
                config.AddInMemoryCollection(dict);
            });
        }
    }
}

示例程式碼也包含了一個NuGet專案,它提供了另一個託管啟動HostingStartupPackage。這個包具有與前面描述的類庫相同的特徵:

  • 包含一個實現了IHostingStartup介面的託管啟動類ServiceKeyInjectionServiceKeyInjection新增一對服務字串到應用程式配置中。
  • 包含HostingStartup屬性

HostingStartupPackage/ServiceKeyInjeciton.cs

[assembly:HOstingStartup(typeof(HostingStartupPackage.ServiceKeyInjection))]

namespace HostingStartupPackage{
    public class ServiceKeyInjection:IHostingStartup{
        public void Configure(IWebHostBuilder builder){
            builder
            .ConfigureAppConfiguration(config=>{
                var dict = new Dictionary<string,string>{
                    {"DeveAccount_FromPackage","DEV_3333333-3333"},
                    {"ProdAccount_FromPackage","PROD_4444444-4444"}
                };

                config.AddInMemoryCollection(dict);
            });
        }
    }
}

應用程式的Index頁面讀取並呈現類庫託管啟動程式集設定的四個鍵的配置值:

HostingStartupApp/Pages/Index.cshtml.cs:

public class IndexModel:PageModel{
    public IndexModel(IConfiguration config){
        ServiceKey_Development_Library = config["DevAccount_FromLibrary"];
        ServiceKey_Production_Library=config["ProdAcction_FromLibrary"];
        ServiceKey_Development_Package = config["DevAccount_FromPackage"];
        ServiceKey_Production_Package = config["ProdAccount_FromPackage"];
    }

    public string ServiceKey_Development_Library{get;private set;}
    public string ServiceKey_Production_Library{get;private set;}
    public string ServiceKey_Development_Package { get; private set; }
    public string ServiceKey_Production_Package { get; private set; }

    public void OnGet(){

    }
}

沒有入口點的控制檯應用程式

這種方式僅僅適用於 .NET Core 應用程式,不適用於 .NET Framework。

動態託管啟動增強不需要編譯時引用啟用提供給不包含入口點的控制程式,它包含一個HostingStartup屬性。釋出控制檯應用程式將生成一個可以從執行時儲存區使用的託管啟動程式集。

一個沒有入口點的控制檯應用程在這個過程中序使用:

  • 在託管啟動程式集中使用託管啟動需要一個依賴檔案。依賴檔案是可執行的應用程式資產,它是通過釋出應用程式而產生的,而不是庫。
  • 庫不能直接新增到執行時包儲存中,這需要一個以共享執行時為目標的可執行專案。

在建立一個動態託管啟動:

  • 託管啟動程式集是從沒有入口點的控制檯應用程式建立的:
    • 包含一個實現了IHostingStartup介面的類
    • 包含一個HostingStartup屬性去定義IHostingStartup實現型別。
  • 控制檯程式是已釋出的,以獲得託管啟動的依賴項。釋出控制檯應用程式的一個後果是從依賴項檔案中刪除未使用的依賴項。
  • 依賴項檔案被修改為設定宿主啟動程式集的執行時位置。
  • 託管啟動程式集合依賴項檔案被放置在執行時包儲存中(runtime package store)。要發現宿主啟動程式集及其依賴項檔案,將它們列在一對環境變數中。

控制檯程式引用Microsoft.AspNetCore.Hosting.Abstractions包:

<Project Sdk="Microsoft.NET.Sdk">

    <ProjectGroup>
        <TargetFromework>netcoreapp3.0</TargetFromework>
    </ProjectGroup>

    <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.Hosting.Abstractions" Version="3.0.0">
    </ItemGroup>
</Project>

HostingStartup屬性將一個類標識為IHostingStartup的實現,以便在構建IWebHost時載入和執行。在如下面示例,名稱空間為StartupEnhancement,類為StartupEnhancementHostingStartup

[assembly:HostingStartup(typeof(StartupEnhancement.StartupEnhancementHostingStartup))]

一個實現IHostingStartup的類的Configure方法使用IWebHostBuilder新增增強功能到應用程式。執行時在使用者程式碼Startup.Configure之前呼叫託管啟動程式集中的IHostingStartup.Configure,這允許使用者程式碼覆蓋由託管啟動程式集中提供的任何配置。

namespace StartupEnhancement{
    public class StartupEnhancementHostingStartup:IHostingStartup{
        public void Configure(IWebHostBuilder builder){
            // 使用IWebHostBuilder新增應用程式增強功能
        }
    }
}

當構建一個IHostingStartup專案,開發檔案(.deps.json)將程式集的執行時位置設定為bin資料夾:

"targets":{
    ".NETCoreApp,Vresion=v3.0":{
        "StartupEnchancement/1.0.0":{
            "dependencies":{
                "Microsoft.AspNetcore.Hosting.Abstractions":"3.0.0"
            },
            "runtime":{
                "StartupEnhancement.dll":{}
            }
        }
    }
}

只顯示了檔案的一部分。示例中的程式集名稱為StartupEnhancement。

提供託管啟動配置

有兩中方法處理配置依賴,取決於你是想託管啟動的配置優先還是應用程式的配置優先:

  1. 提供配置到應用程式,使用ConfigureAppConfiguration載入配置在應用程式的ConfigureAppConfiguration委託後執行,使用這種方法,託管啟動配置優先於應用程式的配置。
  2. 提供配置到應用程式,使用UseConfiguration載入配置在應用程式的ConfigureAppConfiguration委託前執行,使用這種方法,應用程式的配置優先於託管啟動配置。
public class ConfigurationInjection:IHostingStartup
{
    public void Configure(IWebHostBuilder builder){
        Dictionary<string,string> dict;

        builder.ConfigureAppConfiguration(config=>{
            dict = new Dictionary<string,string>{
                {"ConfigurationKey1","From IHostingStartup:比應用程式的配置優先順序更高"}
            };

            config.AddInMemoryCollection(dict);
        });

        dict = new Dictionary<string,string>{
            {"ConfigurationKey2","From IHostingStartup:應用程式的配置的優先順序更高"}
        };

        var builtConfig = new ConfigurationBuilder()
        .AddInMemoryCollection(dict)
        .Build();

        builder.UseConfiguration(builtConfig);
    }
}

指定託管啟動程式集

無論是類庫還是控制檯提供託管啟動,都要在環境變數ASPNETCORE_HOSTINGSTARTUPASSEMBLIES中指定託管啟動程式集名。環境變數是一個用分號分隔的程式集列表。

只有擁有HostingStartup屬性的託管啟動程式集才能被掃描。
如示例應用程式,HostingStartupApp,為了發現前面描述的託管啟動,環境變數被設定為以下值:

HostingStartupLibrary;HostingStartupPackage;StartupDiagnostics

一個託管啟動程式集也能設定使用託管啟動程式集主機配置設定:

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

當有多個託管啟動程式集時,Configure方法按列出程式集的順序執行。

啟用

託管啟動啟用屬性有:

  • Runtime store:啟用不需要編譯時引用來啟用。示例應用程式的託管啟動程式集合和依賴檔案放在deployment資料夾中,以促進託管啟動部署到多級環境中。deployment資料夾還包含一個PowerShell指令碼,該指令碼在部署系統上建立或修改環境變數,以啟用託管啟動。
  • 啟用需要編譯時引用

Runtime store

託管啟動實現被放在runtime store中。增強的應用程式不需要程式集的編譯時引用。

在託管啟動構造之後,將使用manifest專案檔案和dotnet store命令生成一個runtime store。

 dotnet store --manifest {MANIFEST FILE} --runtime {FUNTIME IDENTIFIER} --output {OUT PUT LOCATION} --skip-optimization

在示例應用程式(RuntimeStore project)中,使用下面的命令:

dotnet store --manifest store.manifest.csproj --runtime win7-x64 --output ./deployment/store --skip-optimization

要讓執行時發現runtime store,要在DOTNET_SHARED_STORE環境變數中新增runtime store的位置。

修改並放置託管啟動程式的依賴項檔案

要在沒有包引用的情況下啟用增強,使用additionalDeps指定對執行時的其他依賴項。

additionalDeps允許你:

  • 通過提供一組額外的.deps.json檔案來擴充套件應用程式的庫圖,以便在啟動時與應用程式自己的.deps.json檔案合併。
  • 使託管啟動程式集可被發現和載入。

產生額外的依賴檔案推薦的方法是:

  1. 對上一節引用的runtime store manifest檔案執行dotnet publish
  2. 從庫和生成的 .deps.json 檔案的runtime部分中刪除manifest引用。

在示例專案中,store.manifest/1.0.0屬性從targetlibraries部分中刪除:

{
  "runtimeTarget": {
    "name": ".NETCoreApp,Version=v3.0",
    "signature": ""
  },
  "compilationOptions": {},
  "targets": {
    ".NETCoreApp,Version=v3.0": {
      "store.manifest/1.0.0": {
        "dependencies": {
          "StartupDiagnostics": "1.0.0"
        },
        "runtime": {
          "store.manifest.dll": {}
        }
      },
      "StartupDiagnostics/1.0.0": {
        "runtime": {
          "lib/netcoreapp3.0/StartupDiagnostics.dll": {
            "assemblyVersion": "1.0.0.0",
            "fileVersion": "1.0.0.0"
          }
        }
      }
    }
  },
  "libraries": {
    "store.manifest/1.0.0": {
      "type": "project",
      "serviceable": false,
      "sha512": ""
    },
    "StartupDiagnostics/1.0.0": {
      "type": "package",
      "serviceable": true,
      "sha512": "sha512-xrhzuNSyM5/f4ZswhooJ9dmIYLP64wMnqUJSyTKVDKDVj5T+qtzypl8JmM/aFJLLpYrf0FYpVWvGujd7/FfMEw==",
      "path": "startupdiagnostics/1.0.0",
      "hashPath": "startupdiagnostics.1.0.0.nupkg.sha512"
    }
  }
}

.deps.json 檔案放到以下位置:

{ADDITIONAL DEPENDENCIES PATH}/shared/{SHARED FRAMEWORK NAME}/{SHARED FRAMEWORK VERSION}/{ENHANCEMENT ASSEMBLY NAME}.deps.json
  • {ADDITIONAL DEPENDENCIES PATH}: 位置新增到DOTNET_ADDITIONAL_DEPS環境變數。
  • {SHARED FRAMEWORK NAME}:此附加依賴項檔案需要共享框架。
  • {SHARED FRAMEWORK VERSION}: 最想共享框架版本
  • {ENHANCEMENT ASSEMBLY NAME}:增強的程式集名稱。

在示例應用程式( RuntimeStore 專案)中,附加依賴檔案放置在下面的位置:

deployment/additionalDeps/shared/Microsoft.AspNetCore.App/3.0.0/StartupDiagnostics.deps.json

為了允許時發現runtime store位置,附件引用檔案位置必須新增到DOTNET_ADDITIONAL_DEPS環境變數中。

在示例應用程式(RuntimeStore 專案)中,使用PowerShell指令碼完成構建runtime store和產生附加引用檔案。

如何在各個系統中設定環境變數,請見Use Multiple environments

部署

為了促進託管啟動部署到個環境,示例應用程式在published輸出中建立了一個 deployment 資料夾,資料夾包含:

  • 託管啟動runtime store。
  • 託管啟動引用檔案
  • 一個PowerShell指令碼,在部署系統上從管理員PowerShell命令提示中執行指令碼,以建立或修改ASPNETCORE_HOSTINGSTARTUPASSEMBLIES, DOTNET_SHARED_STORE和DOTNET_ADDITIONAL_DEPS以支援啟用託管啟動。

NuGet包

可以在NuGet包中提供一個託管啟動增強。包中有一個HostingStartup屬性。包提供的託管啟動型別可以使App使用以下任何一種方式:

  • 增強的應用程式的專案檔案在應用程式的專案檔案中為託管啟動建立了一個包引用(一個編譯時引用)。 有了編譯時引用,承載啟動程式集及其所有依賴項都會合併到應用的依賴項檔案 (.deps.json) 中。 此方法適用於已釋出到 nuget.org 的承載啟動程式集包。
  • 託管啟動的依賴檔案可以提供給增強型App,就像在Runtime store章節(沒有編譯時引用)描述的一樣。

更多有關NuGet包和runtimestore的資訊,請見以下文章:

專案bin資料夾

一個託管啟動增強可以由增強的應用程式中的bin部署的程式集提供。由程式集提供的託管啟動型別使用以下方法之一提供給應用程式:

  • 增強應用程式專案檔案為託管啟動進行了程式集引用(一個編譯時引用)。託管啟動程式集及其所有依賴項都會合併到應用的依賴項檔案 (.deps.json) 中。當部署方案要求對託管啟動程式集(.dll 檔案)進行編譯時引用並將程式集移動到以下任一位置時,此方法適用:
    • 進行中的專案
    • 進行中的專案可訪問的位置
  • 託管啟動程式的依賴項檔案對增強的應用程式可用,如Runtime store中所述(沒有編譯時引用)。
  • 當以.NET Framework為目標時,程式集可以在預設的載入上下文中載入,這在.NET Framework中意味著程式集位於以下任意一個位置:

示例程式碼

示例程式碼演示了託管啟動實現方案:

  • 兩個託管啟動程式集(類庫)分別設定一對記憶體中的配置鍵值對:
    • NuGet包(HostingStartupPackage)
    • 類庫(HostingStartupLibrary)
  • 從執行時儲存部署程式集啟用託管啟動(StartupDiagnostics)。程式集在應用程式的Startup中新增兩個中介軟體,以提供一下診斷資訊:
    • 已註冊的服務
    • 地址(scheme,host,path base,path query string)
    • 連線(remote IP,remote port,local IP,local port,client certificate)
    • 請求頭
    • 環境變數

執行示例:

從NuGet包啟用

  1. 使用dotnet pack命令編譯 HostingStartupPackage包。

  2. 將包的程式集名稱 HostingStartupPackage新增到環境變數ASPNETCORE_HOSTINGSTARTUPASSEMBLIES中。

  3. 編譯和執行應用程式。 增強型應用中存在包引用(編譯時引用)。 應用專案檔案中的 <PropertyGroup> 指定包專案的輸出 (../HostingStartupPackage/bin/Debug) 作為包源。 這允許應用使用該包而無需將包上傳到 nuget.org。有關詳細資訊,請參閱 HostingStartupApp 專案檔案中的說明。

    <PropertyGroup>
        <RestoreSources>$(RestoreSources);https://api.nuget.org/v3/index.json;../HostingStartupPackage/bin/Debug</RestoreSources>
    </PropertyGroup>
  4. 觀察由Index頁呈現的服務配置鍵值是否與包的ServiceKeyInjection.Configure設定的值相匹配。

如果更改了HostingStartupPackage專案並重新編譯它,清理本地NuGet包快取,以確保HostingStartupApp接受到更改後的包而不是本地快取的舊包。執行以下dotnet nuget locals清理本地NuGet快取:

dotnet nuget locals all --clear

注意

設定環境變數後一定要重啟電腦,否則設定的環境變數可能不生效

  1. 託管啟動類必須繼承IHostingStartup

  2. 程式集中必須包含HostingStartup屬性,該屬性標記託管啟動的類

  3. 使用dotnet pack命令打包程式集

  4. 在使用應用中,在專案檔案中設定包的引用,配置如下

    <!-- 指定程式所需的引用 -->
    <ItemGroup>
      <PackageReference Include="HostingStartupPackage" Version="1.0.0" />
    </ItemGroup>
    <!-- 指定的包位置 -->
    <PropertyGroup>
      <RestoreSources>..\MyPacks;$(RestoreSources);https://api.nuget.org/v3/index.json;</RestoreSources>
    </PropertyGroup>

從類庫中啟用

  1. 使用dotnet build命令編譯HostingStartupLibrary類庫

  2. 新增類庫程式集的名稱HostingStartupLibrary到ASPNETCORE_HOSTINGSTARTUPASSEMBLIES環境變數。

  3. 通過將HostingStartupLibrary.dll檔案從類庫的編譯輸出複製到應用程式的bin/Debug資料夾,將類庫的程式集部署到應用程式中。

  4. 編譯並執行應用程式。應用程式專案檔案中的<ItemGroup>引用類庫的程式集(.\bin\Debug\netcoreapp3.0\HostingStartupLibrary.dll) (編譯時引用)。請參閱HostingStartupApp專案檔案中的註釋。

    <ItemGroup>
      <Reference Include=".\bin\Debug\netcoreapp3.0\HostingStartupLibrary.dll">
        <HintPath>.\bin\Debug\netcoreapp3.0\HostingStartupLibrary.dll</HintPath>
        <SpecificVersion>False</SpecificVersion>
      </Reference>
    </ItemGroup>
  5. 觀察由Index頁呈現的服務配置鍵值是否與包的ServiceKeyInjection.Configure設定的值相匹配。

注意

設定環境變數後一定要重啟電腦,否則設定的環境變數可能不生效

  1. 託管啟動類必須繼承IHostingStartup
  2. 程式集中必須包含HostingStartup屬性,該屬性標記託管啟動的類
  3. 使用dotnet build命令編譯程式集
  4. 在使用應用中,在專案檔案中設定包的引用

從執行時儲存部署啟用程式集

  1. StartupDiagnostics專案使用PowerShell修改它的StartupDiagnostics.json檔案。PowerShell已在Windows Starting、Windows 7 SP1和Windows Server 2008R2 SP1上預設安裝。其他平臺上獲得PowerShell,請見安裝各種版本的PowerShell
  2. RuntimeStore資料夾中擴充套件build.sp1指令碼:
    • obj\packages資料夾中產生startupDiagnostics
    • 在Store中產生startupDiagnostics的runtime store。該指令碼中的dotnet store 命令使用 win7-x64 執行時識別符號 (RID) 將託管啟動部署到 Windows。當為不同的執行時提供託管啟動時,用正確的RID替代指令碼中的37行。StartupDiagnostics的runtime store稍後會移動到將使用程式集的計算機上的使用者的runtime store中或系統的runtime store中。StartupDiagnostics程式集的使用者runtime store安裝在 .dotnet/store/x64/netcoreapp3.0/startupdiagnostics/1.0.0/lib/netcoreapp3.0/StartupDiagnostics.dll.
    • additionalDeps資料夾中產生StartupDiagnosticsadditionalDeps。附加依賴稍後會移動到使用者或系統的附加依賴中。使用者StartupDiagnostics附加依賴安裝在*.dotnet/x64/additionalDeps/StartupDiagnostics/shared/Microsoft.NETCore.App/3.0.0/StartupDiagnostics.deps.json*。
    • deploy.ps1 檔案放置在 deployment 資料夾中。
  3. deployment資料夾執行deploy.ps1指令碼。指令碼附加:
    • StartupDiagnostics追加到ASPNETCORE_HOSTINGSTARTUPASSEMBLIES環境變數
    • 託管啟動依賴路徑(在RuntimeStore專案的deployment資料夾中)追加到DOTNET_ADDITIONAL_DEPS環境變數
  4. 執行示例應用程式
  5. 請求/services終端,檢視應用程式註冊的服務。請求/diag終端,檢視診斷資訊。