Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
(References)
Using the following Model which correctly gets created in the OpenApi.json file:
public sealed record class NotificationDto : RefDto
{
public DateTimeOffset CreatedOn { get; init; }
public bool Viewed { get; init; }
public required NotificationTypes NotificationType { get; init; }
public required string Subject { get; init; }
public string? Body { get; init; }
public string? ImageUrl { get; init; }
public Guid? ItemId { get; init; }
}
This is the definition it creates:
"NotificationDto": {
"required": [
"notificationType",
"subject",
"id"
],
"type": "object",
"properties": {
"createdOn": {
"type": "string",
"format": "date-time"
},
"viewed": {
"type": "boolean"
},
"notificationType": {
"$ref": "#/components/schemas/NotificationTypes"
},
"subject": {
"type": "string"
},
"body": {
"type": "string",
"nullable": true
},
"imageUrl": {
"type": "string",
"nullable": true
},
"itemId": {
"type": "string",
"format": "uuid",
"nullable": true
},
"id": {
"type": "string",
"format": "uuid"
}
}
},
This creates a definition for the enum but the definition for the enum itself is empty:
"NotificationTypes": {
"type": "integer"
},
Here's the NotificationTypes enum:
public enum NotificationTypes
{
General = 0
}
Expected Behavior
This should be the base OpenApi 2 version that just has the text representation AND it should have OneOf syntax like OpenApi 3 has with Type, Enum value and Title (name)
Ideally it should also inject x-ms-enum if you want on enums and give key/values since it's so widely supported by OpenAPI client generators.
Steps To Reproduce
Create an endpoint that returns the above object.
Generate the openapi.json file.
You'll see the bogus output.
Exceptions (if any)
No response
.NET Version
9.0.100-rc.1.24452.12
Anything else?
This also happens with the latest nighly 9.0.0-rtm.24477.5
It did work at one point in the beta process but is broken now. I don't know where it broke.
Also, I have the following that I was using to put in the 3.1 and x-ms-enum functionality:
internal class FixEnumsSchemaTransformer : IOpenApiSchemaTransformer
{
public Task TransformAsync(OpenApiSchema schema, OpenApiSchemaTransformerContext context,
CancellationToken cancellationToken)
{
Console.WriteLine(context.JsonTypeInfo.Type.Name);
if (!schema.Enum.Any())
return Task.CompletedTask;
if (schema.Type != "integer")
return Task.CompletedTask;
var enumType = schema.Enum.First().GetType();
// Add x-ms-enum extension
var enumValues = new OpenApiArray();
enumValues.AddRange(Enum.GetNames(enumType)
.Select(name => new OpenApiObject
{
["name"] = new OpenApiString(name),
["value"] = new OpenApiInteger((int)Enum.Parse(enumType, name)),
["description"] = new OpenApiString(GetEnumDescription(enumType, name))
}));
schema.Extensions["x-ms-enum"] = new OpenApiObject
{
["name"] = new OpenApiString(enumType.Name),
["modelAsString"] = new OpenApiBoolean(false),
["values"] = enumValues
};
// Add enum schemas to OneOf
foreach (var name in Enum.GetNames(enumType))
{
var enumValue = (int)Enum.Parse(enumType, name);
var enumSchema = new OpenApiSchema
{
Type = "integer", Enum = new List<IOpenApiAny> { new OpenApiInteger(enumValue) }, Title = name
};
schema.OneOf.Add(enumSchema);
}
return Task.CompletedTask;
}
private string GetEnumDescription(Type type, string name)
{
var memberInfo = type.GetMember(name).FirstOrDefault();
var attribute = memberInfo?.GetCustomAttribute<DescriptionAttribute>();
return attribute?.Description ?? string.Empty;
}
}
Which also used to work. But it no longer works and if you put a break point in, NotificationTypes is never one of the passed in types (nor is any other enum) yet the output openapi.json does have it listed as if it did process it.