Configure the Trimmer for ASP.NET Core Blazor
Note
This isn't the latest version of this article. For the current release, see the .NET 9 version of this article.
Warning
This version of ASP.NET Core is no longer supported. For more information, see the .NET and .NET Core Support Policy. For the current release, see the .NET 9 version of this article.
Important
This information relates to a pre-release product that may be substantially modified before it's commercially released. Microsoft makes no warranties, express or implied, with respect to the information provided here.
For the current release, see the .NET 9 version of this article.
This article explains how to control the Intermediate Language (IL) Trimmer when building a Blazor app.
Blazor WebAssembly performs Intermediate Language (IL) trimming to reduce the size of the published output. Trimming occurs when publishing an app.
Configuration
To configure the IL Trimmer, see the Trimming options article in the .NET Fundamentals documentation, which includes guidance on the following subjects:
- Disable trimming for the entire app with the
<PublishTrimmed>
property in the project file. - Control how aggressively unused IL is discarded by the IL Trimmer.
- Stop the IL Trimmer from trimming specific assemblies.
- "Root" assemblies for trimming.
- Surface warnings for reflected types by setting the
<SuppressTrimAnalysisWarnings>
property tofalse
in the project file. - Control symbol trimming and debugger support.
- Set IL Trimmer features for trimming framework library features.
Default trimmer granularity
The default trimmer granularity for Blazor apps is partial
. To trim all assemblies, change the granularity to full
in the app's project file:
<ItemGroup>
<TrimMode>full</TrimMode>
</ItemGroup>
For more information, see Trimming options (.NET documentation).
Failure to preserve types used by a published app
Trimming may have detrimental effects for a published app leading to runtime errors. In apps that use reflection, the IL Trimmer often can't determine the required types for runtime reflection and trims them away or trims away parameter names from methods. This can happen with complex framework types used for JS interop, JSON serialization/deserialization, and other operations.
The IL Trimmer is also unable to react to an app's dynamic behavior at runtime. To ensure the trimmed app works correctly once deployed, test published output frequently while developing.
Consider the following client-side component in a Blazor Web App (ASP.NET Core 8.0 or later) that deserializes a KeyValuePair collection (List<KeyValuePair<string, string>>
):
@rendermode @(new InteractiveWebAssemblyRenderMode(false))
@using System.Diagnostics.CodeAnalysis
@using System.Text.Json
<dl>
@foreach (var item in @items)
{
<dt>@item.Key</dt>
<dd>@item.Value</dd>
}
</dl>
@code {
private List<KeyValuePair<string, string>> items = [];
[StringSyntax(StringSyntaxAttribute.Json)]
private const string data =
"""[{"key":"key 1","value":"value 1"},{"key":"key 2","value":"value 2"}]""";
protected override void OnInitialized()
{
JsonSerializerOptions options = new() { PropertyNameCaseInsensitive = true };
items = JsonSerializer
.Deserialize<List<KeyValuePair<string, string>>>(data, options)!;
}
}
The preceding component executes normally when the app is run locally and produces the following rendered definition list (<dl>
):
key 1
value 1
key 2
value 2
When the app is published, KeyValuePair is trimmed from the app, even in spite of setting the <PublishTrimmed>
property to false
in the project file. Accessing the component throws the following exception:
Unhandled exception rendering component: ConstructorContainsNullParameterNames, System.Collections.Generic.KeyValuePair`2[System.String,System.String]
To address lost types, consider the following approaches.
Preserve the type as a dynamic dependency
We recommend creating a dynamic dependency to preserve the type with the [DynamicDependency]
attribute.
If not already present, add an @using
directive for System.Diagnostics.CodeAnalysis:
@using System.Diagnostics.CodeAnalysis
Add a [DynamicDependency]
attribute to preserve the KeyValuePair:
+ [DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors, typeof(KeyValuePair<string, string>))]
private List<KeyValuePair<string, string>> items = [];
Custom types
The following modifications create a StringKeyValuePair
type for use by the component.
StringKeyValuePair.cs
:
[method: SetsRequiredMembers]
public sealed class StringKeyValuePair(string key, string value)
{
public required string Key { get; init; } = key;
public required string Value { get; init; } = value;
}
The component is modified to use the StringKeyValuePair
type:
- private List<KeyValuePair<string, string>> items = [];
+ private List<StringKeyValuePair> items = [];
- items = JsonSerializer.Deserialize<List<KeyValuePair<string, string>>>(data, options)!;
+ items = JsonSerializer.Deserialize<List<StringKeyValuePair>>(data, options)!;
Because custom types are never trimmed by Blazor when an app is published, the component works as designed after the app is published.
Additional resources
ASP.NET Core