如何在ServiceStack中传输大型多gig文件?

时间:2015-01-23 23:05:14

标签: c# asp.net servicestack

我正在使用ServiceStack作为我的Web框架,并尝试在管道上发送3 gig文件。下面是我试图用来发送文件的代码。它适用于小文件,但是当我尝试发送大文件时,应用程序会停止并且从不实际发送文件。

    public IHttpResult Any(TilesRequest request)
    {
        var filename = request.Name.ToLower();
        var filePath = HttpContext.Current.Server.MapPath(ConfigLookups.TilesDirectory + filename);
        if (File.Exists(filePath))
        {
            Response.AddHeader("content-disposition", "attachment;filename=" + filename);
            var stream = File.OpenRead(filePath);
            return new HttpResult(stream, "application/x-sqlite3");
        }
        else
        {
            return new HttpError(System.Net.HttpStatusCode.NotFound, "File not found");
        }
    }

我也尝试过:

Response.TransmitFile(filePath);

然后我收到一条错误消息:

  

size参数必须介于0和最大Int32值之间。

关于如何正确发送这么大的文件的任何想法?

1 个答案:

答案 0 :(得分:3)

ServiceStack中的

Response.TransmitFile只委托ASP.NET的TransmitFile,它是有效发送大文件的API - 它使用了一个高效的Win32 API,在其下面从错误描述中看起来只限于2 GB(2 ^ 32)的大小。目前尚不清楚是否在64位操作系统中解除了限制。

ASP.NET强加了其他限制(即ServiceStack本身不会增加任何限制)。此前一个主题显示了一些您可以尝试send large files with ASP.NET的提示。

这也适用于ServiceStack,因为它只是ASP.NET IHttpHandler的包装器。您可以使用以下命令获取基础ASP.NET响应:

var aspResponse = base.Response.OriginalResponse as HttpResponseBase;

内置的ASP.NET httpRuntime请求限制也需要调整。

您还希望禁用缓冲以避免内置的2 ^ 32大小限制。 ASP.NET在启用压缩时默认执行此操作,因此您还要禁用此功能:

<system.webServer>
   <urlCompression doStaticCompression="true" doDynamicCompression="false" />
</system.webServer>

但通常如果你超过2 ^ 32的限制,无论你做什么,你都可能会在ASP.NET中一次性发送这么多数据。

部分内容响应

我正在寻找的流式传输大型文件的解决方案是使用ServiceStack的内置Partial Content Support。而不是在1个请求中流式传输大型文件,而是更改HttpClient以在多个请求中以块的形式获取文件。

物理文件

return new HttpResult(new FileInfo(filePath), request.MimeType); 

内存流

return new HttpResult(ms, "audio/mpeg");

以下是使用HttpUtils获取Partial Content from ServiceStack Services的一些示例,例如:

var url = "{0}/{1}".Fmt(BaseUrl, new TilesRequest { ... }.ToUrl());
var partialBytes = url.GetBytesFromUrl(
    requestFilter: httpReq => httpReq.AddRange(Offset, ChunkSize),
    responseFilter: httpRes => {
        "Content-Length header {0}".Print(
           httpRes.Headers["Content-Length"]);
    });

您需要在循环中执行此操作以将所有部分字节响应拼接在一起。