This package provides build infrastructure for trimming the output of an application.
It determines what is used by the application by examining static dependencies of the application binary as well as any directly referenced packages. For any file that is unused it will be removed from the set of files copied to the output and publish folders and removed from the application's dependency file(
deps.json) in the case of a .NET Core application.
Applications which rely on dynamic dependencies, for example using reflection or runtime compilation like ASP.NET MVC, can specify their dynamic dependencies by referencing packages that contain those dependencies or specifying dependent files as roots.
How to use
First install the
Microsoft.Packaging.Tools.Trimming package in your application.
You must use Visual Studio 2017 or later, or .NET Core command-line (CLI) tools 1.0 or later.
From the commandline
/p:TrimUnusedDependencies=true when building the project with either
dotnet build /p:TrimUnusedDependencies=true dotnet publish /p:TrimUnusedDependencies=true msbuild /p:TrimUnusedDependencies=true msbuild /t:Publish /p:TrimUnusedDependencies=true
Important: Specify TrimUnusedDependencies for both build and publish, otherwise build will produce an application that is not trimmed and debugging will run against an untrimmed application that may hide any problems introduced by trimming, like missing dynamic dependencies.
From the IDE or committing the change to your project
In your project (.csproj file) make the following change.
<PropertyGroup> <TrimUnusedDependencies>true</TrimUnusedDependencies> </PropertyGroup>
@(TrimFilesRootFiles) - Additional root files to consider part of the application. See roots.
@(TrimFilesRootPackages) - Additional root packages to consider part of the application. See roots.
@(TrimmableFiles) - Files which should be trimmed from the application. See trimmable.
@(TrimmablePackages) - Packages which should be trimmed from the application. See trimmable.
$(TrimFilesPreferNativeImages) - Prefer a file with the
.ni.dll extension over a file with the
.ni.dll files are native images and significantly larger than a managed assembly but will load faster since they don't need to be JIT compiled. Default is
$(RootPackageReference) - Set to
false to indicate that
PackageReferences should not be considered as roots. Default is
$(RootProjectReference) - Set to
false to indicate that
ProjectReferences should not be considered as roots. Default is
$(TreatMetaPackagesAsTrimmable) - When set to
true indicates that meta-packages (packages without any file assets) should be treated as trimmable. Default is
$(TreatMultiPackagesAsTrimmable) - When set to
true indicates that multi-packages (packages with more than one file asset) should be treated as trimmable unless all files are included. Default is
$(TreatAllPackagesAsTrimmable) - When set to
true indicates that all packages should be treated as trimmable. Default is
false. Note that this has precedence over
TreatMultiPackagesAsTrimmable. Setting this to
true effectively disables all package-graph walking so only static file-dependencies are considered.
$(TrimFilesIncludeRelatedFiles) - When set to
true indicates that related files will be included when the file they are related to is included. Default is
true. See related files.
$(TrimFilesDirectedGraphFile) - Set to the path the dependency graph file will be written in DGML format.
- Specify TrimFilesRootFiles to include file
<ItemGroup> <TrimFilesRootFiles Include="System.IO.Pipes.dll" /> <ItemGroup>
- Specify TrimmablePackages to indicate that the
NuGet.Clientpackage should be considered trimmable and only the files in its closure that are actually used should be included.
<ItemGroup> <TrimmablePackages Include="NuGet.Client" /> <ItemGroup>
- Specify TrimFilesPreferNativeImages to prefer faster and larger native images if they exist.
<PropertyGroup> <TrimFilesPreferNativeImages>true</TrimFilesPreferNativeImages> </PropertyGroup>
- Specify RootPackageReference to avoid rooting packages directly referenced by the project.
<PropertyGroup> <RootPackageReference>false</RootPackageReference> </PropertyGroup>
- Specify RootProjectReference to avoid rooting projects directly referenced by the project.
<PropertyGroup> <RootProjectReference>false</RootProjectReference> </PropertyGroup>
- Specify TrimFilesIncludeRelatedFiles as false to omit related files from the output.
<PropertyGroup> <TrimFilesIncludeRelatedFiles>false</TrimFilesIncludeRelatedFiles> </PropertyGroup>
How it works
The trimming task examines all of the binaries and packages that make up your project and constructs a graph of the two that is related. We start by identifying roots that are included in the application then we traverse the relationships between those to determine if other files or packages should be included in the app.
By default the application is a root, as well as all
PackageReferences from the project file.
The direct packages references may be excluded from the set of roots by specifying the property
Additional file roots may be specified using the
Additional package roots may be specified using the
Files or packages may be treated as trimmable. Essentially this means that when the file or package is encountered while examining dependencies, that file or package will not be included nor will its dependencies unless otherwise referenced.
If a file is trimmable this means that the file will not be included in the application. This takes precedence over all other indirect or direct references, including roots.
If a package is trimmable this means that a package's files will not be included in the application unless those files are directly referenced by another file or as a root.
Additional trimmable files may be specified using the
Additional trimmable packages may be specified using the
Managed assemblies are related to other managed assemblies by assembly references in the compiled assembly. Managed assemblies are related to native libraries by DllImports, P-Invokes, to those libraries.
Adding file relationships explicitly
Not all relationships can be discovered statically. A file may define relationships to other files by placing a text file next to it, with the
.dependencies extension and list other files that it depends on.
foo.dll depends on
somelibrary.dll but that dependency is dynamic. The developer of
foo.dll can specify this dependency by placing a file foo.dll.dependencies next to foo.dll where the content of that file is a single line:
MSBuild locates related files when it resolves assemblies: things like PDBs, XML docs, and pri files. These are defined by AllowedReferenceRelatedFileExtensions and are added by ResolveAssemblyReferences and represented with OriginalItemSpec pointing to the item they were related to. We'll include these related files by default when ever the file they are related to is included.
Packages are related to other packages by dependencies. Files are related to packages if they are contained in a package.
Package relationships are established by the dependencies of a package. In this way if a file (a.dll) has a dynamic dependency on another file (b.dll) which is contained in a package (B), that file may be included in a package (A) with a dependency on the other package (b).
How to identify and fix missing dynamic dependencies
The best way to identify dynamic dependencies is to run your application with trimming enabled and without. If it fails only with trimming enabled then the cause of the failure is likely trimming.
A missing assembly may cause the application to fail with an exception like the following:
Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'AssemblyName, Culture=culture, PublicKeyToken=0123456789abcdef' or one of its dependencies. The system cannot find the file specified.
To fix this you can root the assembly
'AssemblyName, Culture=culture, PublicKeyToken=0123456789abcdef' by adding the following to your project file.
<ItemGroup> <TrimFilesRootFiles Include="AssemblyName.dll" /> <ItemGroup>
A missing native library may cause the application to fail with an exception like the following:
Unhandled Exception: System.DllNotFoundException: Unable to load DLL 'native.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)
To fix this you can root the native library
'native.dll' by adding the following to your project file.
<ItemGroup> <TrimFilesRootFiles Include="native.dll" /> <ItemGroup>
Note: Just because you see these exceptions doesn't necessarily mean trimming is the root cause. If you don't see the exception when running the application with trimming disabled then trimming is the likely cause. If you see the exception when running the application with trimming disabled then the cause could be a missing pre-requisite or an undeclared dependency from some package.