Repository navigation
Fix #3217: resolve enum contracts against the underlying type under source generation - #4131
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #4131 +/- ##
==========================================
- Coverage 95.24% 95.20% -0.04%
==========================================
Files 111 111
Lines 4142 4174 +32
Branches 848 853 +5
==========================================
+ Hits 3945 3974 +29
- Misses 197 200 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
🟡 Changes recommended
The fix bypasses nullable-enum-specific converters even when nullable metadata is available.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Fixes nullable enum schema generation with strict source-generated JSON metadata.
Changes:
- Resolves enum serialization against the underlying enum type.
- Adds source-generation coverage for integer, nullable, string, and property enums.
File summaries
| File | Description |
|---|---|
JsonSerializerDataContractResolver.cs |
Uses the effective enum type during serialization. |
JsonSourceGenerationSchemaGeneratorTests.cs |
Adds source-generated enum regression tests. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…ng type under source generation The enum branch of GetDataContractForType unwraps Nullable<T> into effectiveType for everything except the two calls that serialize a sample value, which were still passed the original type. Under a reflection-based resolver that is harmless, because System.Text.Json synthesizes Nullable<T> metadata on demand. Under a source-generated TypeInfoResolver the metadata only exists if some registered type happens to have a TEnum? member, so an optional enum parameter threw NotSupportedException while the document was being generated.
|
The review point is valid and is addressed. The enum contract now serializes against A new test registers a |
11bd6b8 to
a9a7452
Compare
|
Thanks for your contribution @RaphaelFakhri - the changes from this pull request have been published as part of version 10.3.0 📦, which is now available from NuGet.org 🚀 |

Fixes #3217.
The bug as filed no longer reproduces. The mechanism identified in the thread,
OpenApiAnyFactory.CreateFromJsondeserializing to aJsonElementand failing without reflection, went away when that path was replaced byJsonModelFactoryusingJsonNode.Parse, which needs no metadata. With a strict source-generatedTypeInfoResolver, master emits enum values correctly today, both integer and string forms. Nothing guards that, which is part of why the issue stayed open.What is still live is the nullable case, and it is fatal rather than null:
The enum branch of
GetDataContractForTypeunwrapsNullable<T>intoeffectiveTypefor every purpose except the two calls that serialize a sample value, which still receive the originaltype. Under a reflection-based resolver that is invisible, because System.Text.Json synthesizesNullable<T>metadata on demand. Under a source-generated context the metadata exists only if some registered type happens to have aTEnum?member, and an optional enum route or query parameter, which is the shape in the issue, gives it no reason to. So document generation throws.The fix is to pass
effectiveTypeto both.Four tests in a new
JsonSourceGenerationSchemaGeneratorTests, driven by a realJsonSerializerContextset as the soleTypeInfoResolver: an int-backed enum, a nullable int-backed enum, a string enum throughJsonStringEnumConverter<T>, and an enum reached as a property. Against master's source three pass and the nullable one throws with the exception above. With the change,Swashbuckle.AspNetCore.SwaggerGen.Testis 764 passed, 0 failed on net8.0.One thing to say before it gets asked: the identical mismatch exists in the adjacent primitive branch, so
int?andGuid?under source generation have the same latent crash. I tried the same swap there and it broke twelveGenerateSchema_SetsDefault_IfPropertyHasDefaultValueAttributecases, which serialize a null default through the nullable type on purpose. That needs the null-default path handled separately, so this PR is deliberately scoped to the enum branch.