创建自定义文件下载。 MD5哈希不匹配

时间:2011-01-12 03:05:45

标签: c# asp.net-mvc download

使用Asp.Net MVC我正在创建一个文件下载器。内置的Asp.Net MVC功能的问题在于它们不能用于非常大的文件下载,在某些浏览器中它们不会弹出另存为对话框。所以我使用msdn http://support.microsoft.com/kb/812406中的一篇文章自己推出。现在的问题是文件下载完美,但MD5校验和不匹配,因为服务器上的文件大小与下载略有不同(即使1000个测试表明下载执行得很好)。这是代码:

public class CustomFileResult : ActionResult
{
    public string File { get; set; }

    public CustomFileResult(string file)
    {
        this.File = file;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        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 name.
        string filename = System.IO.Path.GetFileName(this.File);

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


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

            context.HttpContext.Response.ContentType = "application/octet-stream";
            context.HttpContext.Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);

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

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

                    // Flush the data to the HTML output.
                    context.HttpContext.Response.Flush();

                    buffer = new Byte[10000];
                    dataToRead = dataToRead - length;
                }
                else
                {
                    //prevent infinite loop if user disconnects
                    dataToRead = -1;
                }
            }
        }
        catch (Exception ex)
        {
            // Trap the error, if any.
            context.HttpContext.Response.Write("Error : " + ex.Message);
        }
        finally
        {
            if (iStream != null)
            {
                //Close the file.
                iStream.Close();
            }
            context.HttpContext.Response.Close();
        }
    }
}

执行:

return new CustomFileResult(file.FullName);

4 个答案:

答案 0 :(得分:2)

尝试使用

Response.TransmitFile(string fileName) 

方法

这是非常好的,也有一些东西可以避免OutOfMemory考试。

http://msdn.microsoft.com/en-us/library/12s31dhy(v=vs.80).aspx

答案 1 :(得分:1)

原来问题是缺少标题。

context.HttpContext.Response.AddHeader("Content-Length", iStream.Length.ToString());

添加该标题解决了这个问题。

答案 2 :(得分:0)

一旦开始写入OutputStream,请尝试刷新OutputStream本身而不是刷新响应: context.HttpContext.Response.OutputStream.Flush()

答案 3 :(得分:-1)

你的问题在这里:

length = iStream.Read(buffer, 0, 10000);

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

每个循环读入一个精确10,000字节的缓冲区并将其写入流。这意味着某人下载的每个文件都将是10,000的倍数。因此,如果我要从您的站点下载9,998字节的文件,我得到的文件将是10,000字节。意味着哈希永远不会匹配。我的文件末尾有2个空字节。

您需要添加一项检查以确保要读取的数据量大于> = 10k,如果不是,请将字节大小调整为剩余的确切数量,然后传输。应该修复哈希不匹配

尝试这样的事情:

if (context.HttpContext.Response.IsClientConnected)
{
 // Read the data in buffer.
 if (dataToRead>=10000)
 {
   byte[] buffer = new byte[10000];
   length = 10000
   context.HttpContext.Response.OutputStream.Write(buffer, 0, length);
 }
 else
 {
   byte[] buffer = new byte[dataToRead];
   length = buffer.Length;
   context.HttpContext.Response.OutputStream.Write(buffer, 0, length);  
 }
 // Flush the data to the HTML output.
 context.HttpContext.Response.Flush();

 dataToRead = dataToRead - length;
}