Runtime package store
Starting with .NET Core 2.0, it's possible to package and deploy apps against a known set of packages that exist in the target environment. The benefits are faster deployments, lower disk space use, and improved startup performance in some cases.
This feature is implemented as a runtime package store, which is a directory on disk where packages are stored (typically at /usr/local/share/dotnet/store on macOS/Linux and C:/Program Files/dotnet/store on Windows). Under this directory, there are subdirectories for architectures and target frameworks. The file layout is similar to the way that NuGet assets are laid out on disk:
A target manifest file lists the packages in the runtime package store. Developers can target this manifest when publishing their app. The target manifest is typically provided by the owner of the targeted production environment.
Preparing a runtime environment
The administrator of a runtime environment can optimize apps for faster deployments and lower disk space use by building a runtime package store and the corresponding target manifest.
The first step is to create a package store manifest that lists the packages that compose the runtime package store. This file format is compatible with the project file format (csproj).
<Project Sdk="Microsoft.NET.Sdk"> <ItemGroup> <PackageReference Include="<NUGET_PACKAGE>" Version="<VERSION>" /> <!-- Include additional packages here --> </ItemGroup> </Project>
<Project Sdk="Microsoft.NET.Sdk"> <ItemGroup> <PackageReference Include="Newtonsoft.Json" Version="10.0.3" /> <PackageReference Include="Moq" Version="4.7.63" /> </ItemGroup> </Project>
Provision the runtime package store by executing
dotnet store with the package store manifest, runtime, and framework:
dotnet store --manifest <PATH_TO_MANIFEST_FILE> --runtime <RUNTIME_IDENTIFIER> --framework <FRAMEWORK>
dotnet store --manifest packages.csproj --runtime win10-x64 --framework netcoreapp2.0 --framework-version 2.0.0
You can pass multiple target package store manifest paths to a single
dotnet store command by repeating the option and path in the command.
By default, the output of the command is a package store under the .dotnet/store subdirectory of the user's profile. You can specify a different location using the
--output <OUTPUT_DIRECTORY> option. The root directory of the store contains a target manifest artifact.xml file. This file can be made available for download and be used by app authors who want to target this store when publishing.
The following artifact.xml file is produced after running the previous example. Note that
Castle.Core is a dependency of
Moq, so it's included automatically and appears in the artifacts.xml manifest file.
<StoreArtifacts> <Package Id="Newtonsoft.Json" Version="10.0.3" /> <Package Id="Castle.Core" Version="4.1.0" /> <Package Id="Moq" Version="4.7.63" /> </StoreArtifacts>
Publishing an app against a target manifest
If you have a target manifest file on disk, you specify the path to the file when publishing your app with the
dotnet publish command:
dotnet publish --manifest <PATH_TO_MANIFEST_FILE>
dotnet publish --manifest manifest.xml
You deploy the resulting published app to an environment that has the packages described in the target manifest. Failing to do so results in the app failing to start.
Specify multiple target manifests when publishing an app by repeating the option and path (for example,
--manifest manifest1.xml --manifest manifest2.xml). When you do so, the app is trimmed for the union of packages specified in the target manifest files provided to the command.
Specifying target manifests in the project file
An alternative to specifying target manifests with the
dotnet publish command is to specify them in the project file as a semicolon-separated list of paths under a <TargetManifestFiles> tag.
<PropertyGroup> <TargetManifestFiles>manifest1.xml;manifest2.xml</TargetManifestFiles> </PropertyGroup>
Specify the target manifests in the project file only when the target environment for the app is well-known, such as for .NET Core projects. This isn't the case for open-source projects. The users of an open-source project typically deploy it to different production environments. These production environments generally have different sets of packages pre-installed. You can't make assumptions about the target manifest in such environments, so you should use the
--manifest option of
ASP.NET Core implicit store
The runtime package store feature is used implicitly by an ASP.NET Core app when the app is deployed as a framework-dependent deployment (FDD) app. The targets in
Microsoft.NET.Sdk.Web include manifests referencing the implicit package store on the target system. Additionally, any FDD app that depends on the
Microsoft.AspNetCore.All package results in a published app that contains only the app and its assets and not the packages listed in the
Microsoft.AspNetCore.All metapackage. It's assumed that those packages are present on the target system.
The runtime package store is installed on the host when the .NET Core SDK is installed. Other installers may provide the runtime package store, including Zip/tarball installations of the .NET Core SDK,
apt-get, Red Hat Yum, the .NET Core Windows Server Hosting bundle, and manual runtime package store installations.
When deploying a framework-dependent deployment (FDD) app, make sure that the target environment has the .NET Core SDK installed. If the app is deployed to an environment that doesn't include ASP.NET Core, you can opt out of the implicit store by specifying <PublishWithAspNetCoreTargetManifest> set to
false in the project file as in the following example:
<PropertyGroup> <PublishWithAspNetCoreTargetManifest>false</PublishWithAspNetCoreTargetManifest> </PropertyGroup>
For self-contained deployment (SCD) apps, it's assumed that the target system doesn't necessarily contain the required manifest packages. Therefore, <PublishWithAspNetCoreTargetManifest> cannot be set to
true for an SCD app.
If you deploy an application with a manifest dependency that's present in the deployment (the assembly is present in the bin folder), the runtime package store isn't used on the host for that assembly. The bin folder assembly is used regardless of its presence in the runtime package store on the host.
The version of the dependency indicated in the manifest must match the version of the dependency in the runtime package store. If you have a version mismatch between the dependency in the target manifest and the version that exists in the runtime package store and the app doesn't include the required version of the package in its deployment, the app fails to start. The exception includes the name of the target manifest that called for the runtime package store assembly, which helps you troubleshoot the mismatch.
When the deployment is trimmed on publish, only the specific versions of the manifest packages you indicate are withheld from the published output. The packages at the versions indicated must be present on the host for the app to start.