Verwenden von Hostingstartassemblys in ASP.NET Core

Von Pavel Krymets

Mit einer IHostingStartup-Implementierung (Hostingstart) werden Verbesserungen an einer App beim Start von einer externen Assembly aus vorgenommen. Eine externe Bibliothek kann beispielsweise eine Hostingstartimplementierung verwenden, um zusätzliche Konfigurationsanbieter oder -dienste für eine App bereitzustellen.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Das Attribut HostingStartup

Ein HostingStartup-Attribut gibt an, ob eine Hostingstartassembly vorhanden ist, die zur Laufzeit aktiviert werden kann.

Bei der Einstiegsassembly oder bei der Assembly, die die Klasse Startup enthält, wird automatisch geprüft, ob sie das Attribut HostingStartup enthält. Die Liste der Assemblys für die Suche nach HostingStartup-Attributen wird zur Laufzeit aus der Konfiguration in WebHostDefaults.HostingStartupAssembliesKey geladen. Die Liste der Assemblys, die aus der Ermittlung ausgeschlossen werden sollen, wird aus WebHostDefaults.HostingStartupExcludeAssembliesKey geladen.

Im folgenden Beispiel lautet der Namespace der Hostingstartassembly StartupEnhancement. StartupEnhancementHostingStartup ist die Klasse mit dem Hostingstartcode:

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

Das Attribut HostingStartup befindet sich in der Regel in der IHostingStartup-Implementierungsklassendatei der Hostingstartassembly.

Ermitteln geladener Hostingstartassemblys

Zum Ermitteln von geladenen Hostingstartassemblys aktivieren Sie die Protokollierung und überprüfen die Protokolle der App. Fehler, die beim Laden von Assemblys auftreten, werden protokolliert. Geladene Hostingstartassemblys werden auf der Debugebene protokolliert. Außerdem werden alle Fehler protokolliert.

Deaktivieren des automatischen Ladens von Hostingstartassemblys

Um das automatische Laden von Hostingstartassemblys zu deaktivieren, verwenden Sie einen der folgenden Ansätze:

  • Um zu verhindern, dass alle Hostingstartassemblys geladen werden, legen Sie eine der folgenden Einstellungen auf true oder 1 fest:

    • Hostkonfigurationseinstellung „Verhindern des Hostingstarts“:

      public static IHostBuilder CreateHostBuilder(string[] args) =>
          Host.CreateDefaultBuilder(args)
              .ConfigureWebHostDefaults(webBuilder =>
              {
                  webBuilder.UseSetting(
                          WebHostDefaults.PreventHostingStartupKey, "true")
                      .UseStartup<Startup>();
              });
      
    • Die Umgebungsvariable ASPNETCORE_PREVENTHOSTINGSTARTUP

  • Um zu verhindern, dass bestimmte Hostingstartassemblys geladen werden, legen Sie eine der folgenden Einstellungen auf eine durch Semikolons getrennte Zeichenfolge mit Hostingstartassemblys fest, die beim Starten ausgeschlossen werden sollen:

    • Hostkonfigurationseinstellung „Hostingstartausschlussassemblys“:

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

      Der Platzhalter {ASSEMBLY1;ASSEMBLY2; ...} stellt die durch Semikolons getrennte Assemblyliste dar.

    • Die Umgebungsvariable ASPNETCORE_HOSTINGSTARTUPEXCLUDEASSEMBLIES

Wenn sowohl die Konfigurationseinstellung für den Host als auch die Umgebungsvariable festgelegt werden, wird das Verhalten durch die Hosteinstellung gesteuert.

Durch das Deaktivieren von Hostingstartassemblys mithilfe der Hosteinstellung oder der Umgebungsvariable wird die Assembly global deaktiviert. Einige Eigenschaften einer App können ebenfalls deaktiviert werden.

Projekt

Erstellen Sie einen Hostingstart mit einem der folgenden Projekttypen:

Klassenbibliothek

In einer Klassenbibliothek kann eine Hostingstarterweiterung bereitgestellt werden. Die Bibliothek enthält ein HostingStartup-Attribut.

Der Beispielcode enthält die Razor Pages-App HostingStartupApp und die Klassenbibliothek HostingStartupLibrary. Die Klassenbibliothek:

  • Enthält die Hostingstartklasse ServiceKeyInjection, die IHostingStartup implementiert. ServiceKeyInjection fügt mithilfe des Anbieters der Konfiguration im Arbeitsspeicher (AddInMemoryCollection) der App-Konfiguration zwei Dienstzeichenfolgen hinzu.
  • Enthält ein HostingStartup-Attribut, das den Namespace und die Klasse des Hostingstarts angibt.

Die Configure-Methode der ServiceKeyInjection-Klasse verwendet einen IWebHostBuilder, um einer App Erweiterungen hinzuzufügen.

HostingStartupLibrary/ServiceKeyInjection.cs:

[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"},
                    {"ProdAccount_FromLibrary", "PROD_2222222-2222"}
                };

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

Die Indexseite der App liest und rendert die Konfigurationswerte für die beiden Schlüssel, die von der Hostingstartassembly der Klassenbibliothek festgelegt werden:

HostingStartupApp/Pages/Index.cshtml.cs:

public class IndexModel : PageModel
{
    public IndexModel(IConfiguration config)
    {
        ServiceKey_Development_Library = config["DevAccount_FromLibrary"];
        ServiceKey_Production_Library = config["ProdAccount_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()
    {
    }
}

Der Beispielcode enthält darüber hinaus auch ein NuGet-Paketprojekt, das den separaten Hostingstart HostingStartupPackage bereitstellt. Das Paket weist dieselben Merkmale wie die bereits beschriebene Klassenbibliothek auf. Das Paket:

  • Enthält die Hostingstartklasse ServiceKeyInjection, die IHostingStartup implementiert. ServiceKeyInjection fügt der App-Konfiguration zwei Dienstzeichenfolgen hinzu.
  • Enthält ein HostingStartup-Attribut.

HostingStartupPackage/ServiceKeyInjection.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>
                {
                    {"DevAccount_FromPackage", "DEV_3333333-3333"},
                    {"ProdAccount_FromPackage", "PROD_4444444-4444"}
                };

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

Die Indexseite der App liest und rendert die Konfigurationswerte für die beiden Schlüssel, die von der Hostingstartassembly der Bibliothek festgelegt werden:

HostingStartupApp/Pages/Index.cshtml.cs:

public class IndexModel : PageModel
{
    public IndexModel(IConfiguration config)
    {
        ServiceKey_Development_Library = config["DevAccount_FromLibrary"];
        ServiceKey_Production_Library = config["ProdAccount_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()
    {
    }
}

Konsolen-App ohne Einstiegspunkt

Dieses Verfahren ist nur für .NET Core-Apps, nicht jedoch für .NET Framework verfügbar.

Eine dynamische Hostingstarterweiterung, die zur Aktivierung keinen Kompilierungszeitverweis erfordert, kann in einer Konsolen-App ohne Einstiegspunkt bereitgestellt werden, die ein HostingStartup-Attribut enthält. Durch die Veröffentlichung der Konsolen-App wird eine Hostingstartassembly erstellt, die über den Laufzeitspeicher genutzt werden kann.

In diesem Prozess wird aus folgenden Gründen eine Konsolen-App ohne Einstiegspunkt verwendet:

  • Eine Abhängigkeitendatei ist erforderlich, um den Hostingstart in der Hostingstartassembly zu nutzen. Eine Abhängigkeitendatei ist eine ausführbare App-Ressource, die durch das Veröffentlichen einer App, nicht einer Bibliothek, erstellt wird.
  • Eine Bibliothek kann dem Laufzeitpaketspeicher, der ein ausführbares Projekt benötigt, das die freigegebene Laufzeit als Ziel verwendet, nicht direkt hinzugefügt werden.

Bei der Erstellung eines dynamischen Hostingstarts geschieht Folgendes:

  • Eine Hostingstartassembly wird über die Konsolen-App ohne Einstiegspunkt erstellt, für die Folgendes gilt:
    • Sie enthält eine Klasse mit der IHostingStartup-Implementierung.
    • Sie enthält ein HostingStartup-Attribut zum Identifizieren der IHostingStartup-Implementierungsklasse.
  • Die Konsolen-App wird veröffentlicht, um die Abhängigkeiten des Hostingstarts abzurufen. Die Veröffentlichung der Konsolen-App hat unter anderem zur Folge, dass nicht verwendete Abhängigkeiten aus der Abhängigkeitendatei entfernt werden.
  • Die Abhängigkeitendatei wird so geändert, dass der Laufzeitspeicherort der Hostingstartassembly festgelegt wird.
  • Die Hostingstartassembly und die dazu gehörende Abhängigkeitendatei werden im Laufzeitpaketspeicher abgelegt. Damit die Hostingstartassembly und die entsprechende Abhängigkeitendatei erkannt werden, werden sie in einem Paar von Umgebungsvariablen aufgeführt.

Die Konsolen-App verweist auf das Paket Microsoft.AspNetCore.Hosting.Abstractions:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>

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

</Project>

Ein HostingStartup-Attribut identifiziert eine Klasse bei der Erstellung von IWebHost als eine Implementierung von IHostingStartup zum Laden und Ausführen. Im folgenden Beispiel ist der Namespace StartupEnhancement und die Klasse ist StartupEnhancementHostingStartup:

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

Eine Klasse implementiert IHostingStartup. Die Configure-Methode der Klasse verwendet einen IWebHostBuilder, um einer App Erweiterungen hinzuzufügen. IHostingStartup.Configure wird in der Hoststartassembly von der Runtime vor Startup.Configure im Benutzercode aufgerufen. Dadurch kann Benutzercode jede Konfiguration der Hoststartassembly überschreiben.

namespace StartupEnhancement
{
    public class StartupEnhancementHostingStartup : IHostingStartup
    {
        public void Configure(IWebHostBuilder builder)
        {
            // Use the IWebHostBuilder to add app enhancements.
        }
    }
}

Die Datei für die Abhängigkeiten ( .deps.json) legt beim Erstellen eine IHostingStartup-Projekts den runtime-Speicherort der Assembly auf den bin-Ordner fest:

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

Nur ein Teil der Datei wird angezeigt. StartupEnhancement ist der Name der Assembly im Beispiel.

Beim Hostingstart bereitgestellte Konfiguration

Es gibt zwei Ansätze zur Verarbeitung der Konfiguration, je nachdem, ob die Konfiguration des Hostingstarts oder die der App Vorrang haben soll:

  1. Bereitstellen der Konfiguration für die App mit ConfigureAppConfiguration zum Laden der Konfiguration, nachdem die ConfigureAppConfiguration-Delegaten der App ausgeführt wurden. Bei diesem Ansatz hat die Hostingstartkonfiguration Vorrang vor der Konfiguration der App.
  2. Bereitstellen der Konfiguration für die App mit UseConfiguration zum Laden der Konfiguration, bevor die ConfigureAppConfiguration-Delegaten der App ausgeführt werden. Die Konfigurationswerte der App haben bei diesem Ansatz Vorrang vor denen des Hostingstarts.
public class ConfigurationInjection : IHostingStartup
{
    public void Configure(IWebHostBuilder builder)
    {
        Dictionary<string, string> dict;

        builder.ConfigureAppConfiguration(config =>
        {
            dict = new Dictionary<string, string>
            {
                {"ConfigurationKey1", 
                    "From IHostingStartup: Higher priority " +
                    "than the app's configuration."},
            };

            config.AddInMemoryCollection(dict);
        });

        dict = new Dictionary<string, string>
        {
            {"ConfigurationKey2", 
                "From IHostingStartup: Lower priority " +
                "than the app's configuration."},
        };

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

        builder.UseConfiguration(builtConfig);
    }
}

Angeben der Hostingstartassembly

Geben Sie für einen von der Klassenbibliothek oder von der Konsolen-App bereitgestellten Hostingstart den Namen der Hostingstartassembly in der Umgebungsvariablen ASPNETCORE_HOSTINGSTARTUPASSEMBLIES an. Die Umgebungsvariable ist eine durch Semikolons getrennte Liste von Assemblys.

Nur in Hostingstartassemblys wird nach dem HostingStartup-Attribut gesucht. Damit die Beispiel-App HostingStartupApp die weiter oben beschriebenen Hostingstarts erkennt, wird für die Umgebungsvariable der folgende Wert festgelegt:

HostingStartupLibrary;HostingStartupPackage;StartupDiagnostics

Eine Hostingstartassembly kann auch mithilfe der Hostkonfigurationseinstellung „Hostingstartassemblys“ festgelegt werden:

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

Der Platzhalter {ASSEMBLY1;ASSEMBLY2; ...} stellt die durch Semikolons getrennte Assemblyliste dar.

Wenn mehrere Hoststartassemblys vorhanden sind, werden ihre Configure-Methoden in der Reihenfolge der aufgelisteten Assemblys ausgeführt.

Aktivierung

Optionen für die Hostingstartaktivierung:

  • Laufzeitspeicher: Für die Aktivierung ist kein Kompilierzeitverweis erforderlich. Die Beispiel-App legt die Hostingstartassembly und die Abhängigkeitendateien im Ordner deployment ab, um die Bereitstellung des Hostingstarts in einer Umgebung mit mehreren Computern zu erleichtern. Der Ordner deployment enthält darüber hinaus auch ein PowerShell-Skript, das im Bereitstellungssystem Umgebungsvariablen erstellt oder ändert, um den Hostingstart zu ermöglichen.
  • Kompilierzeitverweis für die Aktivierung erforderlich

Laufzeitspeicher

Die Hostingstartimplementierung wird im Laufzeitspeicher abgelegt. Ein Kompilierzeitverweis auf die Assembly wird von der erweiterten App nicht benötigt.

Nach der Erstellung des Hostingstarts wird mithilfe der Manifestprojektdatei und des Befehls dotnet store ein Laufzeitspeicher generiert.

dotnet store --manifest {MANIFEST FILE} --runtime {RUNTIME IDENTIFIER} --output {OUTPUT LOCATION} --skip-optimization

In der Beispiel-App (Projekt RuntimeStore) wird der folgende Befehl verwendet:

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

Damit die Runtime den Laufzeitspeicher ermitteln kann, wird der Speicherort des Laufzeitspeichers der Umgebungsvariablen DOTNET_SHARED_STORE hinzugefügt.

Ändern und Ablegen der Abhängigkeitendatei des Hostingstarts

Um die Erweiterung ohne einen Paketverweis auf die Erweiterung zu aktivieren, geben Sie mit additionalDeps zusätzliche Abhängigkeiten zur Laufzeit an. additionalDeps ermöglicht Ihnen Folgendes:

  • Erweitern des App-Bibliotheksdiagramms durch Bereitstellen einer Reihe zusätzlicher .deps.json-Dateien, die beim Start mit der App-eigenen .deps.json-Datei zusammengeführt werden.
  • Bereitstellen der Hostingstartassembly, sodass sie ermittelt und geladen werden kann

Folgender Ansatz wird zum Generieren der zusätzlichen Abhängigkeitendatei empfohlen:

  1. Führen Sie dotnet publish für die Manifestdatei des Laufzeitspeichers aus, auf die im vorherigen Abschnitt verwiesen wurde.
  2. Entfernen Sie den Manifestverweis aus den Bibliotheken und dem Abschnitt runtime der daraus resultierenden .deps.json-Datei.

Im Beispielprojekt wird die Eigenschaft store.manifest/1.0.0 aus den Abschnitten targets und libraries entfernt:

{
  "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"
    }
  }
}

Legen Sie die .deps.json-Datei an folgendem Speicherort ab:

{ADDITIONAL DEPENDENCIES PATH}/shared/{SHARED FRAMEWORK NAME}/{SHARED FRAMEWORK VERSION}/{ENHANCEMENT ASSEMBLY NAME}.deps.json
  • {ADDITIONAL DEPENDENCIES PATH}: Der Speicherort wurde zur Umgebungsvariable DOTNET_ADDITIONAL_DEPS hinzugefügt.
  • {SHARED FRAMEWORK NAME}: Dies ist das freigegebene Framework, das für diese zusätzliche Abhängigkeitsdatei erforderlich ist.
  • {SHARED FRAMEWORK VERSION}: Dies ist die Mindestversion des freigegebenen Frameworks.
  • {ENHANCEMENT ASSEMBLY NAME}: Dies ist der Name der Erweiterungsassembly.

In der Beispiel-App (Projekt RuntimeStore) wird die zusätzliche Abhängigkeitendatei an folgendem Speicherort abgelegt:

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

Damit die Runtime den Speicherort des Laufzeitspeichers ermitteln kann, wir die zusätzliche Abhängigkeitendatei der Umgebungsvariablen DOTNET_ADDITIONAL_DEPS hinzugefügt.

In der Beispiel-App (Projekt RuntimeStore) wird das Erstellen des Laufzeitspeichers und das Generieren der zusätzlichen Abhängigkeitendatei durch ein PowerShell-Skript durchgeführt.

Beispiele zum Festlegen von Umgebungsvariablen für verschiedene Betriebssysteme finden Sie unter Use multiple environments (Verwenden mehrerer Umgebungen).

Bereitstellung

Um die Bereitstellung eines Hostingstarts in einer Umgebung mit mehreren Computern zu erleichtern, erstellt die Beispiel-App in der veröffentlichten Ausgabe einen deployment-Ordner, der Folgendes enthält:

  • Der Laufzeitspeicher des Hostingstarts.
  • Die Abhängigkeitendatei des Hostingstarts.
  • Ein PowerShell-Skript, das ASPNETCORE_HOSTINGSTARTUPASSEMBLIES, DOTNET_SHARED_STORE und DOTNET_ADDITIONAL_DEPS erstellt oder ändert, um die Aktivierung des Hostingstarts zu unterstützen. Führen Sie das Skript über eine PowerShell-Administratoreingabeaufforderung auf dem Bereitstellungssystem aus.

NuGet-Paket

In einem NuGet-Paket kann eine Hostingstarterweiterung bereitgestellt werden. Das Paket enthält ein HostingStartup-Attribut. Die vom Paket bereitgestellten Hostingstarttypen werden für die App mit einem der folgenden Verfahren verfügbar gemacht:

  • Die Projektdatei der erweiterten App erstellt einen Paketverweis für den Hostingstart in der Projektdatei der App (Kompilierzeitverweis). Wenn ein Kompilierzeitverweis eingerichtet ist, werden die Hostingstartassembly und alle dazu gehörenden Abhängigkeiten in die Abhängigkeitendatei der App ( .deps.json) eingebunden. Dieses Verfahren gilt für ein in nuget.org veröffentlichtes Hostingstartassembly-Paket.
  • Die Abhängigkeitendatei des Hostingstarts wird für die erweiterte App wie im Abschnitt Laufzeitspeicher beschrieben (ohne Kompilierzeitverweis) verfügbar gemacht.

Weitere Informationen zu NuGet-Paketen und den Laufzeitspeicher finden Sie in den folgenden Themen:

Ordner „Bin“ des Projekts

Eine Hostingstarterweiterung kann durch eine mittels bin bereitgestellte Assembly in der erweiterten App bereitgestellt werden. Die von der Assembly bereitgestellten Hostingstarttypen werden für die App mit einem der folgenden Verfahren verfügbar gemacht:

  • Die Projektdatei der erweiterten App enthält einen Assemblyverweis auf den Hostingstart (Kompilierzeitverweis). Wenn ein Kompilierzeitverweis eingerichtet ist, werden die Hostingstartassembly und alle dazu gehörenden Abhängigkeiten in die Abhängigkeitendatei der App ( .deps.json) eingebunden. Dieser Ansatz gilt, wenn das Bereitstellungsszenario erfordert, dass ein Kompilierzeitverweis auf die Assembly des Hostingstarts (DLL-Datei) erstellt und die Assembly in eine der beiden Dateien verschoben wird:
    • Das verbrauchende Projekt.
    • Einen Speicherort, auf den das verbrauchende Projekt zugreifen kann.
  • Die Abhängigkeitendatei des Hostingstarts wird für die erweiterte App wie im Abschnitt Laufzeitspeicher beschrieben (ohne Kompilierzeitverweis) verfügbar gemacht.
  • Wenn das Ziel .NET Framework ist, kann die Assembly in den Standardladekontext geladen werden, was bei .NET Framework bedeutet, dass sich die Assembly an einem der folgenden Speicherorte befindet:
    • Anwendungsbasispfad: Dabei handelt es sich um den Ordner bin, in dem die ausführbare Datei ( .exe) der App gespeichert wird.
    • Globaler Assemblycache (GAC): Der GAC speichert Assemblys, die mehrere .NET Framework-Apps gemeinsam nutzen. Weitere Informationen finden Sie unter Vorgehensweise: Installieren einer Assembly in den globalen Assemblycache in der .NET Framework-Dokumentation.

Beispielcode

Der Beispielcode (Herunterladen) zeigt Szenarios für die Hostingstartimplementierung:

  • Zwei Hostingstartassemblys (Klassenbibliotheken) legen zwei Schlüssel-Wert-Paare der Konfiguration im Arbeitsspeicher fest:
    • NuGet-Paket (HostingStartupPackage)
    • Klassenbibliothek (HostingStartupLibrary)
  • Ein Hostingstart wird über eine im Laufzeitspeicher bereitgestellte Assembly (StartupDiagnostics) aktiviert. Die Assembly fügt der App zum Start zwei Middlewares hinzu, die Diagnoseinformationen zu folgenden Komponenten bereitstellen:
    • Registrierte Dienste
    • Adresse (Schema, Host, Basispfad, Pfad, Abfragezeichenfolge)
    • Verbindung (Remote-IP, Remoteport, lokale IP, lokaler Port, Clientzertifikat)
    • Anforderungsheader
    • Umgebungsvariablen

So führen Sie das Beispiel aus:

Aktivierung über ein NuGet-Paket

  1. Kompilieren Sie das Paket HostingStartupPackage mit dem Befehl dotnet pack.

  2. Fügen Sie den Assemblynamen des Pakets HostingStartupPackage zur Umgebungsvariablen ASPNETCORE_HOSTINGSTARTUPASSEMBLIES hinzu.

  3. Kompilieren Sie die App, und führen Sie diese aus. In der erweiterten App ist ein Paketverweis vorhanden (Kompilierzeitverweis). Eine <PropertyGroup> in der Projektdatei der App gibt die Ausgabe des Paketprojekts ( ../HostingStartupPackage/bin/Debug) als Paketquelle an. Dadurch kann die Anwendung das Paket verwenden, ohne das Paket in nuget.org hochzuladen. Weitere Informationen finden Sie in den Hinweisen in der Projektdatei von HostingStartupApp.

    <PropertyGroup>
      <RestoreSources>$(RestoreSources);https://api.nuget.org/v3/index.json;../HostingStartupPackage/bin/Debug</RestoreSources>
    </PropertyGroup>
    
  4. Die von der Indexseite gerenderten Schlüsselwerte der Dienstkonfiguration entsprechen den durch die ServiceKeyInjection.Configure-Methode des Pakets festgelegten Werten.

Wenn Sie am Projekt HostingStartupPackage Änderungen vornehmen und das Projekt erneut kompilieren, bereinigen Sie die lokalen NuGet-Paketcaches, um sicherzustellen, dass die HostingStartupApp das aktualisierte Paket erhält und kein veraltetes Paket aus dem lokalen Cache. Um die lokalen NuGet-Caches zu bereinigen, führen Sie den folgenden dotnet nuget locals-Befehl aus:

dotnet nuget locals all --clear

Aktivierung über eine Klassenbibliothek

  1. Kompilieren Sie die Klassenbibliothek HostingStartupLibrary mit dem Befehl dotnet build.

  2. Fügen Sie der Umgebungsvariablen ASPNETCORE_HOSTINGSTARTUPASSEMBLIES den Assemblynamen HostingStartupLibrary der Klassenbibliothek hinzu.

  3. Stellen Sie die Assembly der Klassenbibliothek mittels bin für die App bereit, indem Sie die Datei HostingStartupLibrary.dll aus der kompilierten Ausgabe der Klassenbibliothek in den Ordner bin/Debug der App kopieren.

  4. Kompilieren Sie die App, und führen Sie diese aus. Eine <ItemGroup> in der Projektdatei der App verweist auf die Assembly der Klassenbibliothek ( .\bin\Debug\netcoreapp3.0\HostingStartupLibrary.dll) – Kompilierzeitverweis. Weitere Informationen finden Sie in den Hinweisen in der Projektdatei von HostingStartupApp.

    <ItemGroup>
      <Reference Include=".\\bin\\Debug\\netcoreapp3.0\\HostingStartupLibrary.dll">
        <HintPath>.\bin\Debug\netcoreapp3.0\HostingStartupLibrary.dll</HintPath>
        <SpecificVersion>False</SpecificVersion> 
      </Reference>
    </ItemGroup>
    
  5. Die von der Indexseite gerenderten Schlüsselwerte der Dienstkonfiguration entsprechen den durch die ServiceKeyInjection.Configure-Methode der Klassenbibliothek festgelegten Werten.

Aktivierung über eine mittels Laufzeitspeicher bereitgestellten Assembly

  1. Im Projekt StartupDiagnostics wird PowerShell verwendet, um die Datei StartupDiagnostics.deps.json zu bearbeiten. PowerShell ist standardmäßig auf Windows-Betriebssystemen ab Windows 7 SP1 und Windows Server 2008 R2 SP1 installiert. Im Artikel Installieren verschiedener Versionen von PowerShell erfahren Sie, wie Sie PowerShell auf anderen Plattformen erwerben können.
  2. Führen Sie das Skript build.ps1 im Ordner RuntimeStore aus. Das Skript:
    • Generiert das StartupDiagnostics-Paket im Ordner obj\packages .
    • Generiert den Laufzeitspeicher für StartupDiagnostics im Ordner store. Der dotnet store-Befehl im Skript verwendet den win7-x64-Laufzeitbezeichner (RID) für einen Windows bereitgestellten Hostingstart. Wenn der Hostingstart für eine andere Laufzeit bereitgestellt wird, muss in Zeile 37 die entsprechende RID eingegeben werden. Der Runtimespeicher für StartupDiagnostics würde später in den Runtimespeicher des Benutzers oder Systems auf dem Computer verschoben, auf dem die Assembly verwendet wird. Der Installationsspeicherort für den Benutzerruntimespeicher für die StartupDiagnostics-Assembly ist .dotnet/store/x64/netcoreapp3.0/startupdiagnostics/1.0.0/lib/netcoreapp3.0/StartupDiagnostics.dll.
    • Generiert die additionalDeps für StartupDiagnostics im Ordner additionalDeps . Die zusätzlichen Abhängigkeiten würden später in die zusätzlichen Abhängigkeiten des Benutzers oder Systems verschoben. Der Installationsspeicherort der zusätzlichen Abhängigkeiten des Benutzers StartupDiagnostics ist .dotnet/x64/additionalDeps/StartupDiagnostics/shared/Microsoft.NETCore.App/3.0.0/StartupDiagnostics.deps.json.
    • Legt die Datei deploy.ps1 im Ordner deployment ab.
  3. Führen Sie das Skript deploy.ps1 im Ordner deployment aus. Das Skript fügt Folgendes:
    • StartupDiagnostics an die Umgebungsvariable ASPNETCORE_HOSTINGSTARTUPASSEMBLIES.
    • Der Pfad der Hostingstartabhängigkeiten (im Ordner deployment des RuntimeStore-Projekts) zur DOTNET_ADDITIONAL_DEPS-Umgebungsvariablen.
    • Der Pfad des Runtimespeichers (im Ordner deployment des RuntimeStore-Projekts) zur DOTNET_SHARED_STORE-Umgebungsvariablen.
  4. Führen Sie die Beispiel-App aus.
  5. Fordern Sie den Endpunkt /services an, um die registrierten Dienste der App anzuzeigen. Fordern Sie den Endpunkt /diag an, um Diagnoseinformationen anzuzeigen.

Mit einer IHostingStartup-Implementierung (Hostingstart) werden Verbesserungen an einer App beim Start von einer externen Assembly aus vorgenommen. Eine externe Bibliothek kann beispielsweise eine Hostingstartimplementierung verwenden, um zusätzliche Konfigurationsanbieter oder -dienste für eine App bereitzustellen.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)

Das Attribut HostingStartup

Ein HostingStartup-Attribut gibt an, ob eine Hostingstartassembly vorhanden ist, die zur Laufzeit aktiviert werden kann.

Bei der Einstiegsassembly oder bei der Assembly, die die Klasse Startup enthält, wird automatisch geprüft, ob sie das Attribut HostingStartup enthält. Die Liste der Assemblys für die Suche nach HostingStartup-Attributen wird zur Laufzeit aus der Konfiguration in WebHostDefaults.HostingStartupAssembliesKey geladen. Die Liste der Assemblys, die aus der Ermittlung ausgeschlossen werden sollen, wird aus WebHostDefaults.HostingStartupExcludeAssembliesKey geladen. Weitere Informationen finden Sie unter Webhost: HostingstartassemblysWebhost: Auszuschließende Hostingstartassemblys.

Im folgenden Beispiel lautet der Namespace der Hostingstartassembly StartupEnhancement. StartupEnhancementHostingStartup ist die Klasse mit dem Hostingstartcode:

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

Das Attribut HostingStartup befindet sich in der Regel in der IHostingStartup-Implementierungsklassendatei der Hostingstartassembly.

Ermitteln geladener Hostingstartassemblys

Zum Ermitteln von geladenen Hostingstartassemblys aktivieren Sie die Protokollierung und überprüfen die Protokolle der App. Fehler, die beim Laden von Assemblys auftreten, werden protokolliert. Geladene Hostingstartassemblys werden auf der Debugebene protokolliert. Außerdem werden alle Fehler protokolliert.

Deaktivieren des automatischen Ladens von Hostingstartassemblys

Um das automatische Laden von Hostingstartassemblys zu deaktivieren, verwenden Sie einen der folgenden Ansätze:

  • Um zu verhindern, dass alle Hostingstartassemblys geladen werden, legen Sie eine der folgenden Einstellungen auf true oder 1 fest:
  • Um zu verhindern, dass bestimmte Hostingstartassemblys geladen werden, legen Sie eine der folgenden Einstellungen auf eine durch Semikolons getrennte Zeichenfolge mit Hostingstartassemblys fest, die beim Starten ausgeschlossen werden sollen:

Wenn sowohl die Konfigurationseinstellung für den Host als auch die Umgebungsvariable festgelegt werden, wird das Verhalten durch die Hosteinstellung gesteuert.

Durch das Deaktivieren von Hostingstartassemblys mithilfe der Hosteinstellung oder der Umgebungsvariable wird die Assembly global deaktiviert. Einige Eigenschaften einer App können ebenfalls deaktiviert werden.

Projekt

Erstellen Sie einen Hostingstart mit einem der folgenden Projekttypen:

Klassenbibliothek

In einer Klassenbibliothek kann eine Hostingstarterweiterung bereitgestellt werden. Die Bibliothek enthält ein HostingStartup-Attribut.

Der Beispielcode enthält die Razor Pages-App HostingStartupApp und die Klassenbibliothek HostingStartupLibrary. Die Klassenbibliothek:

  • Enthält die Hostingstartklasse ServiceKeyInjection, die IHostingStartup implementiert. ServiceKeyInjection fügt mithilfe des Anbieters der Konfiguration im Arbeitsspeicher (AddInMemoryCollection) der App-Konfiguration zwei Dienstzeichenfolgen hinzu.
  • Enthält ein HostingStartup-Attribut, das den Namespace und die Klasse des Hostingstarts angibt.

Die Configure-Methode der ServiceKeyInjection-Klasse verwendet einen IWebHostBuilder, um einer App Erweiterungen hinzuzufügen.

HostingStartupLibrary/ServiceKeyInjection.cs:

[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"},
                    {"ProdAccount_FromLibrary", "PROD_2222222-2222"}
                };

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

Die Indexseite der App liest und rendert die Konfigurationswerte für die beiden Schlüssel, die von der Hostingstartassembly der Klassenbibliothek festgelegt werden:

HostingStartupApp/Pages/Index.cshtml.cs:

public class IndexModel : PageModel
{
    public IndexModel(IConfiguration config)
    {
        ServiceKey_Development_Library = config["DevAccount_FromLibrary"];
        ServiceKey_Production_Library = config["ProdAccount_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()
    {
    }
}

Der Beispielcode enthält darüber hinaus auch ein NuGet-Paketprojekt, das den separaten Hostingstart HostingStartupPackage bereitstellt. Das Paket weist dieselben Merkmale wie die bereits beschriebene Klassenbibliothek auf. Das Paket:

  • Enthält die Hostingstartklasse ServiceKeyInjection, die IHostingStartup implementiert. ServiceKeyInjection fügt der App-Konfiguration zwei Dienstzeichenfolgen hinzu.
  • Enthält ein HostingStartup-Attribut.

HostingStartupPackage/ServiceKeyInjection.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>
                {
                    {"DevAccount_FromPackage", "DEV_3333333-3333"},
                    {"ProdAccount_FromPackage", "PROD_4444444-4444"}
                };

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

Die Indexseite der App liest und rendert die Konfigurationswerte für die beiden Schlüssel, die von der Hostingstartassembly der Bibliothek festgelegt werden:

HostingStartupApp/Pages/Index.cshtml.cs:

public class IndexModel : PageModel
{
    public IndexModel(IConfiguration config)
    {
        ServiceKey_Development_Library = config["DevAccount_FromLibrary"];
        ServiceKey_Production_Library = config["ProdAccount_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()
    {
    }
}

Konsolen-App ohne Einstiegspunkt

Dieses Verfahren ist nur für .NET Core-Apps, nicht jedoch für .NET Framework verfügbar.

Eine dynamische Hostingstarterweiterung, die zur Aktivierung keinen Kompilierungszeitverweis erfordert, kann in einer Konsolen-App ohne Einstiegspunkt bereitgestellt werden, die ein HostingStartup-Attribut enthält. Durch die Veröffentlichung der Konsolen-App wird eine Hostingstartassembly erstellt, die über den Laufzeitspeicher genutzt werden kann.

In diesem Prozess wird aus folgenden Gründen eine Konsolen-App ohne Einstiegspunkt verwendet:

  • Eine Abhängigkeitendatei ist erforderlich, um den Hostingstart in der Hostingstartassembly zu nutzen. Eine Abhängigkeitendatei ist eine ausführbare App-Ressource, die durch das Veröffentlichen einer App, nicht einer Bibliothek, erstellt wird.
  • Eine Bibliothek kann dem Laufzeitpaketspeicher, der ein ausführbares Projekt benötigt, das die freigegebene Laufzeit als Ziel verwendet, nicht direkt hinzugefügt werden.

Bei der Erstellung eines dynamischen Hostingstarts geschieht Folgendes:

  • Eine Hostingstartassembly wird über die Konsolen-App ohne Einstiegspunkt erstellt, für die Folgendes gilt:
    • Sie enthält eine Klasse mit der IHostingStartup-Implementierung.
    • Sie enthält ein HostingStartup-Attribut zum Identifizieren der IHostingStartup-Implementierungsklasse.
  • Die Konsolen-App wird veröffentlicht, um die Abhängigkeiten des Hostingstarts abzurufen. Die Veröffentlichung der Konsolen-App hat unter anderem zur Folge, dass nicht verwendete Abhängigkeiten aus der Abhängigkeitendatei entfernt werden.
  • Die Abhängigkeitendatei wird so geändert, dass der Laufzeitspeicherort der Hostingstartassembly festgelegt wird.
  • Die Hostingstartassembly und die dazu gehörende Abhängigkeitendatei werden im Laufzeitpaketspeicher abgelegt. Damit die Hostingstartassembly und die entsprechende Abhängigkeitendatei erkannt werden, werden sie in einem Paar von Umgebungsvariablen aufgeführt.

Die Konsolen-App verweist auf das Paket Microsoft.AspNetCore.Hosting.Abstractions:

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

  <PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
  </PropertyGroup>

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

</Project>

Ein HostingStartup-Attribut identifiziert eine Klasse bei der Erstellung von IWebHost als eine Implementierung von IHostingStartup zum Laden und Ausführen. Im folgenden Beispiel ist der Namespace StartupEnhancement und die Klasse ist StartupEnhancementHostingStartup:

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

Eine Klasse implementiert IHostingStartup. Die Configure-Methode der Klasse verwendet einen IWebHostBuilder, um einer App Erweiterungen hinzuzufügen. IHostingStartup.Configure wird in der Hoststartassembly von der Runtime vor Startup.Configure im Benutzercode aufgerufen. Dadurch kann Benutzercode jede Konfiguration der Hoststartassembly überschreiben.

namespace StartupEnhancement
{
    public class StartupEnhancementHostingStartup : IHostingStartup
    {
        public void Configure(IWebHostBuilder builder)
        {
            // Use the IWebHostBuilder to add app enhancements.
        }
    }
}

Die Datei für die Abhängigkeiten ( .deps.json) legt beim Erstellen eine IHostingStartup-Projekts den runtime-Speicherort der Assembly auf den bin-Ordner fest:

"targets": {
  ".NETCoreApp,Version=v2.1": {
    "StartupEnhancement/1.0.0": {
      "dependencies": {
        "Microsoft.AspNetCore.Hosting.Abstractions": "2.1.1"
      },
      "runtime": {
        "StartupEnhancement.dll": {}
      }
    }
  }
}

Nur ein Teil der Datei wird angezeigt. StartupEnhancement ist der Name der Assembly im Beispiel.

Beim Hostingstart bereitgestellte Konfiguration

Es gibt zwei Ansätze zur Verarbeitung der Konfiguration, je nachdem, ob die Konfiguration des Hostingstarts oder die der App Vorrang haben soll:

  1. Bereitstellen der Konfiguration für die App mit ConfigureAppConfiguration zum Laden der Konfiguration, nachdem die ConfigureAppConfiguration-Delegaten der App ausgeführt wurden. Bei diesem Ansatz hat die Hostingstartkonfiguration Vorrang vor der Konfiguration der App.
  2. Bereitstellen der Konfiguration für die App mit UseConfiguration zum Laden der Konfiguration, bevor die ConfigureAppConfiguration-Delegaten der App ausgeführt werden. Die Konfigurationswerte der App haben bei diesem Ansatz Vorrang vor denen des Hostingstarts.
public class ConfigurationInjection : IHostingStartup
{
    public void Configure(IWebHostBuilder builder)
    {
        Dictionary<string, string> dict;

        builder.ConfigureAppConfiguration(config =>
        {
            dict = new Dictionary<string, string>
            {
                {"ConfigurationKey1", 
                    "From IHostingStartup: Higher priority " +
                    "than the app's configuration."},
            };

            config.AddInMemoryCollection(dict);
        });

        dict = new Dictionary<string, string>
        {
            {"ConfigurationKey2", 
                "From IHostingStartup: Lower priority " +
                "than the app's configuration."},
        };

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

        builder.UseConfiguration(builtConfig);
    }
}

Angeben der Hostingstartassembly

Geben Sie für einen von der Klassenbibliothek oder von der Konsolen-App bereitgestellten Hostingstart den Namen der Hostingstartassembly in der Umgebungsvariablen ASPNETCORE_HOSTINGSTARTUPASSEMBLIES an. Die Umgebungsvariable ist eine durch Semikolons getrennte Liste von Assemblys.

Nur in Hostingstartassemblys wird nach dem HostingStartup-Attribut gesucht. Damit die Beispiel-App HostingStartupApp die weiter oben beschriebenen Hostingstarts erkennt, wird für die Umgebungsvariable der folgende Wert festgelegt:

HostingStartupLibrary;HostingStartupPackage;StartupDiagnostics

Eine Hostingstartassembly kann auch mithilfe der Hostkonfigurationseinstellung Hostingstartassemblys festgelegt werden.

Wenn mehrere Hoststartassemblys vorhanden sind, werden ihre Configure-Methoden in der Reihenfolge der aufgelisteten Assemblys ausgeführt.

Aktivierung

Optionen für die Hostingstartaktivierung:

  • Laufzeitspeicher: Für die Aktivierung ist kein Kompilierzeitverweis erforderlich. Die Beispiel-App legt die Hostingstartassembly und die Abhängigkeitendateien im Ordner deployment ab, um die Bereitstellung des Hostingstarts in einer Umgebung mit mehreren Computern zu erleichtern. Der Ordner deployment enthält darüber hinaus auch ein PowerShell-Skript, das im Bereitstellungssystem Umgebungsvariablen erstellt oder ändert, um den Hostingstart zu ermöglichen.
  • Kompilierzeitverweis für die Aktivierung erforderlich

Laufzeitspeicher

Die Hostingstartimplementierung wird im Laufzeitspeicher abgelegt. Ein Kompilierzeitverweis auf die Assembly wird von der erweiterten App nicht benötigt.

Nach der Erstellung des Hostingstarts wird mithilfe der Manifestprojektdatei und des Befehls dotnet store ein Laufzeitspeicher generiert.

dotnet store --manifest {MANIFEST FILE} --runtime {RUNTIME IDENTIFIER} --output {OUTPUT LOCATION} --skip-optimization

In der Beispiel-App (Projekt RuntimeStore) wird der folgende Befehl verwendet:

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

Damit die Runtime den Laufzeitspeicher ermitteln kann, wird der Speicherort des Laufzeitspeichers der Umgebungsvariablen DOTNET_SHARED_STORE hinzugefügt.

Ändern und Ablegen der Abhängigkeitendatei des Hostingstarts

Um die Erweiterung ohne einen Paketverweis auf die Erweiterung zu aktivieren, geben Sie mit additionalDeps zusätzliche Abhängigkeiten zur Laufzeit an. additionalDeps ermöglicht Ihnen Folgendes:

  • Erweitern des App-Bibliotheksdiagramms durch Bereitstellen einer Reihe zusätzlicher .deps.json-Dateien, die beim Start mit der App-eigenen .deps.json-Datei zusammengeführt werden.
  • Bereitstellen der Hostingstartassembly, sodass sie ermittelt und geladen werden kann

Folgender Ansatz wird zum Generieren der zusätzlichen Abhängigkeitendatei empfohlen:

  1. Führen Sie dotnet publish für die Manifestdatei des Laufzeitspeichers aus, auf die im vorherigen Abschnitt verwiesen wurde.
  2. Entfernen Sie den Manifestverweis aus den Bibliotheken und dem Abschnitt runtime der daraus resultierenden .deps.json-Datei.

Im Beispielprojekt wird die Eigenschaft store.manifest/1.0.0 aus den Abschnitten targets und libraries entfernt:

{
  "runtimeTarget": {
    "name": ".NETCoreApp,Version=v2.1",
    "signature": "4ea77c7b75ad1895ae1ea65e6ba2399010514f99"
  },
  "compilationOptions": {},
  "targets": {
    ".NETCoreApp,Version=v2.1": {
      "store.manifest/1.0.0": {
        "dependencies": {
          "StartupDiagnostics": "1.0.0"
        },
        "runtime": {
          "store.manifest.dll": {}
        }
      },
      "StartupDiagnostics/1.0.0": {
        "runtime": {
          "lib/netcoreapp2.1/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-oiQr60vBQW7+nBTmgKLSldj06WNLRTdhOZpAdEbCuapoZ+M2DJH2uQbRLvFT8EGAAv4TAKzNtcztpx5YOgBXQQ==",
      "path": "startupdiagnostics/1.0.0",
      "hashPath": "startupdiagnostics.1.0.0.nupkg.sha512"
    }
  }
}

Legen Sie die .deps.json-Datei an folgendem Speicherort ab:

{ADDITIONAL DEPENDENCIES PATH}/shared/{SHARED FRAMEWORK NAME}/{SHARED FRAMEWORK VERSION}/{ENHANCEMENT ASSEMBLY NAME}.deps.json
  • {ADDITIONAL DEPENDENCIES PATH}: Der Speicherort wurde zur Umgebungsvariable DOTNET_ADDITIONAL_DEPS hinzugefügt.
  • {SHARED FRAMEWORK NAME}: Dies ist das freigegebene Framework, das für diese zusätzliche Abhängigkeitsdatei erforderlich ist.
  • {SHARED FRAMEWORK VERSION}: Dies ist die Mindestversion des freigegebenen Frameworks.
  • {ENHANCEMENT ASSEMBLY NAME}: Dies ist der Name der Erweiterungsassembly.

In der Beispiel-App (Projekt RuntimeStore) wird die zusätzliche Abhängigkeitendatei an folgendem Speicherort abgelegt:

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

Damit die Runtime den Speicherort des Laufzeitspeichers ermitteln kann, wir die zusätzliche Abhängigkeitendatei der Umgebungsvariablen DOTNET_ADDITIONAL_DEPS hinzugefügt.

In der Beispiel-App (Projekt RuntimeStore) wird das Erstellen des Laufzeitspeichers und das Generieren der zusätzlichen Abhängigkeitendatei durch ein PowerShell-Skript durchgeführt.

Beispiele zum Festlegen von Umgebungsvariablen für verschiedene Betriebssysteme finden Sie unter Use multiple environments (Verwenden mehrerer Umgebungen).

Bereitstellung

Um die Bereitstellung eines Hostingstarts in einer Umgebung mit mehreren Computern zu erleichtern, erstellt die Beispiel-App in der veröffentlichten Ausgabe einen deployment-Ordner, der Folgendes enthält:

  • Der Laufzeitspeicher des Hostingstarts.
  • Die Abhängigkeitendatei des Hostingstarts.
  • Ein PowerShell-Skript, das ASPNETCORE_HOSTINGSTARTUPASSEMBLIES, DOTNET_SHARED_STORE und DOTNET_ADDITIONAL_DEPS erstellt oder ändert, um die Aktivierung des Hostingstarts zu unterstützen. Führen Sie das Skript über eine PowerShell-Administratoreingabeaufforderung auf dem Bereitstellungssystem aus.

NuGet-Paket

In einem NuGet-Paket kann eine Hostingstarterweiterung bereitgestellt werden. Das Paket enthält ein HostingStartup-Attribut. Die vom Paket bereitgestellten Hostingstarttypen werden für die App mit einem der folgenden Verfahren verfügbar gemacht:

  • Die Projektdatei der erweiterten App erstellt einen Paketverweis für den Hostingstart in der Projektdatei der App (Kompilierzeitverweis). Wenn ein Kompilierzeitverweis eingerichtet ist, werden die Hostingstartassembly und alle dazu gehörenden Abhängigkeiten in die Abhängigkeitendatei der App ( .deps.json) eingebunden. Dieses Verfahren gilt für ein in nuget.org veröffentlichtes Hostingstartassembly-Paket.
  • Die Abhängigkeitendatei des Hostingstarts wird für die erweiterte App wie im Abschnitt Laufzeitspeicher beschrieben (ohne Kompilierzeitverweis) verfügbar gemacht.

Weitere Informationen zu NuGet-Paketen und den Laufzeitspeicher finden Sie in den folgenden Themen:

Ordner „Bin“ des Projekts

Eine Hostingstarterweiterung kann durch eine mittels bin bereitgestellte Assembly in der erweiterten App bereitgestellt werden. Die von der Assembly bereitgestellten Hostingstarttypen werden für die App mit einem der folgenden Verfahren verfügbar gemacht:

  • Die Projektdatei der erweiterten App enthält einen Assemblyverweis auf den Hostingstart (Kompilierzeitverweis). Wenn ein Kompilierzeitverweis eingerichtet ist, werden die Hostingstartassembly und alle dazu gehörenden Abhängigkeiten in die Abhängigkeitendatei der App ( .deps.json) eingebunden. Dieser Ansatz gilt, wenn das Bereitstellungsszenario erfordert, dass ein Kompilierzeitverweis auf die Assembly des Hostingstarts (DLL-Datei) erstellt und die Assembly in eine der beiden Dateien verschoben wird:
    • Das verbrauchende Projekt.
    • Einen Speicherort, auf den das verbrauchende Projekt zugreifen kann.
  • Die Abhängigkeitendatei des Hostingstarts wird für die erweiterte App wie im Abschnitt Laufzeitspeicher beschrieben (ohne Kompilierzeitverweis) verfügbar gemacht.
  • Wenn das Ziel .NET Framework ist, kann die Assembly in den Standardladekontext geladen werden, was bei .NET Framework bedeutet, dass sich die Assembly an einem der folgenden Speicherorte befindet:
    • Anwendungsbasispfad: Dabei handelt es sich um den Ordner bin, in dem die ausführbare Datei ( .exe) der App gespeichert wird.
    • Globaler Assemblycache (GAC): Der GAC speichert Assemblys, die mehrere .NET Framework-Apps gemeinsam nutzen. Weitere Informationen finden Sie unter Vorgehensweise: Installieren einer Assembly in den globalen Assemblycache in der .NET Framework-Dokumentation.

Beispielcode

Der Beispielcode (Herunterladen) zeigt Szenarios für die Hostingstartimplementierung:

  • Zwei Hostingstartassemblys (Klassenbibliotheken) legen zwei Schlüssel-Wert-Paare der Konfiguration im Arbeitsspeicher fest:
    • NuGet-Paket (HostingStartupPackage)
    • Klassenbibliothek (HostingStartupLibrary)
  • Ein Hostingstart wird über eine im Laufzeitspeicher bereitgestellte Assembly (StartupDiagnostics) aktiviert. Die Assembly fügt der App zum Start zwei Middlewares hinzu, die Diagnoseinformationen zu folgenden Komponenten bereitstellen:
    • Registrierte Dienste
    • Adresse (Schema, Host, Basispfad, Pfad, Abfragezeichenfolge)
    • Verbindung (Remote-IP, Remoteport, lokale IP, lokaler Port, Clientzertifikat)
    • Anforderungsheader
    • Umgebungsvariablen

So führen Sie das Beispiel aus:

Aktivierung über ein NuGet-Paket

  1. Kompilieren Sie das Paket HostingStartupPackage mit dem Befehl dotnet pack.

  2. Fügen Sie den Assemblynamen des Pakets HostingStartupPackage zur Umgebungsvariablen ASPNETCORE_HOSTINGSTARTUPASSEMBLIES hinzu.

  3. Kompilieren Sie die App, und führen Sie diese aus. In der erweiterten App ist ein Paketverweis vorhanden (Kompilierzeitverweis). Eine <PropertyGroup> in der Projektdatei der App gibt die Ausgabe des Paketprojekts ( ../HostingStartupPackage/bin/Debug) als Paketquelle an. Dadurch kann die Anwendung das Paket verwenden, ohne das Paket in nuget.org hochzuladen. Weitere Informationen finden Sie in den Hinweisen in der Projektdatei von HostingStartupApp.

    <PropertyGroup>
      <RestoreSources>$(RestoreSources);https://api.nuget.org/v3/index.json;../HostingStartupPackage/bin/Debug</RestoreSources>
    </PropertyGroup>
    
  4. Die von der Indexseite gerenderten Schlüsselwerte der Dienstkonfiguration entsprechen den durch die ServiceKeyInjection.Configure-Methode des Pakets festgelegten Werten.

Wenn Sie am Projekt HostingStartupPackage Änderungen vornehmen und das Projekt erneut kompilieren, bereinigen Sie die lokalen NuGet-Paketcaches, um sicherzustellen, dass die HostingStartupApp das aktualisierte Paket erhält und kein veraltetes Paket aus dem lokalen Cache. Um die lokalen NuGet-Caches zu bereinigen, führen Sie den folgenden dotnet nuget locals-Befehl aus:

dotnet nuget locals all --clear

Aktivierung über eine Klassenbibliothek

  1. Kompilieren Sie die Klassenbibliothek HostingStartupLibrary mit dem Befehl dotnet build.

  2. Fügen Sie der Umgebungsvariablen ASPNETCORE_HOSTINGSTARTUPASSEMBLIES den Assemblynamen HostingStartupLibrary der Klassenbibliothek hinzu.

  3. Stellen Sie die Assembly der Klassenbibliothek mittels bin für die App bereit, indem Sie die Datei HostingStartupLibrary.dll aus der kompilierten Ausgabe der Klassenbibliothek in den Ordner bin/Debug der App kopieren.

  4. Kompilieren Sie die App, und führen Sie diese aus. Eine <ItemGroup> in der Projektdatei der App verweist auf die Assembly der Klassenbibliothek ( .\bin\Debug\netcoreapp2.1\HostingStartupLibrary.dll) (Kompilierzeitverweis). Weitere Informationen finden Sie in den Hinweisen in der Projektdatei von HostingStartupApp.

    <ItemGroup>
      <Reference Include=".\\bin\\Debug\\netcoreapp2.1\\HostingStartupLibrary.dll">
        <HintPath>.\bin\Debug\netcoreapp2.1\HostingStartupLibrary.dll</HintPath>
        <SpecificVersion>False</SpecificVersion>
      </Reference>
    </ItemGroup>
    
  5. Die von der Indexseite gerenderten Schlüsselwerte der Dienstkonfiguration entsprechen den durch die ServiceKeyInjection.Configure-Methode der Klassenbibliothek festgelegten Werten.

Aktivierung über eine mittels Laufzeitspeicher bereitgestellten Assembly

  1. Im Projekt StartupDiagnostics wird PowerShell verwendet, um die Datei StartupDiagnostics.deps.json zu bearbeiten. PowerShell ist standardmäßig auf Windows-Betriebssystemen ab Windows 7 SP1 und Windows Server 2008 R2 SP1 installiert. Im Artikel Installieren verschiedener Versionen von PowerShell erfahren Sie, wie Sie PowerShell auf anderen Plattformen erwerben können.
  2. Führen Sie das Skript build.ps1 im Ordner RuntimeStore aus. Das Skript:
    • Generiert das StartupDiagnostics-Paket im Ordner obj\packages .
    • Generiert den Laufzeitspeicher für StartupDiagnostics im Ordner store. Der dotnet store-Befehl im Skript verwendet den win7-x64-Laufzeitbezeichner (RID) für einen Windows bereitgestellten Hostingstart. Wenn der Hostingstart für eine andere Laufzeit bereitgestellt wird, muss in Zeile 37 die entsprechende RID eingegeben werden. Der Runtimespeicher für StartupDiagnostics würde später in den Runtimespeicher des Benutzers oder Systems auf dem Computer verschoben, auf dem die Assembly verwendet wird. Der Installationsspeicherort für den Benutzerruntimespeicher für die StartupDiagnostics-Assembly ist .dotnet/store/x64/netcoreapp2.2/startupdiagnostics/1.0.0/lib/netcoreapp2.2/StartupDiagnostics.dll.
    • Generiert die additionalDeps für StartupDiagnostics im Ordner additionalDeps . Die zusätzlichen Abhängigkeiten würden später in die zusätzlichen Abhängigkeiten des Benutzers oder Systems verschoben. Der Installationsspeicherort der zusätzlichen Abhängigkeiten des Benutzers StartupDiagnostics ist .dotnet/x64/additionalDeps/StartupDiagnostics/shared/Microsoft.NETCore.App/2.2.0/StartupDiagnostics.deps.json.
    • Legt die Datei deploy.ps1 im Ordner deployment ab.
  3. Führen Sie das Skript deploy.ps1 im Ordner deployment aus. Das Skript fügt Folgendes:
    • StartupDiagnostics an die Umgebungsvariable ASPNETCORE_HOSTINGSTARTUPASSEMBLIES.
    • Der Pfad der Hostingstartabhängigkeiten (im Ordner deployment des RuntimeStore-Projekts) zur DOTNET_ADDITIONAL_DEPS-Umgebungsvariablen.
    • Der Pfad des Runtimespeichers (im Ordner deployment des RuntimeStore-Projekts) zur DOTNET_SHARED_STORE-Umgebungsvariablen.
  4. Führen Sie die Beispiel-App aus.
  5. Fordern Sie den Endpunkt /services an, um die registrierten Dienste der App anzuzeigen. Fordern Sie den Endpunkt /diag an, um Diagnoseinformationen anzuzeigen.