26 KiB
title | author | description | monikerRange | ms.author | ms.custom | ms.date | uid |
---|---|---|---|---|---|---|---|
Enhance an app from an external assembly in ASP.NET Core with IHostingStartup | guardrex | Discover how to enhance an ASP.NET Core app from an external assembly using an IHostingStartup implementation. | >= aspnetcore-2.0 | riande | mvc | 08/13/2018 | fundamentals/configuration/platform-specific-configuration |
Enhance an app from an external assembly in ASP.NET Core with IHostingStartup
By Luke Latham
An IHostingStartup (hosting startup) implementation adds enhancements to an app at startup from an external assembly. For example, an external library can use a hosting startup implementation to provide additional configuration providers or services to an app. IHostingStartup
is available in ASP.NET Core 2.0 or later.
View or download sample code (how to download)
HostingStartup attribute
A HostingStartup attribute indicates the presence of a hosting startup assembly to activate at runtime.
The entry assembly or the assembly containing the Startup
class is automatically scanned for the HostingStartup
attribute. The list of assemblies to search for HostingStartup
attributes is loaded at runtime from configuration in the WebHostDefaults.HostingStartupAssembliesKey. The list of assemblies to exclude from discovery is loaded from the WebHostDefaults.HostingStartupExcludeAssembliesKey. For more information, see Web Host: Hosting Startup Assemblies and Web Host: Hosting Startup Exclude Assemblies.
In the following example, the namespace of the hosting startup assembly is StartupEnhancement
. The class containing the hosting startup code is StartupEnhancementHostingStartup
:
The HostingStartup
attribute is typically located in the hosting startup assembly's IHostingStartup
implementation class file.
Discover loaded hosting startup assemblies
To discover loaded hosting startup assemblies, enable logging and check the app's logs. Errors that occur when loading assemblies are logged. Loaded hosting startup assemblies are logged at the Debug level, and all errors are logged.
Disable automatic loading of hosting startup assemblies
::: moniker range=">= aspnetcore-2.1"
To disable automatic loading of hosting startup assemblies, use one of the following approaches:
- To prevent all hosting startup assemblies from loading, set one of the following to
true
or1
:- Prevent Hosting Startup host configuration setting.
ASPNETCORE_PREVENTHOSTINGSTARTUP
environment variable.
- To prevent specific hosting startup assemblies from loading, set one of the following to a semicolon-delimited string of hosting startup assemblies to exclude at startup:
- Hosting Startup Exclude Assemblies host configuration setting.
ASPNETCORE_HOSTINGSTARTUPEXCLUDEASSEMBLIES
environment variable.
::: moniker-end
::: moniker range="= aspnetcore-2.0"
To disable automatic loading of hosting startup assemblies, set one of the following to true
or 1
:
- Prevent Hosting Startup host configuration setting.
ASPNETCORE_PREVENTHOSTINGSTARTUP
environment variable.
::: moniker-end
If both the host configuration setting and the environment variable are set, the host setting controls the behavior.
Disabling hosting startup assemblies using the host setting or environment variable disables the assembly globally and may disable several characteristics of an app.
Project
Create a hosting startup with either of the following project types:
Class library
A hosting startup enhancement can be provided in a class library. The library contains a HostingStartup
attribute.
The sample code includes a Razor Pages app, HostingStartupApp, and a class library, HostingStartupLibrary. The class library:
- Contains a hosting startup class,
ServiceKeyInjection
, which implementsIHostingStartup
.ServiceKeyInjection
adds a pair of service strings to the app's configuration using the in-memory configuration provider (AddInMemoryCollection). - Includes a
HostingStartup
attribute that identifies the hosting startup's namespace and class.
The ServiceKeyInjection
class's Configure method uses an IWebHostBuilder to add enhancements to an app. IHostingStartup.Configure
in the hosting startup assembly is called by the runtime before Startup.Configure
in user code, which allows user code to overwrite any configuration provided by the hosting startup assembly.
HostingStartupLibrary/ServiceKeyInjection.cs:
The app's Index page reads and renders the configuration values for the two keys set by the class library's hosting startup assembly:
HostingStartupApp/Pages/Index.cshtml.cs:
The sample code also includes a NuGet package project that provides a separate hosting startup, HostingStartupPackage. The package has the same characteristics of the class library described earlier. The package:
- Contains a hosting startup class,
ServiceKeyInjection
, which implementsIHostingStartup
.ServiceKeyInjection
adds a pair of service strings to the app's configuration. - Includes a
HostingStartup
attribute.
HostingStartupPackage/ServiceKeyInjection.cs:
The app's Index page reads and renders the configuration values for the two keys set by the package's hosting startup assembly:
HostingStartupApp/Pages/Index.cshtml.cs:
Console app without an entry point
This approach is only available for .NET Core apps, not .NET Framework.
A dynamic hosting startup enhancement that doesn't require a compile-time reference for activation can be provided in a console app without an entry point. The app contains a HostingStartup
attribute. To create a dynamic hosting startup:
- An implementation library is created from the class that contains the
IHostingStartup
implementation. The implementation library is treated as a normal package. - A console app without an entry point references the implementation library package. A console app is used because:
- A dependencies file is a runnable app asset, so a library can't furnish a dependencies file.
- A library can't be added directly to the runtime package store, which requires a runnable project that targets the shared runtime.
- The console app is published to obtain the hosting startup's dependencies. A consequence of publishing the console app is that unused dependencies are trimmed from the dependencies file.
- The app and its dependencies file is placed into the runtime package store. To discover the hosting startup assembly and its dependencies file, they're referenced in a pair of environment variables.
The console app references the Microsoft.AspNetCore.Hosting.Abstractions package:
A HostingStartup attribute identifies a class as an implementation of IHostingStartup
for loading and execution when building the IWebHost. In the following example, the namespace is StartupEnhancement
, and the class is StartupEnhancementHostingStartup
:
A class implements IHostingStartup
. The class's Configure method uses an IWebHostBuilder to add enhancements to an app. IHostingStartup.Configure
in the hosting startup assembly is called by the runtime before Startup.Configure
in user code, which allows user code to overwrite any configuration provided by the hosting startup assembly.
When building an IHostingStartup
project, the dependencies file (*.deps.json) sets the runtime
location of the assembly to the bin folder:
Only part of the file is shown. The assembly name in the example is StartupEnhancement
.
Specify the hosting startup assembly
For either a class library- or console app-supplied hosting startup, specify the hosting startup assembly's name in the ASPNETCORE_HOSTINGSTARTUPASSEMBLIES
environment variable. The environment variable is a semicolon-delimited list of assemblies.
Only hosting startup assemblies are scanned for the HostingStartup
attribute. For the sample app, HostingStartupApp, to discover the hosting startups described earlier, the environment variable is set to the following value:
HostingStartupLibrary;HostingStartupPackage;StartupDiagnostics
A hosting startup assembly can also be set using the Hosting Startup Assemblies host configuration setting.
When multiple hosting startup assembles are present, their Configure methods are executed in the order that the assemblies are listed.
Activation
Options for hosting startup activation are:
- Runtime store – Activation doesn't require a compile-time reference for activation. The sample app places the hosting startup assembly and dependencies files into a folder, deployment, to facilitate deployment of the hosting startup in a multimachine environment. The deployment folder also includes a PowerShell script that creates or modifies environment variables on the deployment system to enable the hosting startup.
- Compile-time reference required for activation
Runtime store
The hosting startup implementation is placed in the runtime store. A compile-time reference to the assembly isn't required by the enhanced app.
After the hosting startup is built, the hosting startup's project file serves as the manifest file for the dotnet store command.
dotnet store --manifest <PROJECT_FILE> --runtime <RUNTIME_IDENTIFIER>
This command places the hosting startup assembly and other dependencies that aren't part of the shared framework in the user profile's runtime store at:
Windows
%USERPROFILE%\.dotnet\store\x64\<TARGET_FRAMEWORK_MONIKER>\<ENHANCEMENT_ASSEMBLY_NAME>\<ENHANCEMENT_VERSION>\lib\<TARGET_FRAMEWORK_MONIKER>\
macOS
/Users/<USER>/.dotnet/store/x64/<TARGET_FRAMEWORK_MONIKER>/<ENHANCEMENT_ASSEMBLY_NAME>/<ENHANCEMENT_VERSION>/lib/<TARGET_FRAMEWORK_MONIKER>/
Linux
/Users/<USER>/.dotnet/store/x64/<TARGET_FRAMEWORK_MONIKER>/<ENHANCEMENT_ASSEMBLY_NAME>/<ENHANCEMENT_VERSION>/lib/<TARGET_FRAMEWORK_MONIKER>/
If you desire to place the assembly and dependencies for global use, add the -o|--output
option to the dotnet store
command with the following path:
Windows
%PROGRAMFILES%\dotnet\store\x64\<TARGET_FRAMEWORK_MONIKER>\<ENHANCEMENT_ASSEMBLY_NAME>\<ENHANCEMENT_VERSION>\lib\<TARGET_FRAMEWORK_MONIKER>\
macOS
/usr/local/share/dotnet/store/x64/<TARGET_FRAMEWORK_MONIKER>/<ENHANCEMENT_ASSEMBLY_NAME>/<ENHANCEMENT_VERSION>/lib/<TARGET_FRAMEWORK_MONIKER>/
Linux
/usr/local/share/dotnet/store/x64/<TARGET_FRAMEWORK_MONIKER>/<ENHANCEMENT_ASSEMBLY_NAME>/<ENHANCEMENT_VERSION>/lib/<TARGET_FRAMEWORK_MONIKER>/
Modify and place the hosting startup's dependencies file
The runtime location is specified in the *.deps.json file. To activate the enhancement, the runtime
element must specify the location of the enhancement's runtime assembly. Prefix the runtime
location with lib/<TARGET_FRAMEWORK_MONIKER>/
:
In the sample code (StartupDiagnostics project), modification of the *.deps.json file is performed by a PowerShell script. The PowerShell script is automatically triggered by a build target in the project file.
The implementation's *.deps.json file must be in an accessible location.
For per-user use, place the file in the additonalDeps folder of the user profile's .dotnet
settings:
Windows
%USERPROFILE%\.dotnet\x64\additionalDeps\<ENHANCEMENT_ASSEMBLY_NAME>\shared\Microsoft.NETCore.App\<SHARED_FRAMEWORK_VERSION>\
macOS
/Users/<USER>/.dotnet/x64/additionalDeps/<ENHANCEMENT_ASSEMBLY_NAME>/shared/Microsoft.NETCore.App/<SHARED_FRAMEWORK_VERSION>/
Linux
/Users/<USER>/.dotnet/x64/additionalDeps/<ENHANCEMENT_ASSEMBLY_NAME>/shared/Microsoft.NETCore.App/<SHARED_FRAMEWORK_VERSION>/
For global use, place the file in the additonalDeps folder of the .NET Core installation:
Windows
%PROGRAMFILES%\dotnet\additionalDeps\<ENHANCEMENT_ASSEMBLY_NAME>\shared\Microsoft.NETCore.App\<SHARED_FRAMEWORK_VERSION>\
macOS
/usr/local/share/dotnet/additionalDeps/<ENHANCEMENT_ASSEMBLY_NAME>/shared/Microsoft.NETCore.App/<SHARED_FRAMEWORK_VERSION>/
Linux
/usr/local/share/dotnet/additionalDeps/<ENHANCEMENT_ASSEMBLY_NAME>/shared/Microsoft.NETCore.App/<SHARED_FRAMEWORK_VERSION>/
The shared framework version reflects the version of the shared runtime that the target app uses. The shared runtime is shown in the *.runtimeconfig.json file. In the sample app (HostingStartupApp), the shared runtime is specified in the HostingStartupApp.runtimeconfig.json file.
List the hosting startup's dependencies file
The location of the implementation's *.deps.json file is listed in the DOTNET_ADDITIONAL_DEPS
environment variable.
If the file is placed in the user profile's .dotnet folder, set the environment variable's value to:
Windows
%USERPROFILE%\.dotnet\x64\additionalDeps\
macOS
/Users/<USER>/.dotnet/x64/additionalDeps/
Linux
/Users/<USER>/.dotnet/x64/additionalDeps/
If the file is placed in the .NET Core installation for global use, provide the full path to the file:
Windows
%PROGRAMFILES%\dotnet\additionalDeps\<ENHANCEMENT_ASSEMBLY_NAME>\shared\Microsoft.NETCore.App\<SHARED_FRAMEWORK_VERSION>\<ENHANCEMENT_ASSEMBLY_NAME>.deps.json
macOS
/usr/local/share/dotnet/additionalDeps/<ENHANCEMENT_ASSEMBLY_NAME>/shared/Microsoft.NETCore.App/<SHARED_FRAMEWORK_VERSION>/<ENHANCEMENT_ASSEMBLY_NAME>.deps.json
Linux
/usr/local/share/dotnet/additionalDeps/<ENHANCEMENT_ASSEMBLY_NAME>/shared/Microsoft.NETCore.App/<SHARED_FRAMEWORK_VERSION>/<ENHANCEMENT_ASSEMBLY_NAME>.deps.json
For the sample app (HostingStartupApp) to find the dependencies file (HostingStartupApp.runtimeconfig.json), the dependencies file is placed in the user's profile.
Windows
Set the DOTNET_ADDITIONAL_DEPS
environment variable to the following value:
%UserProfile%\.dotnet\x64\additionalDeps\StartupDiagnostics\
macOS
Set the DOTNET_ADDITIONAL_DEPS
environment variable to the following value:
/Users/<USER>/.dotnet/x64/additionalDeps/StartupDiagnostics/
Linux
Set the DOTNET_ADDITIONAL_DEPS
environment variable to the following value:
/Users/<USER>/.dotnet/x64/additionalDeps/StartupDiagnostics/
For examples of how to set environment variables for various operating systems, see Use multiple environments.
Deployment
To facilitate the deployment of a hosting startup in a multimachine environment, the sample app creates a deployment folder in published output that contains:
- The hosting startup assembly.
- The hosting startup dependencies file.
- A PowerShell script that creates or modifies the
ASPNETCORE_HOSTINGSTARTUPASSEMBLIES
andDOTNET_ADDITIONAL_DEPS
to support the activation of the hosting startup. Run the script from an administrative PowerShell command prompt on the deployment system.
NuGet package
A hosting startup enhancement can be provided in a NuGet package. The package has a HostingStartup
attribute. The hosting startup types provided by the package are made available to the app using either of the following approaches:
- The enhanced app's project file makes a package reference for the hosting startup in the app's project file (a compile-time reference). With the compile-time reference in place, the hosting startup assembly and all of its dependencies are incorporated into the app's dependency file (*.deps.json). This approach applies to a hosting startup assembly package published to nuget.org.
- The hosting startup's dependencies file is made available to the enhanced app as described in the Runtime store section (without a compile-time reference).
For more information on NuGet packages and the runtime store, see the following topics:
Project bin folder
A hosting startup enhancement can be provided by a bin-deployed assembly in the enhanced app. The hosting startup types provided by the assembly are made available to the app using either of the following approaches:
- The enhanced app's project file makes an assembly reference to the hosting startup (a compile-time reference). With the compile-time reference in place, the hosting startup assembly and all of its dependencies are incorporated into the app's dependency file (*.deps.json). This approach applies when the deployment scenario calls for moving the compiled hosting startup library's assembly (DLL file) to the consuming project or to a location accessible by the consuming project and a compile-time reference is made to the hosting startup's assembly.
- The hosting startup's dependencies file is made available to the enhanced app as described in the Runtime store section (without a compile-time reference).
Sample code
The sample code (how to download) demonstrates hosting startup implementation scenarios:
- Two hosting startup assemblies (class libraries) set a pair of in-memory configuration key-value pairs each:
- NuGet package (HostingStartupPackage)
- Class library (HostingStartupLibrary)
- A hosting startup is activated from a runtime store-deployed assembly (StartupDiagnostics). The assembly adds two middlewares to the app at startup that provide diagnostic information on:
- Registered services
- Address (scheme, host, path base, path, query string)
- Connection (remote IP, remote port, local IP, local port, client certificate)
- Request headers
- Environment variables
To run the sample:
Activation from a NuGet package
-
Compile the HostingStartupPackage package with the dotnet pack command.
-
Add the package's assembly name of the HostingStartupPackage to the
ASPNETCORE_HOSTINGSTARTUPASSEMBLIES
environment variable. -
Compile and run the app. A package reference is present in the enhanced app (a compile-time reference). A
<PropertyGroup>
in the app's project file specifies the package project's output (../HostingStartupPackage/bin/Debug) as a package source. This allows the app to use the package without uploading the package to nuget.org. For more information, see the notes in the HostingStartupApp's project file.<PropertyGroup> <RestoreSources>$(RestoreSources);https://api.nuget.org/v3/index.json;../HostingStartupPackage/bin/Debug</RestoreSources> </PropertyGroup>
-
Observe that the service configuration key values rendered by the Index page match the values set by the package's
ServiceKeyInjection.Configure
method.
If you make changes to the HostingStartupPackage project and recompile it, clear the local NuGet package caches to ensure that the HostingStartupApp receives the updated package and not a stale package from the local cache. To clear the local NuGet caches, execute the following dotnet nuget locals command:
dotnet nuget locals all --clear
Activation from a class library
-
Compile the HostingStartupLibrary class library with the dotnet build command.
-
Add the class library's assembly name of HostingStartupLibrary to the
ASPNETCORE_HOSTINGSTARTUPASSEMBLIES
environment variable. -
bin-deploy the class library's assembly to the app by copying the HostingStartupLibrary.dll file from the class library's compiled output to the app's bin/Debug folder.
-
Compile and run the app. An
<ItemGroup>
in the app's project file references the class library's assembly (.\bin\Debug\netcoreapp2.1\HostingStartupLibrary.dll) (a compile-time reference). For more information, see the notes in the HostingStartupApp's project file.<ItemGroup> <Reference Include=".\bin\Debug\netcoreapp2.1\HostingStartupLibrary.dll"> <HintPath>.\bin\Debug\netcoreapp2.1\HostingStartupLibrary.dll</HintPath> <SpecificVersion>False</SpecificVersion> </Reference> </ItemGroup>
-
Observe that the service configuration key values rendered by the Index page match the values set by the class library's
ServiceKeyInjection.Configure
method.
Activation from a runtime store-deployed assembly
-
The StartupDiagnostics project uses PowerShell to modify its StartupDiagnostics.deps.json file. PowerShell is installed by default on Windows starting with Windows 7 SP1 and Windows Server 2008 R2 SP1. To obtain PowerShell on other platforms, see Installing Windows PowerShell.
-
Build the StartupDiagnostics project. After the project is built, a build target in the project file automatically:
- Triggers the PowerShell script to modify the StartupDiagnostics.deps.json file.
- Moves the StartupDiagnostics.deps.json file to the user profile's additionalDeps folder.
-
Execute the
dotnet store
command at a command prompt in the hosting startup's directory to store the assembly and its dependencies in the user profile's runtime store:dotnet store --manifest StartupDiagnostics.csproj --runtime <RID>
For Windows, the command uses the
win7-x64
runtime identifier (RID). When providing the hosting startup for a different runtime, substitute the correct RID. -
Set the environment variables:
- Add the assembly name of StartupDiagnostics to the
ASPNETCORE_HOSTINGSTARTUPASSEMBLIES
environment variable. - On Windows, set the
DOTNET_ADDITIONAL_DEPS
environment variable to%UserProfile%\.dotnet\x64\additionalDeps\StartupDiagnostics\
. On macOS/Linux, set theDOTNET_ADDITIONAL_DEPS
environment variable to/Users/<USER>/.dotnet/x64/additionalDeps/StartupDiagnostics/
, where<USER>
is the user profile that contains the hosting startup.
- Add the assembly name of StartupDiagnostics to the
-
Run the sample app.
-
Request the
/services
endpoint to see the app's registered services. Request the/diag
endpoint to see the diagnostic information.