Claude
Skills
Sign in
Back

dotnet-native-aot

Included with Lifetime
$97 forever

Publishing Native AOT. PublishAot, ILLink descriptors, P/Invoke, size optimization, containers.

General

What this skill does


# dotnet-native-aot

Full Native AOT compilation pipeline for .NET 8+ applications: `PublishAot` configuration, ILLink descriptor XML for type preservation, reflection-free coding patterns, P/Invoke considerations, binary size optimization, self-contained deployment with `runtime-deps` base images, and diagnostic analyzers (`EnableAotAnalyzer`/`EnableTrimAnalyzer`).

**Version assumptions:** .NET 8.0+ baseline. Native AOT for ASP.NET Core Minimal APIs and console apps shipped in .NET 8. .NET 9 improved trimming warnings and library compat. .NET 10 enhanced request delegate generator and expanded Minimal API AOT support.

**Scope boundary:** This skill owns general .NET Native AOT compilation -- the publish pipeline, MSBuild configuration, type preservation, P/Invoke, and size optimization. MAUI-specific iOS/Mac Catalyst AOT (publish profiles, platform-specific library compat) -- see [skill:dotnet-maui-aot]. AOT-first application design patterns (source gen over reflection, DI, serialization choices) are in [skill:dotnet-aot-architecture]. Trim-safe library authoring is in [skill:dotnet-trimming]. WASM AOT for Blazor/Uno is in [skill:dotnet-aot-wasm].

**Out of scope:** MAUI iOS/Mac Catalyst AOT pipeline -- see [skill:dotnet-maui-aot]. Source generator authoring (Roslyn API) -- see [skill:dotnet-csharp-source-generators]. DI container patterns -- see [skill:dotnet-csharp-dependency-injection]. Serialization depth -- see [skill:dotnet-serialization]. Container deployment orchestration -- see [skill:dotnet-containers].

Cross-references: [skill:dotnet-aot-architecture] for AOT-first design patterns, [skill:dotnet-trimming] for trim-safe library authoring, [skill:dotnet-aot-wasm] for WebAssembly AOT, [skill:dotnet-maui-aot] for MAUI-specific AOT, [skill:dotnet-containers] for `runtime-deps` base images, [skill:dotnet-serialization] for AOT-safe serialization, [skill:dotnet-csharp-source-generators] for source gen as AOT enabler, [skill:dotnet-csharp-dependency-injection] for AOT-safe DI, [skill:dotnet-native-interop] for general P/Invoke patterns and cross-platform library resolution.

---

## PublishAot Configuration

### Enabling Native AOT

```xml
<!-- App .csproj -->
<PropertyGroup>
  <PublishAot>true</PublishAot>
</PropertyGroup>
```

```bash
# Publish as Native AOT
dotnet publish -c Release -r linux-x64

# Publish for specific targets
dotnet publish -c Release -r win-x64
dotnet publish -c Release -r osx-arm64
```

### MSBuild Properties: Apps vs Libraries

Apps and libraries use different MSBuild properties. Do not mix them.

**For applications** (console apps, ASP.NET Core Minimal APIs):

```xml
<PropertyGroup>
  <!-- Enable Native AOT compilation on publish -->
  <PublishAot>true</PublishAot>

  <!-- Enable analyzers during development (not just publish) -->
  <EnableAotAnalyzer>true</EnableAotAnalyzer>
  <EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>
```

**For libraries** (NuGet packages, shared class libraries):

```xml
<PropertyGroup>
  <!-- Declare the library is AOT-compatible (auto-enables analyzers) -->
  <IsAotCompatible>true</IsAotCompatible>
  <!-- Declare the library is trim-safe (auto-enables trim analyzer) -->
  <IsTrimmable>true</IsTrimmable>
</PropertyGroup>
```

`IsAotCompatible` and `IsTrimmable` automatically enable the AOT and trim analyzers respectively. Do not also set `PublishAot` in library projects -- libraries are not published as standalone executables.

---

## Diagnostic Analyzers

Enable AOT and trim analyzers during development to catch issues before publishing:

```xml
<PropertyGroup>
  <EnableAotAnalyzer>true</EnableAotAnalyzer>
  <EnableTrimAnalyzer>true</EnableTrimAnalyzer>
</PropertyGroup>
```

### Analysis Without Publishing

Run analysis during `dotnet build` without a full publish:

```bash
# Analyze AOT compatibility without publishing
dotnet build /p:EnableAotAnalyzer=true /p:EnableTrimAnalyzer=true

# See per-occurrence warnings (not grouped by assembly)
dotnet build /p:EnableAotAnalyzer=true /p:EnableTrimAnalyzer=true /p:TrimmerSingleWarn=false
```

This reports IL2xxx (trim) and IL3xxx (AOT) warnings without producing a native binary, enabling fast feedback during development.

### Common Diagnostic Codes

| Code | Category | Meaning |
|------|----------|---------|
| IL2026 | Trim | Member has `[RequiresUnreferencedCode]` -- may break after trimming |
| IL2046 | Trim | Trim attribute mismatch between base/derived types |
| IL2057-IL2072 | Trim | Various reflection usage that the trimmer cannot analyze |
| IL3050 | AOT | Member has `[RequiresDynamicCode]` -- generates code at runtime |
| IL3051 | AOT | `[RequiresDynamicCode]` attribute mismatch |

---

## ILLink Descriptors for Type Preservation

When code uses reflection that the trimmer cannot statically analyze, use ILLink descriptor XML to preserve types. **Do not use legacy RD.xml** -- it is a .NET Native/UWP format that is silently ignored by modern .NET AOT.

### ILLink Descriptor XML

```xml
<!-- ILLink.Descriptors.xml -->
<linker>
  <!-- Preserve all public members of a type -->
  <assembly fullname="MyApp">
    <type fullname="MyApp.Models.LegacyConfig" preserve="all" />
    <type fullname="MyApp.Services.PluginLoader">
      <method name="LoadPlugin" />
    </type>
  </assembly>

  <!-- Preserve an entire external assembly -->
  <assembly fullname="IncompatibleLibrary" preserve="all" />
</linker>
```

```xml
<!-- Register in .csproj -->
<ItemGroup>
  <TrimmerRootDescriptor Include="ILLink.Descriptors.xml" />
</ItemGroup>
```

### `[DynamicDependency]` Attribute

For targeted preservation in code (preferred over ILLink XML for small, localized cases):

```csharp
using System.Diagnostics.CodeAnalysis;

// Preserve a specific method
[DynamicDependency(nameof(LegacyConfig.Initialize), typeof(LegacyConfig))]
public void ConfigureApp() { /* ... */ }

// Preserve all public members
[DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(PluginBase))]
public void LoadPlugins() { /* ... */ }
```

### When to Use Which

| Scenario | Approach |
|----------|----------|
| One or two methods/types | `[DynamicDependency]` attribute |
| Entire assembly or many types | ILLink descriptor XML |
| Third-party library not AOT-safe | ILLink descriptor XML or `<TrimmerRootAssembly>` |
| Your own code with analyzed reflection | Refactor to source generators (best long-term) |

---

## Reflection-Free Patterns

Native AOT works best with code that avoids runtime reflection entirely. Replace reflection patterns with compile-time alternatives.

| Reflection Pattern | AOT-Safe Replacement |
|-------------------|---------------------|
| `Activator.CreateInstance<T>()` | Factory method or explicit `new T()` |
| `Type.GetProperties()` for mapping | Mapperly source generator or manual mapping |
| `Assembly.GetTypes()` for DI scanning | Explicit `services.AddScoped<T>()` |
| `JsonSerializer.Deserialize<T>(json)` | `JsonSerializer.Deserialize(json, Context.Default.T)` |
| `MethodInfo.Invoke()` for dispatch | `switch` on type or interface dispatch |

See [skill:dotnet-aot-architecture] for comprehensive AOT-first design patterns.

---

## P/Invoke Considerations

P/Invoke (platform invoke) calls to native libraries generally work with Native AOT, but require attention:

### Direct P/Invoke (Preferred)

```csharp
// Direct P/Invoke -- AOT-compatible, no runtime marshalling overhead
[LibraryImport("libsqlite3", EntryPoint = "sqlite3_open")]
internal static partial int Sqlite3Open(
    [MarshalAs(UnmanagedType.LPStr)] string filename,
    out nint db);
```

Use `[LibraryImport]` (.NET 7+) instead of `[DllImport]` -- it generates marshalling code at compile time via source generators, making it fully AOT-compatible.

### DllImport vs LibraryImport

| Attribute | AOT Compatibility | Marshalling |
|-----------|------------------|-------------|
| `[DllImport]` | Partial -- some marshalling requires runtime codegen | Runtime marshalling |
| `[LibraryImport]` | 
Files: 1
Size: 15.7 KB
Complexity: 18/100
Category: General

Related in General