-
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 issues
Describe the bug
Issue Summary
When an API endpoint in ASP.NET Core has a FromHeader parameter and the request’s Content-Type is application/x-www-form-urlencoded, ASP.NET Core automatically reads the request body, even if no parameters are bound from the form. This behavior interferes with request forwarding using YARP as the request body can only be read once.
Related code:
form = await request.ReadFormAsync(); |
form = await request.ReadFormAsync(); |
formCollection = await request.ReadFormAsync(); |
Expected Behavior
- Only read the request body if there are parameters bound from the form.
- Provide an option to disable automatic body reading for form requests.
Steps To Reproduce
https://github.com/divyeshio/ModelBindingRepro
- Define a controller method with a FromHeader parameter.
- Send a request with Content-Type: application/x-www-form-urlencoded and a body.
- Observe that ASP.NET Core automatically reads the body.
- Attempt to forward the request using YARP.
- The forwarded request fails because the body has already been consumed.
Exceptions (if any)
RequestBodyClient: The client reported an error when copying the request body.
System.AggregateException: One or more errors occurred. (Sent 0 request content bytes, but Content-Length promised 12.) (Error while copying content to a stream.)
---> System.InvalidOperationException: Sent 0 request content bytes, but Content-Length promised 12.
--- End of inner exception stack trace ---
---> (Inner Exception #1) System.Net.Http.HttpRequestException: Error while copying content to a stream.
---> System.IO.IOException: An error occurred when reading the request body from the client.
---> System.InvalidOperationException: Sent 0 request content bytes, but Content-Length promised 12.
--- End of inner exception stack trace ---
at Yarp.ReverseProxy.Forwarder.StreamCopyHttpContent.SerializeToStreamAsync(Stream stream, TransportContext context, CancellationToken cancellationToken)
at System.Net.Http.HttpContent.<CopyToAsync>g__WaitAsync|56_0(ValueTask copyTask)
--- End of inner exception stack trace ---
at System.Net.Http.HttpContent.<CopyToAsync>g__WaitAsync|56_0(ValueTask copyTask)
at System.Net.Http.HttpConnection.SendRequestContentAsync(HttpRequestMessage request, HttpContentWriteStream stream, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.DiagnosticsHandler.SendAsyncCore(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken)
at Yarp.ReverseProxy.Forwarder.HttpForwarder.SendAsync(HttpContext context, String destinationPrefix, HttpMessageInvoker httpClient, ForwarderRequestConfig requestConfig, HttpTransformer transformer, CancellationToken cancellationToken)
.NET Version
9.0.200
Anything else?
.NET SDK:
Version: 9.0.200
Commit: 90e8b202f2
Workload version: 9.0.200-manifests.b4a8049f
MSBuild version: 17.13.8+cbc39bea8
Runtime Environment:
OS Name: Mac OS X
OS Version: 15.3
OS Platform: Darwin
RID: osx-arm64
Base Path: /usr/local/share/dotnet/sdk/9.0.200/
.NET workloads installed:
There are no installed workloads to display.
Configured to use loose manifests when installing new manifests.
Host:
Version: 9.0.2
Architecture: arm64
Commit: 80aa709f5d
.NET SDKs installed:
9.0.200 [/usr/local/share/dotnet/sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 9.0.2 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 9.0.2 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
Other architectures found:
None
Environment variables:
Not set
global.json file:
Not found