Description
Description
I'm using conventional routing: I'm programmatically assigning templates to controllers, ie not using [ApiController][Route(" .. ")
but an IApplicationModelConvention
implementation. Also, I have a custom IOutputFormatter
. The bug is that my custom formatter is not always executed: it depends on how my routing is configured. Below is my controller in which I use conventional routing
// controller
public class WeatherForecastConventionRoutingController : ControllerBase
{
[HttpGet] public object Get() => Ok("foobar");
[HttpGet("foos")] public object GetFoos() => NotFound("foobar");
[HttpGet("bars")] public object GetBars() => NotFound();
}
When triggering the first and second actions my formatter is executed. For the last action my custom formatter is entirely skipped.
This behaviour is different when using attribute based routing. In this case, for all three actions below my custom outputter is executed:
[ApiController]
[Route("[controller]"))]
public class WeatherForecastAttributeRoutingController : ControllerBase
{
[HttpGet] public object Get() => Ok("foobar");
[HttpGet("foos")] public object GetFoos() => NotFound("foobar");
[HttpGet("bars")] public object GetBars() => NotFound();
}
This behaviour being different is unexpected and I believe it is a bug.
To Reproduce
Clone this repro repository. Run it and check out and hit the endpoints
/weather-forecast-convention // => "barfoo"
/weather-forecast-convention/foos // => "barfoo"
/weather-forecast-convention/bars // => bug: no content
/weather-forecast-attribute // => "barfoo"
/weather-forecast-attribute/bars // => "barfoo"
/weather-forecast-attribute/foos // => "barfoo"
All of them should return the same output but this is not the case.
Use-case
In case the reader is wondering why this is relevant: I'm working on a framework that implements json:api. We're using conventional routing because we want to programmatically configure routing for better extensibility and at the same time we want to use a custom formatter to add additional error details when an entity is not found.
The work-around for now is to return NotFound(null)
instead of NotFound()
.
Further technical details
.NET Core SDK (reflecting any global.json):
Version: 3.0.100
Commit: 04339c3a26
Runtime Environment:
OS Name: Mac OS X
OS Version: 10.14
OS Platform: Darwin
RID: osx.10.14-x64
Base Path: /usr/local/share/dotnet/sdk/3.0.100/
Host (useful for support):
Version: 3.0.0
Commit: 7d57652f33
.NET Core SDKs installed:
2.1.700 [/usr/local/share/dotnet/sdk]
2.2.301 [/usr/local/share/dotnet/sdk]
3.0.100 [/usr/local/share/dotnet/sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.All 2.1.11 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
Microsoft.AspNetCore.All 2.2.6 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.All]
Microsoft.AspNetCore.App 2.1.11 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 2.2.6 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 3.0.0 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.11 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 2.1.13 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 2.2.6 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 3.0.0 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]