Using MapGroup() with MapControllers() results in incorrect path in Swagger
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 281
Description
### Is there an existing issue for this?
- [X] I have searched the existing issues
### Describe the bug
When doing this:
```csharp
app.MapGroup("prefix").MapControllers();
```
Assuming there is a `FooController`, the generated OpenAPI spec incorrectly says the path is `/Foo` instead of `/prefix/Foo`:
```
...
paths": {
"/Foo": {
"get": {
"tags": [
"Foo"
],
"responses": {
"200": {
"description": "Success",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
},
"application/json": {
"schema": {
"type": "string"
}
},
"text/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
...
```
Trying to curl both `/Foo` and `/prefix/Foo` shows that the wrong path was generated in the OpenAPI spec:
```
$ curl -f http://localhost:5147/Foo
curl: (22) The requested URL returned error: 404
$ curl -f http://localhost:5147/prefix/Foo
It works!
```
Interestingly, this problem only happens with `MapControllers()` and minimal API endpoints created using `MapGet()` for example don't experience this problem. See the steps to reproduce to see what I mean.
### Expected Behavior
The OpenAPI spec should generate the correct path when using `MapGroup()` with `MapControllers()`.
### Steps To Reproduce
#### Program.cs
```csharp
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddControllers();
var app = builder.Build();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGroup("prefix").MapGet("/Bar", () => "It works!\n");
});
app.MapGroup("prefix").MapControllers();
app.UseSwagger();
app.UseSwaggerUI();
// Print relative paths
var p = app.Services.GetService()!;
foreach (var group in p.ApiDescriptionGroups.Items)
{
foreach (var api in group.Items)
{
Console.WriteLine(api.RelativePath);
}
}
app.Run();
[ApiController]
[Route("[controller]")]
public class FooController : Controller
{
[HttpGet]
public string Get() => "It works!\n";
}
```
```
$ dotnet run
Building...
prefix/Bar
Foo
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5147
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: /home/brian/projects/SwaggerBugExample/SwaggerBugExample
```
```
$ curl -f http://localhost:5147/swagger/v1/swagger.json
{
"openapi": "3.0.1",
"info": {
"title": "SwaggerBugExample",
"version": "1.0"
},
"paths": {
"/Foo": {
"get": {
"tags": [
"Foo"
],
"responses": {
"200": {
"description": "Success",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
},
"application/json": {
"schema": {
"type": "string"
}
},
"text/json": {
"schema": {
"type": "string"
}
}
}
}
}
}
},
"/prefix/Bar": {
"get": {
"tags": [
"SwaggerBugExample"
],
"responses": {
"200": {
"description": "Success",
"content": {
"text/plain": {
"schema": {
"type": "string"
}
}
}
}
}
}
}
},
"components": { }
```
```
$ curl -f http://localhost:5147/Foo
curl: (22) The requested URL returned error: 404
$ curl -f http://localhost:5147/prefix/Foo
It works!
$ curl -f http://localhost:5147/prefix/Bar
It works!
```
### Exceptions (if any)
_No response_
### .NET Version
8.0.401
### Anything else?

Contributor guide
Assessment
This issue has not been assessed yet.