-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Closed as duplicate of#58968
Closed as duplicate of#58968
Copy link
Labels
area-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesfeature-openapi
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
I was migrating an ASP.NET Core Web API from .NET 8.0
to .NET 9.0
.
As part of the migration, I was replacing AddSwaggerGen()
with AddOpenApi()
and seeing this critical issue. This basically inserts duplicated schema to OpenAPI specification. Solid OpenAPI specification is critical when integrating with services like APIM and hence subject is marked with Critical.
Consider the following minimal reproducible example.
csproj
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="7.2.0" />
</ItemGroup>
</Project>
Startup.cs
namespace WebApplication3;
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddOpenApi();
services.AddControllers();
}
public void Configure(IApplicationBuilder app)
{
app.UseSwaggerUI(x =>
{
x.SwaggerEndpoint("/openapi/v1.json", "My API");
});
app.UseHttpsRedirection();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapOpenApi();
endpoints.MapControllers();
});
}
}
Program.cs
namespace WebApplication3;
public class Program
{
public static void Main(string[] args)
{
IHost host = CreateHostBuilder(args).Build();
host.Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
WeatherForecastController.cs
using Microsoft.AspNetCore.Mvc;
namespace WebApplication3.Controllers;
[ApiController]
[Route("/api/[controller]")]
public class WeatherForecastController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<WeatherForecast>> Get()
{
return Ok();
}
[HttpPost]
public ActionResult<WeatherForecast> Create([FromBody] WeatherForecast weatherForecast)
{
return weatherForecast;
}
}
Up to here, it's pretty standard.
Now carefully review the following WeatherForecast
type.
namespace WebApplication3;
public class WeatherForecast
{
public int Id { get; set; }
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public LocationDto Location { get; set; }
}
public class LocationDto
{
public string Name { get; set; }
public AddressDto Address { get; set; }
}
public class AddressDto
{
string AddressLine { get; set; }
// A circular reference, but not getting any errors
public LocationDto RelatedLocation { get; set; }
}
Note the highlighted schema.
OpenAPI specification
{
"openapi": "3.0.1",
"info": {
"title": "WebApplication3 | v1",
"version": "1.0.0"
},
"servers": [
{
"url": "https://localhost:7286/"
},
{
"url": "http://localhost:5013/"
}
],
"paths": {
"/api/WeatherForecast": {
"get": {
"tags": [
"WeatherForecast"
],
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WeatherForecast"
}
}
},
"application/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WeatherForecast"
}
}
},
"text/json": {
"schema": {
"type": "array",
"items": {
"$ref": "#/components/schemas/WeatherForecast"
}
}
}
}
}
}
},
"post": {
"tags": [
"WeatherForecast"
],
"requestBody": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/WeatherForecast2"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/WeatherForecast2"
}
},
"application/*+json": {
"schema": {
"$ref": "#/components/schemas/WeatherForecast2"
}
}
},
"required": true
},
"responses": {
"200": {
"description": "OK",
"content": {
"text/plain": {
"schema": {
"$ref": "#/components/schemas/WeatherForecast2"
}
},
"application/json": {
"schema": {
"$ref": "#/components/schemas/WeatherForecast2"
}
},
"text/json": {
"schema": {
"$ref": "#/components/schemas/WeatherForecast2"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"AddressDto": {
"type": "object",
"properties": {
"relatedLocation": {
"$ref": "#/components/schemas/LocationDto2"
}
}
},
"AddressDto2": {
"type": "object",
"properties": {
"relatedLocation": {
"$ref": "#/components/schemas/LocationDto4"
}
}
},
"LocationDto": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"address": {
"$ref": "#/components/schemas/AddressDto"
}
}
},
"LocationDto2": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"address": {
"$ref": "#/components/schemas/#/items/properties/location/properties/address"
}
}
},
"LocationDto3": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"address": {
"$ref": "#/components/schemas/AddressDto2"
}
}
},
"LocationDto4": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"address": {
"$ref": "#/components/schemas/#/properties/location/properties/address"
}
}
},
"WeatherForecast": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"date": {
"type": "string",
"format": "date"
},
"temperatureC": {
"type": "integer",
"format": "int32"
},
"location": {
"$ref": "#/components/schemas/LocationDto"
}
}
},
"WeatherForecast2": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"format": "int32"
},
"date": {
"type": "string",
"format": "date"
},
"temperatureC": {
"type": "integer",
"format": "int32"
},
"location": {
"$ref": "#/components/schemas/LocationDto3"
}
}
}
}
},
"tags": [
{
"name": "WeatherForecast"
}
]
}
Expected Behavior
Under components.schemas
, there should be only 3 schemas
- AddressDto
- LocationDto
- WeatherForecast
Steps To Reproduce
Exceptions (if any)
N/A
.NET Version
9.0.200-preview.0.24575.35
Anything else?
N/A
Metadata
Metadata
Assignees
Labels
area-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesfeature-openapi