-
Notifications
You must be signed in to change notification settings - Fork 10.4k
Description
Is there an existing issue for this?
- I have searched the existing issuesTo pick up a draggable item, press the space bar. While dragging, use the arrow keys to move the item. Press space again to drop the item in its new position, or press escape to cancel.
Describe the bug
Returning ObjectResult
from API action with ContentTypes = ["application/json; charset=utf-8"]
results in 406 Not Accepted
.
It fails to match with Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter
due to the ; charset=utf-8
suffix.
By changing it to ContentTypes = ["application/json"]
, it returns 200 OK with JSON response as expected.
Why this happens
NewtonsoftJsonOutputFormatter.CanWriteResult
returns false, because MediaTypeHeaderValue.IsSubsetOf()
and MediaTypeHeaderValue.MatchesParameters() fail to recognize that Accept: application/json
is compatible with Content-Type: application/json; charset=utf-8
Not sure if this is a bug or by design, but I expected it to be able to match regardless of charset - or at least if the charset matched what it would output itself.
Related issue on using IdempotentAPI to cache responses with this content type: ikyriak/IdempotentAPI#78
Sample code
[ApiController]
[Route("[controller]")]
public class FooController : ControllerBase
{
[HttpGet("fail")]
public IActionResult Fail()
{
return new ObjectResult(new
{
Message = """
This will fail with 406 Not Accepted due to unsupported response content type 'application/json; charset=utf-8':
Error message:
No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response.
"""
})
{
ContentTypes = ["application/json; charset=utf-8"],
StatusCode = 200
};
}
[HttpGet("pass")]
public IActionResult Pass()
{
return new ObjectResult(new
{
Message = """
This will succeed due to supported response content type 'application/json'.
"""
})
{
ContentTypes = ["application/json"],
StatusCode = 200
};
}
}
Log output
Key log entries:
Microsoft.AspNetCore.Mvc.Infrastructure.DefaultOutputFormatterSelector[9]
Attempting to select the first output formatter in the output formatters list which supports a content type from the explicitly specified content types 'application/json; charset=utf-8'.
Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[2]
No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response.
Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/1.1 GET http://localhost:5176/foo/fail - 406 0 - 154.7296ms
Full log for GET http://localhost:5176/foo/fail
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
Request starting HTTP/1.1 GET http://localhost:5176/foo/fail - - -
dbug: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[0]
Wildcard detected, all requests with hosts will be allowed.
trce: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[2]
All hosts are allowed.
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1001]
1 candidate(s) found for the request path '/foo/fail'
dbug: Microsoft.AspNetCore.Routing.Matching.DfaMatcher[1005]
Endpoint 'WebApplication2.Controllers.FooController.Fail (WebApplication2)' with route pattern 'Foo/fail' is valid for the request path '/foo/fail'
dbug: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[1]
Request matched endpoint 'WebApplication2.Controllers.FooController.Fail (WebApplication2)'
trce: Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware[8]
The endpoint does not specify the IRequestSizeLimitMetadata.
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
Executing endpoint 'WebApplication2.Controllers.FooController.Fail (WebApplication2)'
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[102]
Route matched with {action = "Fail", controller = "Foo"}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Fail() on controller WebApplication2.Controllers.FooController (WebApplication2).
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
Execution plan of authorization filters (in the following order): None
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
Execution plan of resource filters (in the following order): None
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
Execution plan of action filters (in the following order): Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter (Order: -3000), Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter (Order: -2000)
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
Execution plan of exception filters (in the following order): None
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
Execution plan of result filters (in the following order): Microsoft.AspNetCore.Mvc.Infrastructure.ClientErrorResultFilter (Order: -2000)
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[1]
Executing controller factory for controller WebApplication2.Controllers.FooController (WebApplication2)
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[2]
Executed controller factory for controller WebApplication2.Controllers.FooController (WebApplication2)
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[52]
Action Filter: Before executing OnActionExecuting on filter Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[53]
Action Filter: After executing OnActionExecuting on filter Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[52]
Action Filter: Before executing OnActionExecuting on filter Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[53]
Action Filter: After executing OnActionExecuting on filter Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter.
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[101]
Executing action method WebApplication2.Controllers.FooController.Fail (WebApplication2) - Validation state: Valid
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[103]
Executed action method WebApplication2.Controllers.FooController.Fail (WebApplication2), returned result Microsoft.AspNetCore.Mvc.ObjectResult in 0.4942ms.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[52]
Action Filter: Before executing OnActionExecuted on filter Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[53]
Action Filter: After executing OnActionExecuted on filter Microsoft.AspNetCore.Mvc.Infrastructure.ModelStateInvalidFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[52]
List of registered output formatters, in the following order: Microsoft.AspNetCore.Mvc.Formatters.HttpNoContentOutputFormatter, Microsoft.AspNetCore.Mvc.Formatters.StringOutputFormatter, Microsoft.AspNetCore.Mvc.Formatters.StreamOutputFormatter, Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.DefaultOutputFormatterSelector[4]
No information found on request to perform content negotiation.
dbug: Microsoft.AspNetCore.Mvc.Infrastructure.DefaultOutputFormatterSelector[9]
Attempting to select the first output formatter in the output formatters list which supports a content type from the explicitly specified content types 'application/json; charset=utf-8'.
warn: Microsoft.AspNetCore.Mvc.Infrastructure.ObjectResultExecutor[2]
No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[6]
After executing action result Microsoft.AspNetCore.Mvc.ObjectResult.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[52]
Result Filter: Before executing OnResultExecuted on filter Microsoft.AspNetCore.Mvc.Infrastructure.ClientErrorResultFilter.
trce: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[53]
Result Filter: After executing OnResultExecuted on filter Microsoft.AspNetCore.Mvc.Infrastructure.ClientErrorResultFilter.
info: Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker[105]
Executed action WebApplication2.Controllers.FooController.Fail (WebApplication2) in 55.8371ms
info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
Executed endpoint 'WebApplication2.Controllers.FooController.Fail (WebApplication2)'
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[9]
Connection id "0HN4HQQ1PUQ06" completed keep alive response.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
Request finished HTTP/1.1 GET http://localhost:5176/foo/fail - 406 0 - 154.7296ms
Expected Behavior
Expected GET http://localhost:5176/foo/fail
to return 200 OK, with JSON response.
It returns 406 Not Accepted
with no body.
GET http://localhost:5176/foo/pass
does return 200 OK with JSON response.
Steps To Reproduce
repro-406-notaccepted-when-json-has-charset.zip
- Extract zip
dotnet run
- Call
GET http://localhost:5176/foo/fail
, it returns406 Not Accepted
, but expected 200 OK with JSON body - Call
GET http://localhost:5176/foo/pass
, it returns200 OK
as expected
It also does not help to specify any of these Accept
headers in request:
Accept: application/json; charset=utf-8
Accept: application/json
Accept: application/*
Accept: */*
Exceptions (if any)
No response
.NET Version
8.0.301
Anything else?
Related issues
Versions
ASP.NET Core 8.0.6
.NET SDK:
Version: 8.0.301
Commit: 1a0e9c0300
Workload version: 8.0.300-manifests.011fccd5
MSBuild version: 17.10.4+10fbfbf2e
Runtime Environment:
OS Name: Windows
OS Version: 10.0.22631
OS Platform: Windows
RID: win-x64
Base Path: C:\Program Files\dotnet\sdk\8.0.301\
.NET workloads installed:
[android]
Installation Source: SDK 8.0.300, VS 17.9.34902.65
Manifest Version: 34.0.95/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.android\34.0.95\WorkloadManifest.json
Install Type: Msi
[ios]
Installation Source: SDK 8.0.300, VS 17.9.34902.65
Manifest Version: 17.2.8053/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.ios\17.2.8053\WorkloadManifest.json
Install Type: Msi
[maccatalyst]
Installation Source: SDK 8.0.300, VS 17.9.34902.65
Manifest Version: 17.2.8053/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maccatalyst\17.2.8053\WorkloadManifest.json
Install Type: Msi
[maui-windows]
Installation Source: SDK 8.0.300, VS 17.9.34902.65
Manifest Version: 8.0.21/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.sdk.maui\8.0.21\WorkloadManifest.json
Install Type: Msi
[wasi-experimental]
Installation Source: SDK 8.0.300
Manifest Version: 8.0.6/8.0.100
Manifest Path: C:\Program Files\dotnet\sdk-manifests\8.0.100\microsoft.net.workload.mono.toolchain.current\8.0.6\WorkloadManifest.json
Install Type: Msi
Host:
Version: 8.0.6
Architecture: x64
Commit: 3b8b000a0e
.NET SDKs installed:
5.0.408 [C:\Program Files\dotnet\sdk]
6.0.321 [C:\Program Files\dotnet\sdk]
6.0.423 [C:\Program Files\dotnet\sdk]
7.0.120 [C:\Program Files\dotnet\sdk]
7.0.317 [C:\Program Files\dotnet\sdk]
8.0.106 [C:\Program Files\dotnet\sdk]
8.0.205 [C:\Program Files\dotnet\sdk]
8.0.301 [C:\Program Files\dotnet\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 5.0.17 [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 6.0.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.31 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 7.0.19 [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.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 8.0.6 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 5.0.17 [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 6.0.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.31 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 7.0.19 [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.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 8.0.6 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 5.0.17 [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 6.0.30 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.31 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 7.0.19 [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.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 8.0.6 [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
Activity
[-]Could not find an output formatter based on content negotiation. Accepted types were (['application/json; charset=utf-8'])[/-][+]No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response[/+][-]No output formatter was found for content types 'application/json; charset=utf-8, application/json; charset=utf-8' to write the response[/-][+]No output formatter found when ObjectResult has content type 'application/json; charset=utf-8'[/+][-]No output formatter found when ObjectResult has content type 'application/json; charset=utf-8'[/-][+]406 Not Accepted when returning ObjectResult with content type 'application/json; charset=utf-8'[/+]vanbukin commentedon Jun 20, 2025
The issue stems from
MediaTypeHeaderValue.IsSubsetOf
treating parameters (like charset) as part of the comparison, even thoughapplication/json; charset=utf-8
is semantically equivalent toapplication/json
for the purpose of JSON response formatting.