The following MSBuild properties and items influence the behavior of trimmed self-contained deployments. Some of the options mention
ILLink, which is the name of the underlying tool that implements trimming. For more information about the underlying tool, see the Trimmer documentation.
PublishTrimmed was introduced in .NET Core 3.0. The other options are available only in .NET 5 and above.
Enable trimming during publish. This also turns off trim-incompatible features and enables trim analysis during build.
Place this setting in the project file to ensure that the setting applies during
dotnet build, not just
This setting trims any assemblies that have been configured for trimming. With
Microsoft.NET.Sdk in .NET 6, this includes any assemblies with
[AssemblyMetadata("IsTrimmable", "True")], which is the case for framework assemblies. In .NET 5, framework assemblies from the netcoreapp runtime pack are configured for trimming via
<IsTrimmable> MSBuild metadata. Other SDKs may define different defaults.
The following granularity settings control how aggressively unused IL is discarded. This can be set as a property affecting all trimmer input assemblies, or as metadata on an individual assembly, which overrides the property setting.
Enable member-level trimming, which removes unused members from types. This is the default in .NET 6+.
Enable assembly-level trimming, which will keep an entire assembly if any part of it is used (in a statically understood way).
<IsTrimmable>true</IsTrimmable> metadata but no explicit
TrimMode will use the global
TrimMode. The default
link in .NET 6+, and
copyused in previous versions.
Trim additional assemblies
In .NET 6+,
PublishTrimmed trims assemblies with the following assembly-level attribute:
The framework libraries have this attribute. In .NET 6+, you can also opt in to trimming for a library without this attribute, specifying the assembly by name (without the
<ItemGroup> <TrimmableAssembly Include="MyAssembly" /> </ItemGroup>
This is equivalent to setting MSBuild metadata
<IsTrimmable>true</IsTrimmable> for the assembly in
ManagedAssemblyToLink (see below).
When publishing a trimmed app, the SDK computes an
ManagedAssemblyToLink that represents the set of files to be processed for trimming.
ManagedAssemblyToLink may have metadata that controls the trimming behavior per assembly. To set this metadata, create a target that runs before the built-in
PrepareForILLink target. The following example shows how to enable trimming of
<Target Name="ConfigureTrimming" BeforeTargets="PrepareForILLink"> <ItemGroup> <ManagedAssemblyToLink Condition="'%(Filename)' == 'MyAssembly'"> <IsTrimmable>true</IsTrimmable> </ManagedAssemblyToLink> </ItemGroup> </Target>
You can also use this to override the trimming behavior specified by the library author, by setting
<IsTrimmable>false</IsTrimmable> for an assembly with
Do not add or remove items to/from
ManagedAssemblyToLink, because the SDK computes this set during publish and expects it not to change. The supported metadata is:
Control whether the given assembly is trimmed.
Control the trimming granularity of this assembly. This takes precedence over the global
TrimModeon an assembly implies
Control whether to show single warnings for this assembly.
All assemblies that do not have
<IsTrimmable>true</IsTrimmable> are considered roots for the analysis, which means that they and all of their statically understood dependencies will be kept. Additional assemblies may be "rooted" by name (without the
<ItemGroup> <TrimmerRootAssembly Include="MyAssembly" /> </ItemGroup>
Another way to specify roots for analysis is using an XML file that uses the trimmer descriptor format. This lets you root specific members instead of a whole assembly.
<ItemGroup> <TrimmerRootDescriptor Include="MyRoots.xml" /> </ItemGroup>
MyRoots.xml might root a specific method that is dynamically accessed by the application:
<linker> <assembly fullname="MyAssembly"> <type fullname="MyAssembly.MyClass"> <method name="DynamicallyAccessedMethod" /> </type> </assembly> </linker>
Trimming will remove IL that is not statically reachable. Apps that use reflection or other patterns that create dynamic dependencies may be broken by trimming. To warn about such patterns:
Enable trim analysis warnings.
This will include warnings about the entire app, including your own code, library code, and framework code.
PublishTrimmed in .NET 6+ will also enable a Roslyn analyzer that shows a limited set of analysis warnings. The analyzer may also be enabled or disabled independently of
Enable a Roslyn analyzer for a subset of trim analysis warnings.
Trim analysis respects the
AnalysisLevel property that controls the version of analysis warnings across the SDK. There is another property that controls the version of trim analysis warnings independently (similar to
WarningLevel for the compiler):
Emit only warnings of the given level or lower. This can be
9999to include all warning versions.
Individual warning codes can be suppressed using the usual MSBuild properties respected by the toolchain, including
TreatWarningsAsErrors. There is an additional option that controls the ILLink warn-as-error behavior independently:
Don't treat ILLink warnings as errors. This may be useful to avoid turning trim analysis warnings into errors when treating compiler warnings as errors globally.
Show detailed warnings
In .NET 6+, trim analysis will produce at most one warning for each assembly that comes from a
PackageReference, indicating that the assembly's internals are not compatible with trimming. You can also show individual warnings for all assemblies:
Show all detailed warnings, instead of collapsing them to a single warning per assembly.
The defaults show detailed warnings for the project assembly and
<TrimmerSingleWarn> can also be set as metadata on an individual assembly to control the warning behavior for that assembly only.
Symbols will normally be trimmed to match the trimmed assemblies. You can also remove all symbols:
Remove symbols from the trimmed application, including embedded PDBs and separate PDB files. This applies to both the application code and any dependencies that come with symbols.
The SDK also makes it possible to disable debugger support using the property
DebuggerSupport. When debugger support is disabled, trimming will remove symbols automatically (
TrimmerRemoveSymbols will default to true).
Trimming framework library features
Several feature areas of the framework libraries come with trimmer directives that make it possible to remove the code for disabled features.
Remove code that creates autorelease pools on supported platforms. See AutoreleasePool for managed threads. This is the default for the .NET SDK.
Remove code that enables better debugging experiences. This will also remove symbols.
Remove BinaryFormatter serialization support. For more information, see BinaryFormatter serialization methods are obsolete.
Remove insecure UTF-7 encoding code. For more information, see UTF-7 code paths are obsolete.
Remove EventSource related code or logic.
Remove code related to diagnostics support for System.Net.Http.
Remove globalization-specific code and data. For more information, see Invariant mode.
Remove metadata update specific logic related to hot reload.
Use the default platform implementation of HttpMessageHandler for Android/iOS and remove the managed implementation.
Strip exception messages for
System.*assemblies. When an exception is thrown from a
System.*assembly, the message will be a simplified resource ID instead of the full message.
These properties will cause the related code to be trimmed and will also disable features via the runtimeconfig file. For more information about these properties, including the corresponding runtimeconfig options, see feature switches. Some SDKs may have default values for these properties.
Framework features disabled when trimming
The following features are incompatible with trimming because they require code that is not statically referenced. These are disabled by default in trimmed apps.
Enable these features at your own risk. They are likely to break trimmed apps without extra work to preserve the dynamically referenced code.
Built-in COM support is disabled.
Use of custom resource types is not supported. ResourceManager code paths that use reflection for custom resource types is trimmed.
C++/CLI host activation is disabled.
DesigntimeLicenseContextSerializer use of
BinaryFormatterserialization is disabled.
Running code before
DOTNET_STARTUP_HOOKSis not supported. For more information, see host startup hook.