Publishing a C# 15 Domain Model with Native AOT on .NET 11
NimblePros published its Tiles & Tokens sample, which relies on C# 15 unions and closed hierarchies, as a Native AOT binary on the .NET 11 RC1 SDK. The domain and serialization code produced no trimming or AOT warnings, and the native app ran correctly. The publish errors came from a reflection-based converter, an anonymous type and EF Core, which is a useful checklist for anyone planning a Native AOT app.
Key points
- The Windows publish needs the Desktop development with C++ workload; without it, linking fails with a vswhere error.
- The Linux mcr.microsoft.com/dotnet/sdk:11.0.100-rc.1-aot image ships the native toolchain ready to use.
- With PublishAot on, AOT analyzer warnings in every referenced project become errors when TreatWarningsAsErrors is set.
- Unions and closed hierarchies produced no AOT warnings, and source-generated System.Text.Json serialization ran natively.
- Replace anonymous types used with JsonSerializer by named types registered in a source-generated JsonSerializerContext.
- EF Core is not fully Native AOT compatible and needs a compiled model and precompiled queries, plus its own testing.
The team asked whether the C# 15 domain model from its Tiles & Tokens series, built on unions and closed hierarchies, could ship as a Native AOT binary. A Windows publish stopped because the Visual Studio C++ linker workload was missing, so the attempt moved to the Linux -aot SDK container. With warnings treated as errors, the build failed on eight analyzer errors, all from the reflection-based legacy converter, an anonymous type in a Postgres query and EF Core itself.
With warnings allowed through, the whole-program compiler reported nothing for the domain or serialization code, and the resulting binary played, saved and reloaded correctly. The EF Core path was not run under AOT, since it would need a compiled model and precompiled queries. The original post breaks down the analyzer-versus-compiler difference and gives a checklist for a clean publish.
Real-world use
- A worker service or CLI tool that needs fast startup and ships as a single native executable.
- A command-line tool using C# 15 unions and closed hierarchies for its domain, with data access kept out of the AOT binary.
- A team that wants repeatable Native AOT publishes in CI using the -aot SDK container instead of local Visual Studio setups.
Why it matters
Before moving to Native AOT, audit reflection-based serialization and EF Core usage separately, since the new language features themselves did not block the publish.