ILLinker Trimming Configuration Missing Constraint for Generic Type Reflection Metadata
0 reputation · 03 Jul 2020, 19:33 UTC
0 reputation · 03 Jul 2020, 19:33 UTC
The goal is to retain reflection metadata for generic types when using ILLinker trimming with PublishTrimmed=true in .NET 5+ SDKs. The default trimming configuration does not include a rule to preserve System.Reflection.MetadataLoadContext and related generic type metadata, which can cause MissingMethodException or InvalidProgramException at runtime. Developers face an unresolved decision about whether to add a custom trimming descriptor XML file or apply [Preserve] attributes to generic type definitions, balancing size benefits against metadata completeness.
Should a custom trimming descriptor be preferred over [Preserve] attributes for preserving generic type metadata? What level of metadata preservation offers an acceptable trade‑off between binary size and runtime reliability? How can teams verify that the chosen approach does not introduce linker warnings or break trimmed builds?
34775 reputation · 03 Jul 2020, 23:04 UTC
Use a custom trimming descriptor XML file (conventionally ILLink.Descriptors.xml) instead of scattering preservation attributes. A descriptor centralizes policy, works on third‑party assemblies you cannot annotate, and travels with the project in source control. Attributes are appropriate only for code you own where the preservation requirement is intrinsic to the type definition.
Reference it in the project file:
<ItemGroup>
<TrimmerRootDescriptor Include="ILLink.Descriptors.xml" />
</ItemGroup>The legacy [Preserve] attribute is not the standard .NET API. Current SDKs expect [DynamicallyAccessedMembers] on generic type parameters or [DynamicDependency] on members. These feed the static analyzers so the trimmer and IDE agree. Use them only on your types where reflection is a documented contract (e.g., a serializer you ship).
System.Reflection.MetadataLoadContext loads assemblies for inspection‑only reflection. If it appears only in build‑time or design‑time tooling, exclude that assembly from the published output (ExcludeAssets="runtime" or a separate tool project) rather than rooting it. Rooting it in a trimmed app usually indicates a design mismatch.
Preserve all on the specific open‑generic definitions your code activates via reflection (serializers, DI containers, configuration binders). Example descriptor snippet:
<linker>
<assembly fullname="MyApp.Core">
<type fullname="MyApp.Core.Services.IGenericService`1" preserve="all" />
</assembly>
</linker>Rooting entire assemblies or using preserve="all" broadly negates most size savings.
<TrimmerSingleWarn>false</TrimmerSingleWarn> to surface every IL2xxx warning per assembly.<TreatWarningsAsErrors>true</TreatWarningsAsErrors> for the trimmed configuration.Are the MissingMethodException / InvalidProgramException failures reproducible in an untrimmed build? If they only appear when PublishTrimmed=true, trimming is the cause; if they also appear untrimmed, the fix is not a descriptor.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.