【问题标题】:ASP.NET Overflow or underflow in the arithmetic operation when returning large file bigger 1 GB返回大于 1 GB 的大文件时,算术运算中的 ASP.NET 溢出或下溢
【发布时间】:2014-03-09 22:41:57
【问题描述】:

我在 ASP.NET 中遇到了某种限制。 我将问题简化为 ASP.NET MVC 项目(使用 Visual Studio 2010 和 .NET 4 创建)中的示例项目,但问题仍然存在:

在 MVC 控制器中,我有一个提供文件下载的方法:

public ActionResult DownloadBigFile()
{
    string file = @"C:\Temp\File.txt";
    var readStream = new FileStream(file, FileMode.Open, FileAccess.Read);
    return File(readStream, "text/plain", "FILE");
}

当文件低于 1 GB 时,下载工作正常, 超过 1 GB 时会引发异常:“算术运算中的溢出或下溢”,详细信息如下:

 Overflow or underflow in the arithmetic operation.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArithmeticException: Overflow or underflow in the arithmetic operation.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.

Stack Trace:


[ArithmeticException: Overflow or underflow in the arithmetic operation.]

[HttpException (0x80004005): An error occurred while communicating with the remote host. The error code is 0x80070216.]
   System.Web.Hosting.IIS7WorkerRequest.RaiseCommunicationError(Int32 result, Boolean throwOnDisconnect) +4081269
   System.Web.Hosting.IIS7WorkerRequest.FlushCore(Boolean keepConnected, Int32 numBodyFragments, IntPtr[] bodyFragments, Int32[] bodyFragmentLengths, Int32[] bodyFragmentTypes) +12233777
   System.Web.Hosting.IIS7WorkerRequest.FlushCachedResponse(Boolean isFinal) +847
   System.Web.HttpResponse.UpdateNativeResponse(Boolean sendHeaders) +1110
   System.Web.HttpRuntime.FinishRequestNotification(IIS7WorkerRequest wr, HttpContext context, RequestNotificationStatus& status) +336


Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET  Version:4.0.30319.34009 

该问题是可重现的,但我没有找到有关此行为的任何信息。如何防止此类问题或如何管理大量下载 (> 1GB)?

【问题讨论】:

标签: asp.net arithmeticexception


【解决方案1】:

在 IIS 中禁用缓冲就可以了:

public ActionResult DownloadBigFile()
{
    string file = @"C:\Temp\File.txt";
    var readStream = new FileStream(file, FileMode.Open, FileAccess.Read);
    Response.BufferOutput = false; //<-----
    return File(readStream, "text/plain", "FILE");
}

为什么这不是返回文件时默认的 ASP.Net MVC 行为,这真的让我感到震惊。尤其是在使用流时。

【讨论】:

    【解决方案2】:

    参考资料:

    Download function failing with big file sizes

    How to increase request timeout in IIS?

    https://msdn.microsoft.com/en-us/library/system.web.httpserverutility.scripttimeout%28v=vs.110%29.aspx

    什么对我有用:

                If File.Exists(file2return) Then
                Dim finfo As New FileInfo(file2return)
                Response.Clear()
                Response.Buffer = False
                Response.BufferOutput = False
                Response.ContentType = "application/octet-stream"
                Response.AddHeader("Content-Length", finfo.Length.ToString)
                Response.AddHeader("Content-Disposition", "attachment; filename=" + finfo.Name)
                WriteBytesToResponseBuffered(file2return)
                Response.End()
    

    实际写入流输出的函数:

        Private Sub WriteBytesToResponseBuffered(file2return As String)
        Const MAX_BUFFER As Integer = 1024 ^ 2 ' = 1 048 576 bytes = 2^20 = 1 mebibyte = 1 MiB
        Dim BytesRead As Integer = 0
        Try
            Dim Buffer As Byte() = New Byte(MAX_BUFFER - 1) {}
            Using myFileStream As New FileStream(file2return, FileMode.Open, FileAccess.Read)
                While (InlineAssignHelper(BytesRead, myFileStream.Read(Buffer, 0, MAX_BUFFER))) > 0
                    Response.OutputStream.Write(Buffer, 0, BytesRead)
                End While
            End Using
        Catch ex As Exception
        End Try
    End Sub
    Private Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
        target = value
        Return value
    End Function
    

    web.config 部分: 没有这个,如果服务花费了太多时间,页面的服务将被终止。该参数仅在编译时debug="false"

    有效
      <system.web>
    <httpRuntime executionTimeout="600"/>
    

    建议仅为提供文件的页面更改此值。而不是改变 web.config 把它放在 page_load 上:

    Page.Server.ScriptTimeout = 60 * 20 ' 20 minutes in this case
    

    【讨论】:

      【解决方案3】:

      如果您要保存文件,请执行 OutputStream,因此您必须在 .Save 命令之前的一行禁用缓冲区,如下所示:

                  Response.BufferOutput = false; -- <- Must include this line before the Save method
                  _zip.Save(Response.OutputStream);
                  Response.Flush();
                  Response.End();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-25
        • 1970-01-01
        • 2015-05-25
        • 1970-01-01
        • 2011-05-15
        相关资源
        最近更新 更多