Skip to content

Issue with OpenAPI Documentation Generation When Using [FromQuery] in a Separate Class #61297

@simonkimi

Description

@simonkimi

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

There is an issue with the generation of OpenAPI documentation when using the [FromQuery] attribute inside a separate class. The expected behavior is that when parameters are directly specified in the action method using [FromQuery], the OpenAPI documentation is generated correctly, including the associated descriptions. However, when the [FromQuery] attributes are moved into a separate class (in this case, QueryDto), the descriptions are not recognized in the generated OpenAPI documentation.

Example: Failing Case (Using a Separate DTO Class)

[HttpGet]
public Task<IActionResult> GetWithQueryDto([FromQuery] QueryDto query)
{
    return Task.FromResult<IActionResult>(Ok());
}

public record QueryDto
{
    [Description("Page index")]
    [FromQuery(Name = "p")]
    public int Page { get; init; }

    [Description("Page size")]
    [FromQuery(Name = "s")]
    public int Size { get; init; }

    [Description("Sort by")]
    [FromQuery(Name = "sort")]
    public string SortBy { get; init; }
}

In this case, the descriptions for the QueryDto properties are not reflected in the generated OpenAPI documentation.

"/WeatherForecast/GetWithQueryDto": {
      "get": {
        "tags": [
          "WeatherForecast"
        ],
        "parameters": [
          {
            "name": "p",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "s",
            "in": "query",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }

Expected Behavior

Example: Working Case (Inline Parameters)

[HttpGet]
public Task<IActionResult> GetInline(
    [Description("Page index")] [FromQuery(Name = "p")]
    int page,
    
    [Description("Page size")] [FromQuery(Name = "s")]
    int size,
    
    [Description("Sort by")] [FromQuery(Name = "sort")]
    string sortBy
)
{
    return Task.FromResult<IActionResult>(Ok());
}

In this case, the OpenAPI documentation is generated correctly, including the descriptions for each query parameter.

    "/WeatherForecast/GetInline": {
      "get": {
        "tags": [
          "WeatherForecast"
        ],
        "parameters": [
          {
            "name": "p",
            "in": "query",
            "description": "Page index",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "s",
            "in": "query",
            "description": "Page size",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Sort by",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },

Steps To Reproduce

I have created a minimal demo that can be reproduced. The address is as follows: OpenapiDemo

Exceptions (if any)

No response

.NET Version

9.0.200

Anything else?

Microsoft.AspNetCore.OpenApi: 9.0.3

.NET SDK:
 Version:           9.0.200
 Commit:            90e8b202f2
 Workload version:  9.0.200-manifests.69179adf
 MSBuild version:   17.13.8+cbc39bea8

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.26100
 OS Platform: Windows
 RID:         win-x64
 Base Path:   E:\dotnet\sdk\9.0.200\

.NET workloads installed:
 [android]
   Installation Source: SDK 9.0.200, VS 17.14.35821.62
   Manifest Version:    35.0.39/9.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\9.0.100\microsoft.net.sdk.android\35.0.39\WorkloadManifest.json
   Install Type:              Msi

 [ios]
   Installation Source: SDK 9.0.200, VS 17.14.35821.62
   Manifest Version:    18.2.9180/9.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\9.0.100\microsoft.net.sdk.ios\18.2.9180\WorkloadManifest.json
   Install Type:              Msi

 [maccatalyst]
   Installation Source: SDK 9.0.200, VS 17.14.35821.62
   Manifest Version:    18.2.9180/9.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\9.0.100\microsoft.net.sdk.maccatalyst\18.2.9180\WorkloadManifest.json
   Install Type:              Msi

 [maui-windows]
   Installation Source: SDK 9.0.200, VS 17.14.35821.62
   Manifest Version:    9.0.14/9.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\9.0.100\microsoft.net.sdk.maui\9.0.14\WorkloadManifest.json
   Install Type:              Msi

Configured to use loose manifests when installing new manifests.

Host:
  Version:      9.0.2
  Architecture: x64
  Commit:       80aa709f5d

.NET SDKs installed:
  6.0.404 [E:\dotnet\sdk]
  8.0.100-preview.5.23303.2 [E:\dotnet\sdk]
  9.0.200 [E:\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.23 [E:\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.12 [E:\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.0-preview.5.23302.2 [E:\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.13 [E:\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 9.0.2 [E:\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.23 [E:\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.17 [E:\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.12 [E:\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.0-preview.5.23280.8 [E:\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.7 [E:\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.13 [E:\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 9.0.2 [E:\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 6.0.12 [E:\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.0-preview.5.23302.2 [E:\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.13 [E:\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 9.0.2 [E:\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcfeature-openapigood first issueGood for newcomers.help wantedUp for grabs. We would accept a PR to help resolve this issue

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions