docs/design/features/DotNetCore-SharedPackageStore.md
To enable sharing of assemblies among all machine-wide .NET Core applications, a centralized shared assembly store is needed. It enables applications to be trimmed of the shared assemblies and frees the apps from carrying them. This document will describe such an assembly store and its lookup that applications can take advantage of during development and their deployment. It also describes commands that will augment dotnet to compose shared package store entries and publishing mechanisms through which apps can filter assemblies to reduce disk usage.
The package store can be either a global system-wide folder or a dotnet.exe relative folder:
dotnet root location -- on Windows, the folder is located in C:\Program Files (x86)\. See layout below.store/install folder we expect packages to be installed ONLY through platform installers like MSI, pkg, deb, apt-get etc.dotnet store command (details follow) are expected to be unzipped directly into the store folder. Note, that this unzip step is a manual action. - dotnet.exe
- shared
- netcoreapp2.0
+ 2.0.0-preview2-00001
- store
- install
+ refs
+ netcoreapp2.0
+ netcoreapp2.1
+ refs
+ netcoreapp2.0
+ netcoreapp2.1
The layout within netcoreapp* folders is a NuGet cache layout.
To compose the layout of the shared package store, we will use a dotnet command called dotnet store. We expect the hosting providers (ex: Antares) to use the command to prime their machines and framework authors who want to provide pre-optimized package archives create the compressed archive layouts.
The layout is composed from a list of package names and versions specified as xml:
Roslyn Example
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="1.3.2" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="1.3.2" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic.Features" Version="1.3.2" />
</ItemGroup>
</Project>
and issue a command like below:
dotnet store --manifest packages.xml --framework netcoreapp2.0 [--output C:\Foo] --runtime win7-x64 --framework-version 2.0.0-preview2-00001 [--no-optimize]
--framework Specifies the TFM that the package store is applicable to
--output The output directory to create the package store in (default: %USERPROFILE%\.dotnet or ~/.dotnet)
--skip-optimization Do not perform crossgen of the assemblies after "restore" (optimize is the default)
--runtime The runtime identifier of the target platform where these assemblies will be run
--framework-version The Microsoft.NETCore.App package version that will be used to run the assemblies
NOTE: It is a requirement that packages.xml is of msbuild format, because it forms the entry point from which the rest of the SDK's functionality can be accessed
Hosting providers would create a packages.xml file corresponding to the packages that will be shared in their hosting environment and specify the file to dotnet store. The file can be on the file system or from an URL. The TFM argument is used in the shared package layout described above.
If --optimize is specified, we would precompile all the managed assets to native code in a temp folder before copying to the output folder. If crossgen is used, it would be the one acquired in the closure of the Microsoft.NETCore.App specified by the --framework-version option. Also, if no --output folder is specified, then the default is ~/.dotnet or %USERPROFILE%\.dotnet\. The output asset files will be present in the following layout: $HOME/.dotnet/packages/{tfm}/{package-name}/{package-version}/{asset-path}.
The output folder will be consumed by the runtime by adding to the DOTNET_SHARED_STORE environment variable. See probe precedence below.
The current mechanism to build applications that share assemblies is by not specifying a RID in the project file. Then, a portable app model is assumed and assemblies that are part of Microsoft.NETCore.App are found under the dotnet install root. With shared package store, applications have the ability to filter any set of packages from their publish output. Thus the decision of a portable or a standalone application is not made at the time of project authoring but is instead done at publish time.
We will by default treat Microsoft.NETCore.App as though type: platform is always specified, thus requiring no explicit RID specification by the user. It will be an ERROR to specify a RID in the csproj file using the <RuntimeIdentifier/> tag.
Because RIDs are not available until publish time, the application is treated as though it is a present day portable app and a regular restore is performed.
dotnet build should treat any project as though it is a portable app and produce runtimeconfig.json with the Microsoft.NETCore.App as the framework. In addition, the runtimeconfig.json file should also specify the TFM field as:
"runtimeOptions": {
"tfm": "netcoreapp2.0",
"framework": {
"version": "2.0.0",
"name": "Microsoft.NETCore.App"
}
}
Note that this is different from current behavior of dotnet run for an application that specifies the <RuntimeIdentifier/> tag in the csproj.
Current Behavior: Picks M.N.A assemblies out of the NuGet cache without taking advantage of optimizations available from the shared Microsoft.NETCore.App.
New Behavior: Picks M.N.A assemblies from the shared framework and the rest of them from the shared package store or the NuGet cache.
dotnet build can take advantage of the refs folder available at the store/install/ folder from the dotnet root directory enabling the offline-restore-build scenario. Although we are designing to augment dotnet build in the future regarding the reference assemblies, for the scope of this work we'll focus only on runtime assemblies.
The host will probe in the order described in host-probing for dotnet run and application activations post dotnet publish.
Publish will be enhanced to support a filter profile file specified as xml. This file explicitly lists all asset packages that need to be trimmed out of the publish output. The following are examples of how various application types can be published.
Publish a portable app:
dotnet publish
Publish a standalone app for the current RID:
dotnet publish --standalone
Publish a standalone app for win7-x64 filtering out the publish profile:
dotnet publish --runtime win7-x64 filter https://asp.net/core/dev/1.2.0/profile.xml
Publishing a portable app for win7-x64 filtering out the publish profile:
dotnet publish filter https://asp.net/core/dev/1.2.0/profile.xml
Publishing a Windows level portable application (a.k.a rid-specific portable app) i.e., filter all non-windows RIDs but split the bin directory on windows RIDs (win8, win7 and win10, for example):
dotnet publish filter https://asp.net/core/dev/1.2.0/win.profile.xml
To chain multiple profiles, specify filter multiple times.
Note that the profile.xml specifies exact RID-specific or IL packages to filter out of dotnet publish output -- i.e., the physical files will be filtered out of the dotnet publish output. The deps.json (logical assets) file will still contain the entries specified in the profile.xml file.
packages.xml file.dotnet store to produce the layout in the directory.profile.xml file that users can use in sync with the installers.packages.xml file that can be used to perform dotnet store.profile.xml file that can perform publish filtering.dotnet store when running the app.dotnet publish filter profile.xml to produce an ASP.NET app without containing shared components.
dotnet run after installing MSIs or zips.dotnet store in a folder.DOTNET_SHARED_STORE.dotnet run to pick up the shared packages.dotnet publish filter profile.xml with Antares profile.I host apps that are already published
dotnet store and produce layout or unzip an earlier layout.DOTNET_SHARED_STORE to point to layout.I build user apps from source
Microsoft.NETCore.App to netcoreapp2.0 in the dotnet root. Note that this has to maintain compat.dotnet restore restore as though project is type: platform.dotnet build treat projects as though they are type: platform.dotnet publish filter support.dotnet store full implementation.