Is there an existing issue for this?
Describe the bug
With .net 9, we had Type, Type2, Type3 generated in openapi definition (using Microsoft.Extensions.ApiDescription.Server) - that was buggy but at least tractable.
With .net 10, components are emitted using type name - and not using the type - leading to wrong types being generated if multiple types have same name (not-considering namespace) and completely silently.
Expected Behavior
Components shall be all generated, deduplicated and eventually named with a numbering scheme as before in case of name conflicts.
Steps To Reproduce
OpenApiOneFile.csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<OpenApiDocumentsDirectory>.</OpenApiDocumentsDirectory>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="10.0.0" />
<PackageReference Include="Microsoft.Extensions.ApiDescription.Server" Version="10.0.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
Program.cs
namespace SampleApiOneFile.Models {
public record User {
public required int Id { get; init; }
public required string FirstName { get; init; }
public required string LastName { get; init; }
}
}
namespace SampleApiOneFile.Models.Patch {
public record User {
public string? FirstName { get; init; }
public string? LastName { get; init; }
}
}
namespace SampleApiOneFile.Controllers {
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
[ApiController]
[Route("[controller]")]
public partial class UserController() : ControllerBase {
[HttpGet("{id}")]
public ActionResult<Models.User> Get(int id) {
return new Models.User {
Id = id,
FirstName = $"FirstName {id}",
LastName = $"LastName {id}"
};
}
[HttpPatch("{id}")]
[ProducesResponseType<Models.User>(StatusCodes.Status200OK)]
public ActionResult<Models.User> Update(int id, Models.Patch.User patch) {
return new Models.User {
Id = id,
FirstName = patch.FirstName ?? $"FirstName {id}",
LastName = patch.LastName ?? $"LastName {id}"
};
}
}
}
namespace SampleApiOneFile {
public static class Program {
public static int Main(string[] args) {
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenApi();
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
return 0;
}
}
}
Generated SampleApiOneFile.json (OpenAPI schema):
{
"openapi": "3.1.1",
"info": {
"title": "SampleApiOneFile | v1",
"version": "1.0.0"
},
"paths": {
"/User/{id}": {
"get": {
"tags": [
"User"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/User"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
}
}
},
"patch": {
"tags": [
"User"
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"pattern": "^-?(?:0|[1-9]\\d*)$",
"type": [
"integer",
"string"
],
"format": "int32"
}
}
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/User"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/User"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"User": {
"type": "object",
"properties": {
"firstName": {
"type": [
"null",
"string"
]
},
"lastName": {
"type": [
"null",
"string"
]
}
}
}
}
},
"tags": [
{
"name": "User"
}
]
}
Look at User component definition: it's plain wrong. We shall have here 2 components:
- one for Models.User - with no nullable
- one for Models.Patch.User - with nullable
Exceptions (if any)
No response
.NET Version
10.0.100
Anything else?
macOS 15.7.2
Is there an existing issue for this?
Describe the bug
With .net 9, we had Type, Type2, Type3 generated in openapi definition (using Microsoft.Extensions.ApiDescription.Server) - that was buggy but at least tractable.
With .net 10, components are emitted using type name - and not using the type - leading to wrong types being generated if multiple types have same name (not-considering namespace) and completely silently.
Expected Behavior
Components shall be all generated, deduplicated and eventually named with a numbering scheme as before in case of name conflicts.
Steps To Reproduce
OpenApiOneFile.csproj
Program.cs
Generated SampleApiOneFile.json (OpenAPI schema):
Look at User component definition: it's plain wrong. We shall have here 2 components:
Exceptions (if any)
No response
.NET Version
10.0.100
Anything else?
macOS 15.7.2