These suggestions are based on hands-on experience migrating a real-world .NET 10 application (ASP.NET Core + SignalR + YamlDotNet) to Native AOT using StaticDeserializerBuilder and YamlDotNet.Analyzers.StaticGenerator.
I’m happy to work on PRs for each of these, pending approval from the YamlDotNet team.
These are just initial suggestions. I’ll create a separate issue for each one that gets approved for work.
1. Publish the Source Generator as a NuGet Package
Problem: YamlDotNet.Analyzers.StaticGenerator is not published to NuGet. Users must build it from source or reference it as a local project.
Impact: This is the single biggest barrier to AOT adoption. Users who want [YamlStaticContext] must clone the YamlDotNet repo and add a <ProjectReference ... OutputItemType="Analyzer" ReferenceOutputAssembly="false" /> to their project. Most users will never discover this workflow.
Suggestion: Publish the analyzer as a NuGet package (as the .csproj already has PackageId and packaging metadata configured), or bundle it inside the main YamlDotNet package under the analyzers/ folder — similar to how System.Text.Json ships its source generator inside the main package.
2. Support required Members in Generated Object Factories
Problem: The source generator emits new T() in StaticObjectFactory.Create(), which fails to compile when T has C# required members (error CS9035).
Impact: The required keyword is idiomatic modern C# (since C# 11) and commonly paired with [Required] from DataAnnotations for validation. Users are forced to remove required and use = null!; defaults, weakening their type contracts.
Suggestion: Detect required properties during source generation and emit object initializer syntax instead of bare new T():
// Current generated code (fails with CS9035):
case "MyType": return new MyType();
// Suggested:
case "MyType": return new MyType() { RequiredProp = default! };
// Or use [SetsRequiredMembers] on generated factory methods
3. Support OrderedDictionary<TKey, TValue> in the Static Context
Problem: The source generator does not handle System.Collections.Generic.OrderedDictionary<TKey, TValue> (introduced in .NET 9). When registered via [YamlSerializable(typeof(OrderedDictionary<string, T>))], the generated code emits the unqualified type name OrderedDictionary without generic arguments, causing error CS0305.
Impact: YAML documents are inherently ordered. OrderedDictionary<K,V> is the natural .NET type for representing ordered YAML mappings. Users must downgrade to Dictionary<K,V> (which only preserves insertion order as an implementation detail, not a contract).
Suggestion: Update the source generator's type name emission to properly handle generic types, including newer BCL types like OrderedDictionary<TKey, TValue>.
4. Built-in Type Converters for Common BCL Types
Problem: StaticDeserializerBuilder does not automatically convert YAML scalars to TimeSpan, IPEndPoint, Uri, or HttpMethod. The reflection-based DeserializerBuilder handles these via ScalarNodeDeserializer using TypeConverter infrastructure, but the static builder lacks these code paths.
Impact: Users must write and register custom IYamlTypeConverter implementations for every non-primitive type. This is boilerplate-heavy and error-prone. A fresh migration required creating TimeSpanConverter, IPEndPointConverter, and HttpMethodConverter — types that "just worked" with the reflection-based deserializer.
Suggestion: Either:
- Ship built-in
IYamlTypeConverter implementations for common BCL types (TimeSpan, DateTimeOffset, DateTime, Uri, IPAddress, IPEndPoint, Guid, Version, HttpMethod, TimeOnly, DateOnly), or
- Have the source generator emit conversion code for types that implement
IParsable<T> or have a TypeConverter, mirroring what ScalarNodeDeserializer does at runtime.
5. Better Error Messages for Unregistered Types
Problem: When a type is not registered in the [YamlStaticContext], the runtime error is:
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
(Parameter 'Unknown type: System.Collections.Generic.OrderedDictionary`2[...]')
Impact: The ArgumentOutOfRangeException type is misleading — it suggests a value range issue rather than a missing type registration. Users unfamiliar with the static context pattern will struggle to diagnose this.
Suggestion: Throw a more descriptive exception, e.g.:
throw new InvalidOperationException(
$"Type '{type.FullName}' is not registered in the YamlDotNet static context. " +
$"Add [YamlSerializable(typeof({type.Name}))] to your static context class.");
6. Roslyn Analyzer Diagnostic for Missing Type Registrations
Problem: If a type used in a [YamlSerializable] class hierarchy is not itself registered in the static context, the error only surfaces at runtime.
Impact: Users discover missing registrations only when the application crashes during deserialization. This defeats the purpose of compile-time source generation.
Suggestion: Add a Roslyn analyzer diagnostic that:
- Walks all registered types' properties recursively
- Emits a warning/error for any property type (or generic argument) that is not also registered in the context
- Example: if
ApplicationConfiguration has a Dictionary<string, PullMonitorConfiguration> property, and Dictionary<string, PullMonitorConfiguration> is not registered, emit a diagnostic at compile time.
7. Document the StaticDeserializerBuilder API Parity Gaps
Problem: The migration from DeserializerBuilder to StaticDeserializerBuilder is not documented. Users discover API differences (missing methods, behavioral changes) only through trial and error.
Impact: The migration path is unclear. The README and wiki focus on the [YamlStaticContext] attribute but don't explain:
- Which
DeserializerBuilder methods are available on StaticDeserializerBuilder
- Which BCL type conversions are lost
- That
required properties break the generated code
- That
OrderedDictionary<K,V> is unsupported
Suggestion: Add a migration guide section in the documentation, structured as:
- Step-by-step:
DeserializerBuilder → StaticDeserializerBuilder
- Table of supported/unsupported builder methods
- Known limitations and workarounds
- Checklist of common issues (required members, generic collections, BCL type converters)
These suggestions are based on hands-on experience migrating a real-world .NET 10 application (ASP.NET Core + SignalR + YamlDotNet) to Native AOT using
StaticDeserializerBuilderandYamlDotNet.Analyzers.StaticGenerator.I’m happy to work on PRs for each of these, pending approval from the YamlDotNet team.
These are just initial suggestions. I’ll create a separate issue for each one that gets approved for work.
1. Publish the Source Generator as a NuGet Package
Problem:
YamlDotNet.Analyzers.StaticGeneratoris not published to NuGet. Users must build it from source or reference it as a local project.Impact: This is the single biggest barrier to AOT adoption. Users who want
[YamlStaticContext]must clone the YamlDotNet repo and add a<ProjectReference ... OutputItemType="Analyzer" ReferenceOutputAssembly="false" />to their project. Most users will never discover this workflow.Suggestion: Publish the analyzer as a NuGet package (as the
.csprojalready hasPackageIdand packaging metadata configured), or bundle it inside the mainYamlDotNetpackage under theanalyzers/folder — similar to howSystem.Text.Jsonships its source generator inside the main package.2. Support
requiredMembers in Generated Object FactoriesProblem: The source generator emits
new T()inStaticObjectFactory.Create(), which fails to compile whenThas C#requiredmembers (error CS9035).Impact: The
requiredkeyword is idiomatic modern C# (since C# 11) and commonly paired with[Required]from DataAnnotations for validation. Users are forced to removerequiredand use= null!;defaults, weakening their type contracts.Suggestion: Detect
requiredproperties during source generation and emit object initializer syntax instead of barenew T():3. Support
OrderedDictionary<TKey, TValue>in the Static ContextProblem: The source generator does not handle
System.Collections.Generic.OrderedDictionary<TKey, TValue>(introduced in .NET 9). When registered via[YamlSerializable(typeof(OrderedDictionary<string, T>))], the generated code emits the unqualified type nameOrderedDictionarywithout generic arguments, causingerror CS0305.Impact: YAML documents are inherently ordered.
OrderedDictionary<K,V>is the natural .NET type for representing ordered YAML mappings. Users must downgrade toDictionary<K,V>(which only preserves insertion order as an implementation detail, not a contract).Suggestion: Update the source generator's type name emission to properly handle generic types, including newer BCL types like
OrderedDictionary<TKey, TValue>.4. Built-in Type Converters for Common BCL Types
Problem:
StaticDeserializerBuilderdoes not automatically convert YAML scalars toTimeSpan,IPEndPoint,Uri, orHttpMethod. The reflection-basedDeserializerBuilderhandles these viaScalarNodeDeserializerusingTypeConverterinfrastructure, but the static builder lacks these code paths.Impact: Users must write and register custom
IYamlTypeConverterimplementations for every non-primitive type. This is boilerplate-heavy and error-prone. A fresh migration required creatingTimeSpanConverter,IPEndPointConverter, andHttpMethodConverter— types that "just worked" with the reflection-based deserializer.Suggestion: Either:
IYamlTypeConverterimplementations for common BCL types (TimeSpan,DateTimeOffset,DateTime,Uri,IPAddress,IPEndPoint,Guid,Version,HttpMethod,TimeOnly,DateOnly), orIParsable<T>or have aTypeConverter, mirroring whatScalarNodeDeserializerdoes at runtime.5. Better Error Messages for Unregistered Types
Problem: When a type is not registered in the
[YamlStaticContext], the runtime error is:Impact: The
ArgumentOutOfRangeExceptiontype is misleading — it suggests a value range issue rather than a missing type registration. Users unfamiliar with the static context pattern will struggle to diagnose this.Suggestion: Throw a more descriptive exception, e.g.:
6. Roslyn Analyzer Diagnostic for Missing Type Registrations
Problem: If a type used in a
[YamlSerializable]class hierarchy is not itself registered in the static context, the error only surfaces at runtime.Impact: Users discover missing registrations only when the application crashes during deserialization. This defeats the purpose of compile-time source generation.
Suggestion: Add a Roslyn analyzer diagnostic that:
ApplicationConfigurationhas aDictionary<string, PullMonitorConfiguration>property, andDictionary<string, PullMonitorConfiguration>is not registered, emit a diagnostic at compile time.7. Document the
StaticDeserializerBuilderAPI Parity GapsProblem: The migration from
DeserializerBuildertoStaticDeserializerBuilderis not documented. Users discover API differences (missing methods, behavioral changes) only through trial and error.Impact: The migration path is unclear. The README and wiki focus on the
[YamlStaticContext]attribute but don't explain:DeserializerBuildermethods are available onStaticDeserializerBuilderrequiredproperties break the generated codeOrderedDictionary<K,V>is unsupportedSuggestion: Add a migration guide section in the documentation, structured as:
DeserializerBuilder→StaticDeserializerBuilder