Preserve attribute vs LinkDescription.xml for reflection types in Xamarin.Forms Release builds
0 reputation · 14 Aug 2021, 12:10 UTC
0 reputation · 14 Aug 2021, 12:10 UTC
A Xamarin.Forms 5.x solution uses types that are only accessed via reflection for DI, JSON serialization, or attribute scanning. The managed linker is typically disabled in Debug and enabled in Release, which can strip metadata that is not statically referenced.
Two documented mitigation approaches exist for this behavior. Applying [Preserve(AllMembers=true)] keeps types and members when the linker runs, but the directives are distributed across source files and require source access and recompilation when new types are added. A custom LinkDescription.xml centralizes preservation rules without source changes, but the file must be maintained manually as dependencies evolve and type name errors are silent.
The constraint is a production build that must preserve reflection targets while keeping configuration maintainable across iOS and Android, with some dependencies from third-party NuGet packages that cannot be modified.
Which approach provides a single source of truth for linker preservation when third-party assemblies lack Preserve annotations? What maintenance trade-offs arise between source-scattered attributes and a centralized XML descriptor as the dependency graph changes? Is there a documented way to confirm completeness of preservation without relying on Release device testing?
35275 reputation · 14 Aug 2021, 17:01 UTC
For third-party assemblies that lack [Preserve] annotations, a centralized LinkDescription.xml is the only practical single source of truth. You cannot annotate NuGet packages without forking them, so source-scattered attributes cannot cover dependencies. Use [Preserve(AllMembers = true)] for your own types where co-location is useful, and use the XML descriptor for cross-cutting rules and third-party types.
Likely explanation: In Release, the managed linker removes metadata that is not statically reachable. DI containers, JSON serializers, and attribute scanners discover types through reflection, so the linker has no static reference to keep and strips those types. This is expected linker behavior, not random stripping.
Confirmed facts: Xamarin.Forms 5.x on classic Xamarin.iOS and Xamarin.Android typically enables the managed linker in Release and disables it in Debug. Preservation rules must match the schema accepted by each platform SDK, and the linker input must be present in the Release build configuration.
LinkDescription.xml listing the third-party types and members accessed only through reflection.[Preserve(AllMembers = true)] to your own reflection-scanned types when you control the source.| Approach | Advantage | Risk as the dependency graph changes |
|---|---|---|
Scattered [Preserve] attributes | Intent lives next to the type and is visible during code review of your own code. | Easy to forget for new types; impossible for third-party NuGet packages without modifying source. |
Centralized LinkDescription.xml | One reviewable file; covers dependencies you cannot edit; single source of truth for global policy. | Wrong full type names are often silent; broad assembly rules can hide missing metadata and increase app size. |
There is no documented static proof that all reflection targets are preserved. The practical substitute is to build with the same Release linker mode locally or in CI, run a reflection smoke test against every expected type, and inspect linker diagnostics for removed or unresolved types. Also confirm the descriptor is consumed by checking the build log for the linker input and the correct platform build action.
Confirm whether your installed SDK accepts the same LinkDescription.xml schema on both iOS and Android, or whether each platform requires a separate linker input. If they differ, the implementation changes from one shared file to two platform-specific inputs. This detail changes the steps, not the recommended approach.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.