Owner Swaroop Sridhar
The design of single-file apps in .NET Core 3.0.
In .NET Core 3.0 implements Stage 1 (described in the staging document) support for single-file apps.
Publishing to a single file can be triggered by adding the following property to an application's project file:
<PropertyGroup>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
- The
PublishSingleFile
property applies to both framework dependent and self-contained publish operations. - The
PublishSingleFile
property applies to platform-specific builds with respect to a given runtime-identifier. The output of the build is a native binary for the specified platform. WhenPublishSingleFile
is set totrue
, it is an error to leaveRuntimeIdentifier
undefined, or to setUseAppHost
tofalse
. - Setting the
PublishSingleFile
property causes the managed app, managed dependencies, platform-specific native dependencies, configurations, etc. (basically the contents of the publish directory whendotnet publish
is run without setting the property) to be embedded within the nativeapphost
.
By default, the symbol files are not embedded within the single-file, but remain as separate files in the publish directory. This includes both the IL .pdb
file, and the native .ni.pdb
/ app.guid.map
files generated by ready-to-run compiler. Setting the following property causes the symbol files to be included in the single-file.
<PropertyGroup>
<IncludeSymbolsInSingleFile>true</IncludeSymbolsInSingleFile>
</PropertyGroup>
Certain files can be explicitly excluded from being embedded in the single-file by setting following meta-data:
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
For example, to place some files in the publish directory but not bundle them in the single-file:
<ItemGroup>
<Content Update="*.xml">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
</ItemGroup>
The bundler is a tool that embeds the managed app and its dependencies into the native AppHost
executable, as described here. The bundle layout in .NET Core 3.x is described below.
Bundle Layout (ver 1.0) |
---|
AppHost(Bundle-Marker) |
Embedded Filesapp.dll app.deps.json app.runtimeconfig.json dependency.dll ... |
Bundle Header 1.0 (Version #)#Number of Embedded Files Bundle-ID |
Bundle Manifest For each bundled file: Location (Offset, Size) Type :IL, ReadyToRun, other (This information is not used in 3.0) |
On Startup, the AppHost checks if it has embedded files. If so, it
- Memory maps the entire bundle file.
- Checks if the contents are already extracted to the extraction location (described below)
- If all files are intact in the extraction location, the execution continues reusing the extracted files.
- If not, extract out the missing components
- If an extraction is not available, the host extracts the embedded files to disk as explained in this document.
- Invokes the runtime (through other host components).
For a single-file app, the extraction directory is <base>/<app>/<bundle-id>
-
<base>
isDOTNET_BUNDLE_EXTRACT_BASE_DIR
environment variable, if set.- If not, defaults to:
- Windows:
%TEMP%\.net
- Unix:
${TMPDIR}/.net/${UID}
if${TMPDIR}
is set; otherwise,/var/tmp/.net/${UID}
if/var/tmp
exists, and is writable; otherwise,/tmp/.net/${UID}
if/tmp
exists, and is writable; otherwise fail.
- Windows:
-
<app>
is the name of the single-exe binary -
<bundle-id>
is a unique Bundle-identifier.
Most of the app development can be agnostic to whether the app is published as single-file or not. However, the parts of the app that deal with physical locations of files need to be aware of the single-file packaging.
Assembly.Location
: Returns the actual location within the extraction-location.AppContext.BaseDirectory
: Returns the extraction directory, the location whereapp.dll
resides.
To summarize, here's the overall experience for creating a HelloWorld single-file app
- Create a new HelloWorld app:
HelloWorld$ dotnet new console
-
Normal publish:
dotnet publish
- Publish directory contains the host
HelloWorld.exe
, the appHelloWorld.dll
, configuration filesHelloWorld.deps.json
,HelloWorld.runtimeconfig.json
, and the PDB-fileHelloWorld.pdb
.
- Publish directory contains the host
-
Single-file publish:
dotnet publish -r win10-x64 --self-contained=false /p:PublishSingleFile=true
-
Publish directory contains:
HelloWorld.exe
HelloWorld.pdb
-
HelloWorld.dll
,HelloWorld.deps.json
, andHelloWorld.runtimeconfig.json
are embedded withinHelloWorld.exe
.
-
-
Run:
HelloWorld.exe
- The app runs completely from the single-file, without the need for intermediate extraction to file.
-
Normal publish:
dotnet publish -r win10-x64
- Publish directory contains 221 files including the host, the app, configuration files, the PDB-file and the runtime.
-
Single-file publish:
dotnet publish -r win10-x64 /p:PublishSingleFile=true
- Publish directory contains:
HelloWorld.exe
HelloWorld.pdb
- The remaining 219 files are embedded within the host
HelloWorld.exe
.
- Publish directory contains:
-
Run:
HelloWorld.exe
- On first run, the 219 embedded files will be extracted to disk at startup.
- Subsequent runs of the app will reuse the extraction, without incurring startup overhead.
No difference is expected with respect to debugging and analysis of apps.