Nota
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare ad accedere o a cambiare directory.
L'accesso a questa pagina richiede l'autorizzazione. Puoi provare a cambiare directory.
Nota
Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 10 di questo articolo.
Avviso
Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere i criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 10 di questo articolo.
Questo articolo spiega come controllare l'IL Trimmer durante la compilazione di un'app Blazor.
Blazor WebAssembly esegue il taglio del linguaggio intermedio (IL) per ridurre le dimensioni dell'output pubblicato. Il trimming si verifica durante la pubblicazione di un'app.
Granularità del trimmer predefinita
La granularità predefinita del trimmer per le applicazioni Blazor è partial, il che significa che vengono ridotte solo le librerie del framework core e le librerie che hanno abilitato esplicitamente il supporto alla riduzione. Il taglio completo non è supportato.
Per altre informazioni, vedere Opzioni di trimming (documentazione di .NET).
Impostazione
Per configurare il trimmer IL, vedere l'articolo Opzioni trimming nella documentazione di .NET Fundamentals, che include indicazioni sugli argomenti seguenti:
- Disabilitare la rifilatura per l'intera app tramite la proprietà
<PublishTrimmed>nel file di progetto. - Controlla come l'IL non utilizzato venga rimosso aggressivamente dal trimmer IL.
- Impedire al trimmer IL di tagliare assembly specifici.
- Assembly "radice" per il taglio.
- Avvisi di superficie per i tipi riflessi impostando la
<SuppressTrimAnalysisWarnings>proprietà sufalsenel file di progetto. - Controllo del taglio dei simboli e supporto del debugger.
- Impostare le funzionalità di Trimmer IL per le funzionalità della libreria del framework di taglio.
Quando la granularità del trimmer è partial, ovvero il valore predefinito, il trimmer IL taglia la libreria di classi di base e tutti gli altri assembly contrassegnati come trimmable. Per acconsentire esplicitamente al taglio in uno dei progetti di libreria di classi dell'app, impostare la <IsTrimmable> proprietà MSBuild su true in tali progetti:
<PropertyGroup>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
Per indicazioni relative alle librerie .NET, vedere Preparare le librerie .NET per il taglio.
Mancata conservazione dei tipi usati da un'app pubblicata
Il trimming può avere effetti negativi per un'app pubblicata che comporta errori di runtime, anche nonostante l'impostazione della <PublishTrimmed> proprietà su false nel file di progetto. Nelle app che usano la reflection, Il Trimmer spesso non riesce a determinare i tipi necessari per la reflection di runtime e li elimina o rimuove i nomi dei parametri dai metodi. Ciò può verificarsi con tipi di framework complessi usati per JS l'interoperabilità, la serializzazione/deserializzazione JSON e altre operazioni.
Anche il trimmer IL non è in grado di reagire al comportamento dinamico di un'app in fase di esecuzione. Per assicurarsi che l'app tagliata funzioni correttamente dopo la distribuzione, testare frequentemente l'output pubblicato durante lo sviluppo.
Si consideri l'esempio seguente che esegue la deserializzazione JSON in una Tuple<T1,T2> raccolta (List<Tuple<string, string>>).
TrimExample.razor:
@page "/trim-example"
@using System.Diagnostics.CodeAnalysis
@using System.Text.Json
<h1>Trim Example</h1>
<ul>
@foreach (var item in @items)
{
<li>@item.Item1, @item.Item2</li>
}
</ul>
@code {
private List<Tuple<string, string>> items = [];
[StringSyntax(StringSyntaxAttribute.Json)]
private const string data =
"""[{"item1":"1:T1","item2":"1:T2"},{"item1":"2:T1","item2":"2:T2"}]""";
protected override void OnInitialized()
{
JsonSerializerOptions options = new() { PropertyNameCaseInsensitive = true };
items = JsonSerializer
.Deserialize<List<Tuple<string, string>>>(data, options)!;
}
}
Il componente precedente viene eseguito normalmente quando l'app viene eseguita in locale e produce l'elenco di rendering seguente:
• 1:T1, 1:T2
• 2:T2, 2:T2
Quando l'app viene pubblicata, Tuple<T1,T2> viene tagliata dall'app, anche nonostante l'impostazione della <PublishTrimmed> proprietà su false nel file di progetto. L'accesso al componente genera l'eccezione seguente:
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: ConstructorContainsNullParameterNames, System.Tuple`2[System.String,System.String]
System.NotSupportedException: ConstructorContainsNullParameterNames, System.Tuple`2[System.String,System.String]
Per risolvere i tipi persi, prendere in considerazione l'adozione di uno degli approcci seguenti.
Tipi personalizzati
Per evitare problemi con il trimming di .NET negli scenari che si basano sulla reflection, come ad esempio JS interop e serializzazione JSON, usare tipi personalizzati definiti nelle librerie non riducibili o preservare i tipi tramite la configurazione con il linker.
Le modifiche seguenti creano un StringTuple tipo per l'uso da parte del componente.
StringTuple.cs:
[method: SetsRequiredMembers]
public sealed class StringTuple(string item1, string item2)
{
public required string Item1 { get; init; } = item1;
public required string Item2 { get; init; } = item2;
}
Il componente viene modificato per usare il StringTuple tipo :
- private List<Tuple<string, string>> items = [];
+ private List<StringTuple> items = [];
- items = JsonSerializer.Deserialize<List<Tuple<string, string>>>(data, options)!;
+ items = JsonSerializer.Deserialize<List<StringTuple>>(data, options)!;
Poiché i tipi personalizzati definiti in assembly non trimmable non vengono eliminati da Blazor durante la pubblicazione di un'app, il componente funziona come progettato dopo la pubblicazione dell'app.
Se si preferisce usare i tipi di framework nonostante la raccomandazione, usare uno degli approcci seguenti:
Se si preferisce usare i tipi di framework nonostante la raccomandazione, mantenere il tipo come dipendenza dinamica.
Mantenere il tipo come dipendenza dinamica
Creare una dipendenza dinamica per mantenere il tipo con l'attributo[DynamicDependency] .
Se non è già presente, aggiungere una @using direttiva per System.Diagnostics.CodeAnalysis:
@using System.Diagnostics.CodeAnalysis
Aggiungi un [DynamicDependency] attributo per preservare Tuple<T1,T2>:
+ [DynamicDependency(DynamicallyAccessedMemberTypes.PublicConstructors,
+ typeof(Tuple<string, string>))]
private List<Tuple<string, string>> items = [];
Usare un descrittore radice
Un descrittore radice può mantenere il tipo.
Aggiungere un ILLink.Descriptors.xml file alla radice dell'app† con il tipo :
<linker>
<assembly fullname="System.Private.CoreLib">
<type fullname="System.Tuple`2" preserve="all" />
</assembly>
</linker>
†La radice dell'app fa riferimento alla radice dell'app Blazor WebAssembly o alla radice del .Client progetto di un Blazor Web App oggetto (.NET 8 o versione successiva).
Aggiungere un TrimmerRootDescriptor elemento al file di progetto dell'app facendo riferimento al ILLink.Descriptors.xml file:
<ItemGroup>
<TrimmerRootDescriptor Include="$(MSBuildThisFileDirectory)ILLink.Descriptors.xml" />
</ItemGroup>
*Il file di progetto è il file di progetto dell'app Blazor WebAssembly o il .Client file di progetto del progetto di un Blazor Web App oggetto (.NET 8 o versione successiva).
Soluzione alternativa in .NET 8
Come soluzione alternativa in .NET 8, è possibile aggiungere la proprietà MSBuild impostata su _ExtraTrimmerArgs nel file di progetto dell'app per mantenere i nomi dei parametri durante il --keep-metadata parametername taglio:
<PropertyGroup>
<_ExtraTrimmerArgs>--keep-metadata parametername</_ExtraTrimmerArgs>
</PropertyGroup>