WCF REST,流式上传文件和httpRuntime maxRequestLength属性如何实现?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (51)

我创建了一个简单的WCF服务来创建原型文件上传。服务:

[ServiceContract]
public class Service1
{
    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "/Upload")]
    public void Upload(Stream stream)
    {
        using (FileStream targetStream = new FileStream(@"C:\Test\output.txt", FileMode.Create, FileAccess.Write))
        {
            stream.CopyTo(targetStream);
        }
    }
}

它使用webHttpBindingtransferMode设置为“流”和maxReceivedMessageSizemaxBufferPoolSizemaxBufferSize全部设置为2GB。httpRuntime已经maxRequestLength设置为10MB。

客户端通过以下方式发出HTTP请求:

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(@"http://.../Service1.svc/Upload");

request.Method = "POST";
request.SendChunked = true;
request.AllowWriteStreamBuffering = false;
request.ContentType = MediaTypeNames.Application.Octet;

using (FileStream inputStream = new FileStream(@"C:\input.txt", FileMode.Open, FileAccess.Read))
{
    using (Stream outputStream = request.GetRequestStream())
    {
        inputStream.CopyTo(outputStream);
    }
}

现在,最后,什么是错的:

当上传100MB大文件时,服务器返回HTTP 400(错误请求)。我试图启用WCF跟踪,但它没有显示任何错误。当我增加httpRuntimemaxRequestLength到1GB,文件上传没有问题。的MSDN说的是maxRequestLength指定输入流缓冲阈值极限,以KB ”。

这使我相信整个文件(全部100MB)首先存储在“输入流缓冲区”中,然后才可用于Upload服务器上的方法。我实际上可以看到,服务器上的文件大小并没有逐渐增加(正如我所预期的那样),相反,在它创建时它已经是100MB大小了。

问题:我怎样才能使这个工作,以便“输​​入流缓冲区”是相当小(比如1MB),当它溢出时,我的Upload方法被调用?换句话说,我希望上传真正流式传输,无需在任何地方缓冲整个文件。

我现在发现httpRuntime包含另一个在这里相关的设置 - requestLengthDiskThreshold。看来,当输入缓冲区增长超过此阈值时,它不再存储在内存中,而是存储在文件系统中。所以至少整个100MB的大文件不会保留在内存中(这是我最害怕的),但是,我仍然想知道是否有某种方法可以完全避免这个缓冲区

提问于
用户回答回答于

如果使用.NET 4并在IIS7 +中托管服务,则可能会影响到以下博客文章中描述的ASP.NET错误:

http://blogs.microsoft.co.il/blogs/idof/archive/2012/01/17/what-s-new-in-wcf-4-5-improved-streaming-in-iis-hosting.aspx

基本上,对于流式传输的请求,IIS中的ASP.NET处理程序会在将控制权移交给WCF之前缓冲整个请求。这个处理程序服从的maxRequestLength限制。

据我所知,这个错误没有解决方法,你有以下选择:

  • 升级到.NET 4.5
  • 自己承载服务而不是使用IIS
  • 使用不基于HTTP的绑定,以便不涉及ASP.NET处理程序
用户回答回答于

这可能是流式实现中的一个错误。我发现了一篇MSDN文章,建议在http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/fb9efac5-8b57-417e-9f71-35d48d421eb4/上描述所描述的内容。不幸的是,建议修复的微软员工在实施中发现了一个错误,并没有跟进修复的细节。

也就是说,它看起来像是破坏了实现,可以通过使用内存分析器分析代码并验证整个文件是否存储在内存中来测试。如果整个文件存储在内存中,除非有人发现您的代码存在配置问题,否则将无法解决此问题。

也就是说,虽然使用requestLengthDiskThreshold在技​​术上可以工作,但它会显着增加写入时间,因为每个文件必须首先作为临时数据写入,从临时数据读取,再次写入最终数据,最后删除临时数据。正如你已经说过你正在处理非常大的文件,所以我怀疑这样的解决方案是可以接受的。

你最好的选择是使用分块框架并手动重建文件。我在http://aspilham.blogspot.com/2011/03/file-uploading-in-chunks-using.html上发现了如何编写此类逻辑的说明,但没有时间检查它的准确性。

对不起,我不能告诉你为什么你的代码不能像记录那样工作,但类似于第二个例子的东西应该能够工作,而不会使你的内存占用空间膨胀。

扫码关注云+社区