【问题标题】:Unexpected end of stream at Microsoft.AspNetCore.WebUtilities.MultipartReaderStreamMicrosoft.AspNetCore.WebUtilities.MultipartReaderStream 的流意外结束
【发布时间】:2019-10-23 15:22:03
【问题描述】:
System.IO.IOException: Unexpected end of stream.
at Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.<ReadAsync>d__32.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.WebUtilities.StreamHelperExtensions.<DrainAsync>d__2.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.WebUtilities.MultipartReader.<ReadNextSectionAsync>d__14.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at AspNetCoreFileUpload.Controllers.FileUploadController.<Index>d__0.MoveNext() 
in C:\\GitHub\\StackOverflow\\LargeFileUploadController\\FileUploadController.cs:line 29

复制:https://github.com/bigfont/StackOverflow/tree/master/LargeFileUploadController

表格

<form action = ""/FileUpload"" method=""post"" enctype=""multipart/form-data"">
    <label for=""myfile1"">File</label>
    <input type=""file"" name=""myFile1"" />
    <label for=""myfile2"">File</label>
    <input type=""file"" name=""myFile2"" />
    <input type=""submit"" value=""Send"" />
</form>

控制器

public class FileUploadController : Controller
{
    [HttpPost]
    public async Task<IActionResult> Index()
    {
        var boundary = GetBoundary(Request.ContentType);
        var reader = new MultipartReader(boundary, Request.Body);

        try
        {
            var section = await reader.ReadNextSectionAsync();
        }
        catch (System.Exception ex)
        {
            return new OkObjectResult(new { ex = ex.ToString() });
        }

        return new OkObjectResult(new { message = "Done" });
    }

    private static string GetBoundary(string contentType)
    {
        var elements = contentType.Split(' ');
        var element = elements.Where(entry => entry.StartsWith("boundary=")).First();
        var boundary = element.Substring("boundary=".Length);
        // Remove quotes
        if (boundary.Length >= 2 && 
            boundary[0] == '"' && boundary[boundary.Length - 1] == '"')
        {
            boundary = boundary.Substring(1, boundary.Length - 2);
        }
        return boundary;
    }
}

【问题讨论】:

  • 这通常意味着你的边界错误。逐步执行 GetBoundary 并确保它正常工作。还有 Microsoft.Net.Http.Headers.MediaTypeHeaderValue 可以为您解析。

标签: asp.net-core


【解决方案1】:

我最近几乎遇到了同样的异常。我说几乎是因为他们实际上将异常重命名为Unexpected end of Stream, the content may have already been read by another component.,这实际上意味着某些东西已经消耗了正文流。以下变化的 cmets 让我们了解正在发生的事情:

Tratcher commented on Mar 23

...MVC 模型绑定器读取表单并缓冲多部分段 对你来说,所以重新解析请求正文没有意义 多部分阅读器...

那么,问题是如何禁用默认的表单绑定(读取请求表单)?

我在这个Mvc.FileUpload sample 中找到了DisableFormValueModelBindingAttribute 属性,它禁用了表单绑定,它看起来像这样:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class DisableFormValueModelBindingAttribute : Attribute, IResourceFilter
{
    public void OnResourceExecuting(ResourceExecutingContext context)
    {
        var formValueProviderFactory = context.ValueProviderFactories
                .OfType<FormValueProviderFactory>()
                .FirstOrDefault();
        if (formValueProviderFactory != null)
        {
            context.ValueProviderFactories.Remove(formValueProviderFactory);
        }

        var jqueryFormValueProviderFactory = context.ValueProviderFactories
            .OfType<JQueryFormValueProviderFactory>()
            .FirstOrDefault();
        if (jqueryFormValueProviderFactory != null)
        {
            context.ValueProviderFactories.Remove(jqueryFormValueProviderFactory);
        }
    }

    public void OnResourceExecuted(ResourceExecutedContext context)
    {
    }
}

如果您想了解更多信息,可以查看以下内容:

仅供参考 - 如前所述,MVC 模型绑定器读取表单,但在哪里可以找到结果。结果可以在HttpRequest.Form中找到,其中有Files

【讨论】:

    【解决方案2】:

    不知道这是否对您有帮助,但我遇到了类似的问题“流意外结束,内容可能已被另一个组件读取”。

    app.Use(async (context, next) => {
                context.Request.EnableRewind();
                await next();
            });
    

    上面的代码是在 Startup.cs 的配置方法中添加的。

    希望对你有帮助

    【讨论】:

    • 遇到了同样的问题,这解决了!但我真的很想知道为什么以及如何解决它。有人吗?
    • 是否有针对 ASPNET Core 3.0 的更新解决方案?我试过这个,但 Request 没有 EnableRewind 的定义,并且没有关于导入/程序集的建议。我已经尝试过 context.Request.EnableBuffering(),但这要么没有帮助(如果我把它放在 Configure 方法的末尾)或者导致所有请求返回 500 Internal Server 错误(当我把它放在开头时)。
    • @Shaggydog 我通过更改为“EnableBuffering”来编译它,但我仍然遇到同样的异常。使用 Microsoft.AspNetCore.Http; app.Use(async (context, next) => { context.Request.EnableBuffering(); await next(); });
    • @programmerj 是的,我想出了一个。然而,把它放在 Startup.cs Configure 方法中会导致问题。最后,我设法通过创建一个自定义属性公共类 EnableBufferingAttribute 使其工作: Attribute, IResourceFilter {public void OnResourceExecuting(ResourceExecutingContext context) { context.HttpContext.Request.EnableBuffering(); }
    • @Shaggydog 您的代码对我有用,您应该将其发布为答案,以便更容易发现。谢谢!
    【解决方案3】:

    我创建了一个 MemoryStream,从那里复制了流,它的工作就像一个魅力 :) 关键是你不能读取 Stream 两次。但是,MemoryStream 并非如此。当然,您必须确定缩放,我认为这不适用于上传的非常大的文件。我没有测试这个。 我重写了 Microsoft 网站上的示例:enter link description here 这是其中的一部分:

        while (section != null)
    {
        ContentDispositionHeaderValue contentDisposition;
        var hasContentDispositionHeader = ContentDispositionHeaderValue.TryParse(section.ContentDisposition, out contentDisposition);
    
        if (hasContentDispositionHeader)
        {
            if (MultipartRequestHelper.HasFileContentDisposition(contentDisposition))
            {
                var ms = new MemoryStream();
                var fileSection = section.AsFileSection();
                await fileSection.FileStream.CopyToAsync(ms);
                ms.Position = 0;
                documentUpload.Attachments.Add(new SimpleFileInstance { FileName = fileSection.FileName, FileStream = ms });
    
            }
            else if (MultipartRequestHelper.HasFormDataContentDisposition(contentDisposition))
            {
                // Content-Disposition: form-data; name="key"//
                // value
                // Do not limit the key name length here because the 
                // multipart headers length limit is already in effect.
                var key = HeaderUtilities.RemoveQuotes(contentDisposition.Name).Value;
                var encoding = GetEncoding(section);
                using (var streamReader = new StreamReader(
                    section.Body,
                    encoding,
                    detectEncodingFromByteOrderMarks: true,
                    bufferSize: 1024,
                    leaveOpen: true))
                {
                    // The value length limit is enforced by MultipartBodyLengthLimit
                    var value = await streamReader.ReadToEndAsync();
    
                    if (string.Equals(value, "undefined", StringComparison.OrdinalIgnoreCase))
                    {
                        value = string.Empty;
                    }
    
                    formAccumulator.Append(key, value);
    
                    if (formAccumulator.ValueCount > DefaultFormOptions.ValueCountLimit)
                    {
                        throw new InvalidDataException($"Form key count limit {DefaultFormOptions.ValueCountLimit} exceeded.");
                    }
                }
            }
        }
        section = await reader.ReadNextSectionAsync();
    }
    

    documentUpload 是我们进一步处理文件的 DTO。在我们的例子中,一些文档被上传到 SharePoint。

    【讨论】:

      猜你喜欢
      • 2015-11-17
      • 1970-01-01
      • 1970-01-01
      • 2017-05-03
      • 1970-01-01
      • 1970-01-01
      • 2020-08-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多