dotnet / dotnet/aspnetcore

OpenAPI: Context.GetOrCreateSchemaAsync used in IOpenApiDocumentTransformer doesnt resolve some references

Open
#67,657 1 comment 0 reactions 1 assignee Claimed by @Youssef1313 View on GitHub
area-minimal feature-openapi investigate
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 10h
Merged PRs (30d)
281

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Describe the bug

Our application has some POCOs that are used over SignalR that we like to include in our openAPI specs so clients can use them, for most classes this isnt necessary because the POCOs are used in a controller so they are exported to the spec already.

To do this we added an attribute that is picked up on by an `IOpenApiDocumentTransformer` that adds the schema to the openAPI spec (`ExtraOpenApiSchemasDocumentTransformer` below).

We've run into an issue where we have two POCOs, `StartCheckinDto` and `StoreCheckinDto`, that both reference an enum `CheckinType`. The `StartCheckinDto` is used in a controller and correctly used a reference for the property it has that is of type `CheckinType`:

Image

The `StoreCheckinDto`, which uses our attribute & document transformer to be included in the schema without being used in a controller, does not use a reference in the spec and instead re-declares the `CheckinType` enum:

Image

I did come across [issue 63598](https://github.com/dotnet/aspnetcore/issues/63598) which seems related, but I'm not quite sure...

Inside of our `IOpenApiDocumentTransformer` I checked and the `x-schema-id` for both the `CheckinType` that is properly declared and referenced by `StartCheckinDto` and the one used while generating the `StoreCheckinDto` match and are both `"CheckinType"`

### Expected Behavior

Both `StartCheckinDto` and `StoreCheckinDto` should reference the same `CheckinType` in the spec

### Steps To Reproduce

Here are the various classes described above:

```
///
/// Adds any entities with the to the
/// OpenAPI Document if they are not present.
///
internal class ExtraOpenApiSchemasDocumentTransformer : IOpenApiDocumentTransformer
{
public async Task TransformAsync(
OpenApiDocument document,
OpenApiDocumentTransformerContext context,
CancellationToken cancellationToken
)
{
document.Components ??= new OpenApiComponents();
document.Components.Schemas ??= new Dictionary();

foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
if (type.GetCustomAttributes(typeof(IncludeInOpenApiSchemaAttribute), true).Length > 0)
{
if (!document.Components.Schemas.ContainsKey(type.Name))
{
var openApiSchema = await context.GetOrCreateSchemaAsync(
type,
null,
cancellationToken
);
document.Components.Schemas.Add(type.Name, openApiSchema);
}
}
}
}
}

public enum CheckinType
{
Shop,
Vend,
}

public class Checkin : BaseEntity
{
public required Guid StoreId { get; set; }

public required Guid CustomerId { get; set; }

public required CheckinType Type { get; set; }
}

public class StartCheckinDto
{
public required Guid CustomerId { get; set; }

public required CheckinType Type { get; set; }
}

[IncludeInOpenApiSchema]
public record StoreCheckinDto
{
public required Guid CheckinId { get; set; }
public required CheckinType CheckinType { get; set; }
public required Guid CustomerId { get; set; }
}
```

### Exceptions (if any)

_No response_

### .NET Version

10.0.103

### Anything else?

`Microsoft.AspNetCore.OpenApi` @ `10.0.9`
`Microsoft.OpenApi` @ `2.9.0`

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.