Skip to content

Request.ReadFromJsonAsync does not support quoted charset parameter values #61514

@Tragetaschen

Description

@Tragetaschen

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When a client request contains a quoted charset in the content-type header (like application/json; charset="utf-8"), normal model binding works, but reading the JSON body manually with ReadFromJsonAsync generates an internal server error from an exception.

Expected Behavior

ReadFromJsonAsync should be symmetrical with model binding and accept a quoted charset parameter.

Steps To Reproduce

Using the following controller

[ApiController]
public class TestController : ControllerBase
{
    [HttpPost("one")]
    [Consumes("application/json")]
    public int One([FromBody] Model model)
    {
        return model is not null ? 1 : 0;
    }

    [HttpPost("two")]
    [Consumes("application/json")]
    public async Task<int> Two()
    {
        var model = await Request.ReadFromJsonAsync<Model>();
        return model is not null ? 2 : 0;
    }
}

public class Model
{
    public required string Name { get; init; }
}

issue this request to both endpoints:
curl -v -X POST -d '{"name":"a"}' -H 'Content-Type: application/json; charset="utf-8"' https://localhost:…/[one|two].

For one, there'll be a normal response, for two, there is an internal server error. With an unquoted charset=utf-8, both requests succeed.

Exceptions (if any)

      System.InvalidOperationException: Unable to read the request as JSON because the request content type charset '"utf-8"' is not a known encoding.
       ---> System.ArgumentException: '"utf-8"' is not a supported encoding name. For information on defining a custom encoding, see the documentation for the Encoding.RegisterProvider method. (Parameter 'name')
         at System.Text.EncodingTable.InternalGetCodePageFromName(String name)
         at System.Text.EncodingTable.GetCodePageFromName(String name)
         at System.Text.Encoding.GetEncoding(String name)
         at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.GetEncodingFromCharset(StringSegment charset)
         --- End of inner exception stack trace ---
         at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.GetEncodingFromCharset(StringSegment charset)
         at Microsoft.AspNetCore.Http.HttpRequestJsonExtensions.ReadFromJsonAsync[TValue](HttpRequest request, JsonTypeInfo`1 jsonTypeInfo, CancellationToken cancellationToken)
         at QuotedCharset.TestController.Two() in …TestController.cs:line 17
         at lambda_method6(Closure, Object)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
      --- End of stack trace from previous location ---
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
         at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

.NET Version

9.0.201

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templates

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions