-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Closed
Closed
Copy link
Labels
area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-openapi
Milestone
Description
Is there an existing issue for this?
- I have searched the existing issuesTo pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.
Describe the bug
When generating openapi containing Generic types, with a JsonConverterFactory, the same schema is generated for different types.
Given the following minimal example:
using System.Text.Json;
using System.Text.Json.Serialization;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
var app = builder.Build();
app.UseHttpsRedirection();
app.MapOpenApi();
app.MapGet("/", () => new ExampleModel());
app.Run();
public class GenericConverterFactory : JsonConverterFactory
{
public override bool CanConvert(Type typeToConvert) => typeToConvert.GetGenericTypeDefinition() == typeof(GenericValue<>);
public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) => (JsonConverter?)Activator.CreateInstance(typeof(GenericConverter<>).MakeGenericType(typeToConvert.GetGenericArguments()[0]));
}
public class GenericConverter<T> : JsonConverter<GenericValue<T>>
{
public override GenericValue<T> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => throw new NotImplementedException();
public override void Write(Utf8JsonWriter writer, GenericValue<T> value, JsonSerializerOptions options) => throw new NotImplementedException();
}
[JsonConverter(typeof(GenericConverterFactory))]
public readonly struct GenericValue<TId>
{
public TId Id { get; init; }
}
public class ExampleModel
{
public GenericValue<Guid> GuidValue { get; set; }
public GenericValue<string> StringValue { get; set; }
}
I am getting the following openapi:
{
"openapi": "3.0.1",
"info": {
"title": "MinimalApi | v1",
"version": "1.0.0"
},
"paths": {
"/": {
"get": {
"tags": [
"MinimalApi"
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ExampleModel"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"ExampleModel": {
"type": "object",
"properties": {
"guidValue": {
"$ref": "#/components/schemas/GenericValueOfstring"
},
"stringValue": {
"$ref": "#/components/schemas/GenericValueOfstring"
}
}
},
"GenericValueOfstring": { }
}
},
"tags": [
{
"name": "MinimalApi"
}
]
}
There is only one schema generated for the GenericValue, namely GenericValueOfstring
(which is the last defined type). I was expecting GenericValueOfstring
and GenericValueOfGuid
.
Expected Behavior
No response
Steps To Reproduce
No response
Exceptions (if any)
No response
.NET Version
9.0.100
Anything else?
No response
Metadata
Metadata
Assignees
Labels
area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-openapi
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
desjoerd commentedon Nov 28, 2024
After some more investigation, I think this is caused by dotnet/runtime#110241
desjoerd commentedon Nov 28, 2024
After even more investigation, the cause of this is probably fixed in dotnet/runtime#109868. I am fine if someone wants to close this, otherwise I will wait for the next servicing release to test this.
captainsafia commentedon Dec 18, 2024
@desjoerd Thanks for filing this issue and taking the time to investigate it yourself.
I'll keep this open so that we can follow up once the next servicing release comes out.
The reference PR does seem to solve the issue but it would be good to verify that there isn't a confounding issue in Microsoft.AspNetCore.OpenApi that is also causing the problem.
In the meantime, sticking this in the backlog until we verify.
desjoerd commentedon Jan 15, 2025
@captainsafia I just checked with .NET Runtime 9.0.1 and I now get the correct output, a
GenericValueOfGuid
ANDGenericValueOfstring
. So in my opinion this issue can be closed 👍Cyberzim commentedon May 31, 2025
There are still issues when using
JsonConverterFactory
. I am using dotnet v9.0.300The schema is empty for the involved generic type. In my case, I have the following struct defined:
And here is an example of a model using this type:
Without the JsonConverterFactory, I get the correct schema:
As soon as I add the JsonConverterFactory to the JsonOptions in my minimal API, the generated schema for the
OptionalValue<T>
types are empty:desjoerd commentedon May 31, 2025
@Cyberzim you will have to do some unwrapping. I've done that for you with .NET 10 because it has the GetOrCreateSchema method: https://github.com/desjoerd/OptionalValues/blob/feature/net10/examples/OptionalValues.Examples.OpenApi/Program.cs
It's the same for NSwag or Swashbuckle, which I've implemented and published. For .NET 10 I can publish a preview as well if you want.
Edit:
The empty schemas are expected. As aspnetcore does not know the format of your json.
Cyberzim commentedon May 31, 2025
Thank you for sharing this. Unfortunately switching to .NET 10 is not an option for now until it is released. For now, the workaround for me is to just exclude the JsonConverterFactory when generating the OpenAPI specs. I should also note that I have a
IOpenApiSchemaTransformer
for transformingOptionalValue<T>
intoT
.desjoerd commentedon Jul 31, 2025
I see that this is still open. Since 9.0.1 it gives the correct behavior, for generic types without a converter it generates complete schemas and for generic types with a converter empty ones (which are seperate instances so they can be transformed). So I am closing 🙂.
1 remaining item