C# 为什么我的异步操作在下载大文件时挂起?

C# 为什么我的异步操作在下载大文件时挂起?,c#,asp.net-mvc,download,async-await,C#,Asp.net Mvc,Download,Async Await,我使用异步操作下载大文件(>500MB)。我下面的代码将挂起我的应用程序,直到文件下载完成 public async Task<ActionResult> Download(string filePath, string fileName) { try { if(!string.IsNullOrEmpty(filePath)) { filePath = Path.C

我使用异步操作下载大文件(>500MB)。我下面的代码将挂起我的应用程序,直到文件下载完成

public async Task<ActionResult> Download(string filePath, string fileName)
    {
        try
        {
            if(!string.IsNullOrEmpty(filePath))
            {
                filePath = Path.Combine(Code.Config.UploadFilesPath(), filePath);
                string contentType = MimeMapping.GetMimeMapping(fileName);

                if (System.IO.File.Exists(filePath))
                {
                    await GetLargeFile(filePath, fileName);
                }
                else
                {
                    return Content("Requested File does not exist");
                }
            }
        }
        catch(Exception ex) { }
        return Content("");
    }

private async Task GetLargeFile(string fullPath, string outFileName)
{
  System.IO.Stream iStream = null;

        // Buffer to read 10K bytes in chunk:
        byte[] buffer = new Byte[10000];

        // Length of the file:
        int length;

        // Total bytes to read:
        long dataToRead;

        // Identify the file to download including its path.
        string filepath = fullPath;

        // Identify the file name.
        string filename = System.IO.Path.GetFileName(filepath);

        try
        {
            // Open the file.
            iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open,
                        System.IO.FileAccess.Read, System.IO.FileShare.Read);


            // Total bytes to read:
            dataToRead = iStream.Length;

            Response.Clear();
            Response.ContentType = MimeMapping.GetMimeMapping(filename);
            Response.AddHeader("content-disposition", "attachment; filename=\"" + outFileName + "\"");
            Response.AddHeader("Content-Length", iStream.Length.ToString());

            // Read the bytes.
            while (dataToRead > 0)
            {
                // Verify that the client is connected.
                if (Response.IsClientConnected)
                {
                    // Read the data in buffer.
                    length = iStream.Read(buffer, 0, 10000);

                    // Write the data to the current output stream.
                    Response.OutputStream.Write(buffer, 0, length);

                    // Flush the data to the output.
                    Response.Flush();

                    buffer = new Byte[10000];
                    dataToRead = dataToRead - length;
                }
                else
                {
                    //prevent infinite loop if user disconnects
                    dataToRead = -1;
                }
            }
        }
        catch (Exception ex)
        {
            throw new ApplicationException(ex.Message);
        }
        finally
        {
            if (iStream != null)
            {
                //Close the file.
                iStream.Close();
            }
            Response.Close();
        }
}
公共异步任务下载(字符串文件路径,字符串文件名)
{
尝试
{
如果(!string.IsNullOrEmpty(文件路径))
{
filePath=Path.Combine(Code.Config.uploadfilepath(),filePath);
字符串contentType=MimeMapping.GetMimeMapping(文件名);
if(System.IO.File.Exists(filePath))
{
等待GetLargeFile(文件路径、文件名);
}
其他的
{
返回内容(“请求的文件不存在”);
}
}
}
捕获(例外情况除外){}
返回内容(“”);
}
专用异步任务GetLargeFile(字符串完整路径、字符串outFileName)
{
System.IO.Stream iStream=null;
//在区块中读取10K字节的缓冲区:
字节[]缓冲区=新字节[10000];
//文件的长度:
整数长度;
//要读取的总字节数:
长数据存储;
//标识要下载的文件,包括其路径。
字符串filepath=fullPath;
//识别文件名。
字符串filename=System.IO.Path.GetFileName(filepath);
尝试
{
//打开文件。
iStream=new System.IO.FileStream(文件路径,System.IO.FileMode.Open,
System.IO.FileAccess.Read、System.IO.FileShare.Read);
//要读取的总字节数:
dataToRead=iStream.Length;
Response.Clear();
Response.ContentType=MimeMapping.GetMimeMapping(文件名);
AddHeader(“内容处置”、“附件;文件名=\”“+outFileName+”\”);
AddHeader(“Content-Length”,iStream.Length.ToString());
//读取字节。
而(数据读取>0)
{
//验证客户端是否已连接。
if(Response.IsClientConnected)
{
//读取缓冲区中的数据。
长度=iStream.Read(缓冲区,0,10000);
//将数据写入当前输出流。
Response.OutputStream.Write(缓冲区,0,长度);
//将数据刷新到输出。
Response.Flush();
缓冲区=新字节[10000];
dataToRead=dataToRead-长度;
}
其他的
{
//如果用户断开连接,防止无限循环
dataToRead=-1;
}
}
}
捕获(例外情况除外)
{
抛出新的ApplicationException(例如消息);
}
最后
{
如果(iStream!=null)
{
//关闭文件。
iStream.Close();
}
Response.Close();
}
}
奇怪的是,如果我在一个全新的Web应用程序上使用与上面相同的代码并下载一个大文件(大约1GB),该应用程序不会挂起,因为我可以在下载过程中切换视图并触发javascript警报功能

但对于我真正的项目,应用程序挂起,直到下载完成

<> P>在配置或其他方面,我应该考虑什么?


是否有任何调试提示可以查看它在全新的应用程序上如何工作,而不是在我的实际项目上?

在web应用程序的上下文中,async只允许为请求提供服务的线程在进入等待状态时返回到线程池。如果线程正在积极地执行工作,例如将文件假脱机到响应中,那么它实际上与运行sync相同


同样,在web应用程序的上下文中,有一个请求和一个响应。客户端发出请求,服务器响应该请求。在这里,该响应是一个文件,无论是否异步,线程都将被绑定,直到响应完成。在发送响应之前,您无法从操作中“返回”。

如果您需要任何帮助
一些代码来读取文件并使用异步IO将其写入循环中的响应流,您需要发布GetLargeFile的代码?向我们展示代码。感谢您的回复。代码更新您在异步方法中没有执行任何异步操作。如果异步方法从不等待,那么简单地将方法标记为
async
将毫无用处,并且该方法将同步运行。这是Web服务器上糟糕的jujuju。对于所有IO交互,请使用基于任务的异步方法和
wait
。@Raghu为什么不自己试一试,如果遇到更多麻烦,请提出新问题?要开始,您的第一个读取操作可能是
length=await-iStream.ReadAsync(缓冲区,0,10000)