Skip to content

[OpenApi] $ref not generated for identical lists in same class #63096

@BorisGerretzen

Description

@BorisGerretzen

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When I create a class with two List<T> where T is the same for both classes, the second declared list does not get a $ref for the items in the generated OpenApi document. It does not have to be a list, an array or IEnumerable also leads to the same result.

As a concrete example take public record Balance(List<BalanceEntry> Assets, List<BalanceEntry> Liabilities); in the following program.cs file, you can also find this same file in this repository.

using Microsoft.AspNetCore.Http.HttpResults;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddOpenApi();

var app = builder.Build();
app.MapOpenApi();
app.MapGet("/balance", GetBalance);
app.Run();

return;

Ok<Balance> GetBalance()
{
    var balance = new Balance(
        [
            new BalanceEntry("Cash", 1000),
            new BalanceEntry("Stocks", 4000)
        ],
        [
            new BalanceEntry("Credit Card", 2000),
            new BalanceEntry("Loan", 3000)
        ]
    );

    return TypedResults.Ok(balance);
}

public record BalanceEntry(string AccountName, decimal Amount);

public record Balance(List<BalanceEntry> Assets, List<BalanceEntry> Liabilities);

In the generated OpenApi document I get the following, as you can see there is no $ref for liabilities.

      "Balance": {
        "required": [
          "assets",
          "liabilities"
        ],
        "type": "object",
        "properties": {
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BalanceEntry"
            }
          },
          "liabilities": {
            "type": "array",
            "items": { }
          }
        }
      },

In this example I use TypedResults but if you remove that and return the Balance object directly the issue is still there.
This issue occurs when using Microsoft.AspNetCore.OpenApi version 9.0.7. Swashbuckle.AspNetCore.SwaggerGen version 9.0.3 does not have this issue.

I asked this question on StackOverflow as well but I did not get any replies.

Generated OpenApi document

Expected Behavior

Both lists should get the $ref attribute.

Steps To Reproduce

You can find a small project that exhibits this problem here. Run the project and navigate to http://localhost:5045/openapi/v1.json.

Exceptions (if any)

No response

.NET Version

9.0.300

Anything else?

Item Version
.NET SDK 9.0.300
Microsoft.AspNetCore.OpenApi 9.0.7
Microsoft.OpenApi (implicit through Microsoft.AspNetCore.OpenApi ) 1.6.17
Rider (irrelevant I think) 2025.1.3

Output from dotnet --info

.NET SDK:
 Version:           9.0.300
 Commit:            15606fe0a8
 Workload version:  9.0.300-manifests.87b8cca8
 MSBuild version:   17.14.5+edd3bbf37

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.26100
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\9.0.300\

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

 [aspire]
   Installation Source: SDK 9.0.300
   Manifest Version:    8.2.2/8.0.100
   Manifest Path:       C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.aspire\8.2.2\WorkloadManifest.json
   Install Type:              Msi

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

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

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

Configured to use loose manifests when installing new manifests.

Host:
  Version:      9.0.5
  Architecture: x64
  Commit:       e36e4d1a8f

.NET SDKs installed:
  6.0.418 [C:\Program Files\dotnet\sdk]
  8.0.102 [C:\Program Files\dotnet\sdk]
  8.0.201 [C:\Program Files\dotnet\sdk]
  8.0.303 [C:\Program Files\dotnet\sdk]
  9.0.102 [C:\Program Files\dotnet\sdk]
  9.0.200 [C:\Program Files\dotnet\sdk]
  9.0.300 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.13 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 9.0.1 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 9.0.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 9.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 3.1.32 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.11 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.13 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 9.0.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 9.0.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 9.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 6.0.11 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.26 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.13 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 9.0.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 9.0.2 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 9.0.5 [C:\Program Files\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-openapi

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions