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 usage, 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:

\dotnet
    \store
        \x64
            \netcoreapp2.0
                \microsoft.applicationinsights
                \microsoft.aspnetcore
                ...
        \x86
            \netcoreapp2.0
                \microsoft.applicationinsights
                \microsoft.aspnetcore
                ...

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>

Example

The following example package store manifest (packages.csproj) is used to add Newtonsoft.Json and Moq to a runtime package store:

<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>

Example

dotnet store --manifest packages.csproj --runtime win-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.

Example

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>

Example

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.

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.

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 dotnet publish.

ASP.NET Core implicit store (.NET Core 2.0 only)

The ASP.NET Core implicit store applies only to ASP.NET Core 2.0. We strongly recommend applications use ASP.NET Core 2.1 and later, which does not use the implicit store. ASP.NET Core 2.1 and later use the shared framework.

For .NET Core 2.0, the runtime package store feature is used implicitly by an ASP.NET Core app when the app is deployed as a framework-dependent deployment app. The targets in Microsoft.NET.Sdk.Web include manifests referencing the implicit package store on the target system. Additionally, any framework-dependent 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 SDK is installed. Other installers may provide the runtime package store, including Zip/tarball installations of the .NET 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 app, make sure that the target environment has the .NET 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>

Note

For self-contained deployment 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 self-contained app.

See also