Skip to content

.NET 5: Null body + content-type with no content-length = validation error even with AllowEmptyInputInBodyModelBinding = true #34980

@JohnGalt1717

Description

@JohnGalt1717

Describe the bug

Even if you set AllowEmptyInputInBodyModelBinding = true it's basically impossible to have a nullable [FromBody] with no value that works across platforms because it still requires the content-length to be set, which browsers won't let you set, and won't set themselves on a null/empty or even "{}" body.

The standards say that if no body is passed you don't need to send the content-length header (for obvious reasons) thus the current implementation is not following standards and validating AllowEmptyInputInBodyModelBinding against the content-length header if and only if it is set when it should be if it is set to 0 or it doesn't exist.

To Reproduce

public async Task<ActionResult<IEnumerable<SubscriptionDto>>> ListSubscriptions(string? contactId = null, [FromBody] LoadCriteriaDto? criteria = null, CancellationToken cancellationToken = default)

This should allow a null criteria property to be received.

This does work with Android because Android allows setting the content-length header so you can set it to 0 if there is no body and still set the content-type = "application/json". (if you don't set the content-type you get a media type not supported even though the body is null which I believe is a separate bug because if the body is null, then the content-type should be null and it shouldn't be testing/validating it.)

As long as the Content-Length header is set on the request, and the body is null/empty then .net will accept the empty body. However as soon as the Content-Length header is not set but the body is null/empty then AllowEmptyInputInBodyModelBinding doesn't take effect and you get a validation error which is not correct and very problematic because all Chromium/Firefox browsers do not set the Content-Length header in this scenario AND you can't set it yourself because it's a protected header thus there is no way to actually send an empty body from a browser and have .NET accept it as an empty body.

Exceptions (if any)

Invaid json token

Proposed Solution:

  1. if AllowEmptyInputInBodyModelBinding = true, and the body is empty/null/{} and the content-length is not set/null then it should still work and not throw a validation error. (you can make this work by injecting middleware that if it sees no Content-length header, adds it to the request pipeline as a work around for now, but that isn't optimal)
  2. If the body is null, and the content-type header is not set, it shouldn't evaluate the media type because the deserializer is immaterial because there is no body and thus nothing to deserialize and combined with No. 1, should work fine with no content-type, no content-length, no body and AllowEmptyInputInBodyModelBinding = true.
  3. The inline FromBody attribute's ability to allow an empty body should also be updated to the same behavior.

Further technical details

  • ASP.Net core 5.0.302

.NET SDK (reflecting any global.json):
Version: 5.0.302
Commit: c005824e35

Runtime Environment:
OS Name: Windows
OS Version: 10.0.22000
OS Platform: Windows
RID: win10-x64
Base Path: C:\Program Files\dotnet\sdk\5.0.302\

Host (useful for support):
Version: 6.0.0-preview.6.21352.12
Commit: 770d630b28

.NET SDKs installed:
5.0.302 [C:\Program Files\dotnet\sdk]
6.0.100-preview.6.21355.2 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
Microsoft.AspNetCore.App 3.1.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.7 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 5.0.8 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.AspNetCore.App 6.0.0-preview.6.21355.2 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 3.1.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 5.0.8 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.NETCore.App 6.0.0-preview.6.21352.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 3.1.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.7 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 5.0.8 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
Microsoft.WindowsDesktop.App 6.0.0-preview.6.21353.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

VS 2019

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-minimalIncludes minimal APIs, endpoint filters, parameter binding, request delegate generator etcarea-mvcIncludes: MVC, Actions and Controllers, Localization, CORS, most templatesfeature-minimal-actionsController-like actions for endpoint routingfeature-model-bindinghelp candidateIndicates that the issues may be a good fit for community to help with. Requires work from eng. team

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions