Skip to content

[OpenApi] .NET 10, XML schema transformer applies property comments on referenced schema #61965

Open
@desjoerd

Description

@desjoerd

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

The generated schema transformer currently applies the comment on a property on a referenced schema instead of as part of the property. It also overwrites the description based on the last property transformed.

Expected Behavior

I would expect that the description of a referenced schema would be solely based on comments on that type. And for properties when it has a comment to generate something like:

"allOf": [
  { "$ref": "#/components/schemas/Address" }
],
"description": "Billing address"

But that removes some simplicity in the schemas, so it could also be that a description is not generated for "$ref" schemas.

Steps To Reproduce

Program.cs

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();

var app = builder.Build();

app.MapPost("/operation", (Company c) =>
{
    throw new NotImplementedException();
}).WithTags();

app.Run();

class Company
{
    /// <summary>
    /// Billing address
    /// </summary>
    public Address BillingAddress { get; set; }

    /// <summary>
    /// Visiting address
    /// </summary>
    public Address VisitingAddress { get; set; }
}

class Address
{
    public string Street { get; set; }
}
.csproj - all default, enable output on build and generate docs
<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <PropertyGroup>
    <GenerateDocumentationFile>true</GenerateDocumentationFile>
    <OpenApiDocumentsDirectory>.</OpenApiDocumentsDirectory>
    <OpenApiGenerateDocumentsOptions>--file-name openapi</OpenApiGenerateDocumentsOptions>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0-preview.4.25258.110" />
    <PackageReference Include="Microsoft.Extensions.ApiDescription.Server"
      Version="10.0.0-preview.4.25258.110">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>
  </ItemGroup>

</Project>

Output:

{
  "openapi": "3.1.1",
  "info": {
    "title": "WebApplication5 | v1",
    "version": "1.0.0"
  },
  "paths": {
    "/operation": {
      "post": {
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Company"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Address": {
        "type": "object",
        "properties": {
          "street": {
            "type": "string"
          }
        },
        "description": "Visiting address"
      },
      "Company": {
        "type": "object",
        "properties": {
          "billingAddress": {
            "$ref": "#/components/schemas/Address"
          },
          "visitingAddress": {
            "$ref": "#/components/schemas/Address"
          }
        }
      }
    }
  }
}

Exceptions (if any)

No response

.NET Version

10.0.100-preview.4.25258.110

Anything else?

Related xml generated code
    [System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.AspNetCore.OpenApi.SourceGenerators, Version=10.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60", "10.0.0.0")]
    file class XmlCommentSchemaTransformer : IOpenApiSchemaTransformer
    {
        public Task TransformAsync(OpenApiSchema schema, OpenApiSchemaTransformerContext context, CancellationToken cancellationToken)
        {
            if (context.JsonPropertyInfo is { AttributeProvider: PropertyInfo propertyInfo })
            {
                if (XmlCommentCache.Cache.TryGetValue(propertyInfo.CreateDocumentationId(), out var propertyComment))
                {
                    schema.Description = propertyComment.Value ?? propertyComment.Returns ?? propertyComment.Summary;
                    if (propertyComment.Examples?.FirstOrDefault() is { } jsonString)
                    {
                        schema.Example = jsonString.Parse();
                    }
                }
            }
            if (XmlCommentCache.Cache.TryGetValue(context.JsonTypeInfo.Type.CreateDocumentationId(), out var typeComment))
            {
                schema.Description = typeComment.Summary;
                if (typeComment.Examples?.FirstOrDefault() is { } jsonString)
                {
                    schema.Example = jsonString.Parse();
                }
            }
            return Task.CompletedTask;
        }
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-openapi

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions