Configure Trim-Safe EF Core
Entity Framework Core relies heavily on runtime reflection and dynamic code compilation to discover model schemas and execute LINQ queries. In trimmed Blazor WebAssembly applications, reflection causes massive WASM payload sizes and introduces runtime crash risks when the IL Linker strips out internal C# entity properties.
Purpose
This skill provides a systematic workflow to optimize and configure EF Core for reflection-free builds, ensuring safety and minimal payloads in trimmed Blazor WebAssembly projects.
Inputs
Before executing this workflow, the agent needs:
- An active Blazor WebAssembly project targeting .NET 9.0/10.0+ using EF Core.
- The
.csprojconfigured for publishing with trimming (<PublishTrimmed>true</PublishTrimmed>). - Installation of the
.NET WebAssembly build toolsworkload on the system.
Workflow
Step 1 — Configure Query Precompilation
Instead of compiling LINQ queries dynamically at runtime, generate static interceptors:
- Run the EF Core optimizer tool to generate compiled model files:
dotnet ef dbcontext optimize --output-dir Persistence/CompiledModels --namespace YourApp.CompiledModels - Modify your DbContext options registration in
Program.csto use the precompiled model:options.UseModel(YourApp.CompiledModels.ContestDbContextModel.Instance);
Checkpoint: Ensure Persistence/CompiledModels is populated with CompiledModel files.
Step 2 — Implement Source-Generated JSON Serialization
To prevent reflection crashes during Entity serialization (common when saving SQLite backups or parsing JSON payloads):
- Declare a partial class inheriting from
JsonSerializerContextand mark all your database entities as serializable:[JsonSerializable(typeof(CategoryEntity))] [JsonSerializable(typeof(EntryEntity))] [JsonSerializable(typeof(RelationEntity))] public partial class EntityJsonContext : JsonSerializerContext { } - Use this context when deserializing payloads to avoid reflection:
var rawBase64 = JsonSerializer.Deserialize(raw, typeof(string), EntityJsonContext.Default);
Checkpoint: All JSON operations on entities are resolved statically at compile time.
Step 3 — Apply Assembly Linker Descriptors
If third-party assemblies throw linker warnings during publish, declare explicit preservation rules:
- Create a
LinkerConfig.xmlfile at the project root. - Instruct the trimmer to preserve database entities:
<linker> <assembly fullname="ContestJudging.Core"> <type fullname="ContestJudging.Core.Entities.*" preserve="all" /> </assembly> </linker> - Include the XML file in your
.csproj:<ItemGroup> <IllinkImportDescriptor Include="LinkerConfig.xml" /> </ItemGroup>
Checkpoint: Critical database model structures are protected from being stripped by the trimmer.
Validation
To verify the trimming configurations are correct:
- Publish the application using the Release configuration:
dotnet publish -c Release - Confirm the compiler outputs zero
IL2026orIL2111warnings during publish evaluation. - Launch the published WASM client in a headless browser test and verify the initial database load succeeds.
Common Pitfalls
| Pitfall | Why It Fails | Correct Approach |
|---|---|---|
Suppressing warnings using [UnconditionalSuppressMessage] |
It hides warnings but does not prevent the trimmer from stripping models, leading to NullReferenceException at runtime. |
Implement compile-time model precompilation and source serialization contexts instead. |
| Using dynamic runtime queries | Trimming strips methods needed to evaluate dynamic query expressions. | Rely solely on statically analyzable LINQ queries. |