OpenAPI duplicates a polymorphic union case when the union is used as a property
feature-openapiarea-minimal
### Is there an existing issue for this?
- [x] I have searched the existing issues
### Describe the bug
When a C# union contains a polymorphic type and the union is used as a property of another type, the generated OpenAPI document contains two components for the polymorphic type.
The repro defines:
```csharp
public sealed record Envelope(OneOrManyAnimal? Data);
public union OneOrManyAnimal(Animal, IReadOnlyList<Animal>);
```
`Animal` is a polymorphic base type with `Cat` and `Dog` derived types.
The generated components include both `Animal` and `OneOrManyAnimalAnimal`. The latter is a duplicate of the `Animal` hierarchy. The union uses the duplicate for its single-value case but uses `Animal` for the collection case:
```json
"OneOrManyAnimal": {
"anyOf": [
{
"$ref": "#/components/schemas/OneOrManyAnimalAnimal"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/Animal"
}
}
]
}
```
Returning `OneOrManyAnimal` directly from the endpoint does not produce the duplicate. It appears only when the union is nested in Envelope.
### Expected Behavior
Both union cases should reuse the existing `Animal` component:
```json
"OneOrManyAnimal": {
"anyOf": [
{
"$ref": "#/components/schemas/Animal"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/Animal"
}
}
]
}
```
`OneOrManyAnimalAnimal` should not be generated.
### Steps To Reproduce
Run the following command:
```bash
ASPNETCORE_URLS=http://localhost:5000 dotnet run - <<'EOF'
#:sdk Microsoft.NET.Sdk.Web
#:package Microsoft.AspNetCore.OpenApi@11.0.0-preview.7.26381.103
#:property LangVersion=preview
#:property EnableRequestDelegateGenerator=false
using System.Text.Json.Serialization;
using System.Text.Json.Serialization.Metadata;
var builder = WebApplication.CreateBuilder(args);
builder.Services.ConfigureHttpJsonOptions(options =>
options.SerializerOptions.TypeInfoResolver = new DefaultJsonTypeInfoResolver());
builder.Services.AddOpenApi();
var app = builder.Build();
app.MapOpenApi();
app.MapGet("/animals", () => new Envelope(new OneOrManyAnimal(new Cat("Milo"))));
app.Run();
public sealed record Envelope(OneOrManyAnimal? Data);
public union OneOrManyAnimal(Animal, IReadOnlyList<Animal>);
[JsonPolymorphic(TypeDiscriminatorPropertyName = "type")]
[JsonDerivedType(typeof(Cat), "cats")]
[JsonDerivedType(typeof(Dog), "dogs")]
public abstract record Animal(string Name);
public sealed record Cat(string Name) : Animal(Name);
public sealed record Dog(string Name) : Animal(Name);
EOF
```
In another terminal, inspect the generated document:
```bash
curl --silent http://localhost:5000/openapi/v1.json | jq '.components.schemas | keys'
```
The generated schema components include:
```json
[
"Animal",
"AnimalCat",
"AnimalDog",
"Envelope",
"OneOrManyAnimal",
"OneOrManyAnimalAnimal"
]
```
The duplicate can also be seen directly with:
```bash
curl --silent http://localhost:5000/openapi/v1.json | jq '.components.schemas.OneOrManyAnimal'
```
which returns:
```json
{
"anyOf": [
{
"$ref": "#/components/schemas/OneOrManyAnimalAnimal"
},
{
"type": "array",
"items": {
"$ref": "#/components/schemas/Animal"
}
}
]
}
```
### Exceptions (if any)
_No response_
### .NET Version
11.0.100-preview.7.26381.103
### Anything else?
Microsoft.AspNetCore.OpenApi 11.0.0-preview.7.26381.103
.NET SDK:
Version: 11.0.100-preview.7.26381.103
Commit: e2c1e00b3d
Workload version: 11.0.100-manifests.779dc26a
MSBuild version: 18.10.0-1.26381.103+e2c1e00b3
Runtime Environment:
OS Name: Mac OS X
OS Version: 26.2
OS Platform: Darwin
RID: osx-arm64
Host:
Version: 11.0.0-preview.7.26381.103
Architecture: arm64
Commit: e2c1e00b3d
1 条评论