Unexpected end of Stream, the content may have already been read by another component.
See original GitHub issueI have some weird problem which happens to only 1 user of let’s say 50
When he uploads file there’s Unexpected end of Stream, the content may have already been read by another component. at Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.ReadAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken) at Microsoft.AspNetCore.WebUtilities.StreamHelperExtensions.DrainAsync(Stream stream, ArrayPool1 bytePool, Nullable1 limit, CancellationToken cancellationToken) at Microsoft.AspNetCore.WebUtilities.MultipartReader.ReadNextSectionAsync(CancellationToken cancellationToken) at Microsoft.AspNetCore.Http.Features.FormFeature.InnerReadFormAsync(CancellationToken cancellationToken) at Microsoft.AspNetCore.Mvc.ModelBinding.FormValueProviderFactory.AddValueProviderAsync(ValueProviderFactoryContext context) at Microsoft.AspNetCore.Mvc.ModelBinding.CompositeValueProvider.CreateAsync(ActionContext actionContext, IList1 factories) at Microsoft.AspNetCore.Mvc.ModelBinding.CompositeValueProvider.CreateAsync(ControllerContext controllerContext) at Microsoft.AspNetCore.Mvc.Internal.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<g__Bind|0>d.MoveNext() — End of stack trace from previous location where exception was thrown — at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync() at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextExceptionFilterAsync()
` being thrown
Here’s my endpoint:
[HttpPost]
public async Task<JsonResult> UploadFile(IFormFile file, int type, string otherParam)
The thing is that I have middleware which logs every request, so it is reading requests and setting body position to 0 in order to be able to use request data later
public async Task Invoke(HttpContext ctx)
{
var request = await FormatRequest(ctx.Request, ctx);
Log.Information(request);
await next(ctx);
}
private async Task<string> FormatRequest(HttpRequest request, HttpContext ctx)
{
//This line allows us to set the reader for the request back at the beginning of its stream.
request.EnableRewind();
//We now need to read the request stream. First, we create a new byte[] with the same length as the request stream...
var length = Convert.ToInt32(request.ContentLength);
if (length > 30000)
return $"file of length: {length}";
var buffer = new byte[length];
//...Then we copy the entire request stream into the new buffer.
await request.Body.ReadAsync(buffer, 0, buffer.Length);
//We convert the byte[] into a string using UTF8 encoding...
var bodyAsText = Encoding.UTF8.GetString(buffer);
//..and finally, assign the read body back to the request body, which is allowed because of // EnableRewind()
request.Body.Position = 0;
return $"User: '{ctx?.User?.Identity?.Name}' {Environment.NewLine} {request.Scheme} {request.Host}{request.Path} {Environment.NewLine} {request.QueryString} {Environment.NewLine} {bodyAsText}";
}
I thought that early return in
if (length > 30000)
return $"file of length: {length}";
may cause problems, but when file’s too large, then I’m receiving Request body too large.
I Increased
.UseKestrel(x =>
{
x.Limits.MaxRequestBodySize = 100_000_000;
})
and now I’m able to upload “huge files” fine, so that
if (length > 30000)
return $"file of length: {length}";
isn’t causing this problem, but original problem Unexpected end of Stream, the content may have already been read by another component. still probably remains.
Anybody has an idea what may go wrong? or how to debug that? I’m unable to reproduce it on any (dev/prod/beta) environment., but I see this exception in logs. It only occurs when that user uploads file. AFAIK he’s using Chrome.
.NET Core 2.1
We’re posting those files via JS.
I’ve seen that solution:
But if there was problem with lack of DisableFormValueModelBinding then wouldn’t every upload request fail this way?
Issue Analytics
- State:
- Created 4 years ago
- Reactions:2
- Comments:56 (22 by maintainers)
Top Related StackOverflow Question
I ran into this as well, using the fetch() API on the browser.
First, I POST a form to the current page:
The matching controller (this same endpoint is used without issues when posting forms normally via a submit button):
This results in a HTTP 302 response, as it should. However, fetch() will follow the redirect path but it still appends the Content-Type to the next GET headers:
If I resend the GET without the Content-Type, everything works as it should.
It seems that the Content-Type should be straight up ignored in GET requests, as it should be irrelevant? At least it should result in a 400 instead of 500. Although I think it’s also a bug that fetch() sends that invalid header in the first place.
EDIT: I solved the issue by adding a custom header to the fetch call, and then returning 200 directly if the call came from fetch
Thanks I can reproduce the issue now!