我创建了一个简单的 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);
}
}
}
它使用webHttpBinding
设置transferMode
为“流式传输”和maxReceivedMessageSize
,maxBufferPoolSize
并且maxBufferSize
全部设置为 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 跟踪,但没有显示错误。当我增加httpRuntime
. maxRequestLength
到 1GB,文件上传没有问题。MSDN 说“指定输入流缓冲阈值的限制,以 KB 为单位maxRequestLength
” 。
这使我相信整个文件(全部 100MB)首先存储在“输入流缓冲区”中,然后才可用于我Upload
在服务器上的方法。我实际上可以看到服务器上文件的大小并没有逐渐增加(正如我所期望的那样),相反,在创建它的那一刻它已经是 100MB 大。
问题:我怎样才能让它工作,以便“输入流缓冲区”相当小(比如,1MB),当它溢出时,我的Upload
方法被调用?换句话说,我希望上传能够真正流式传输,而不必在任何地方缓冲整个文件。
编辑:
我现在发现httpRuntime
包含与此处相关的另一个设置 - requestLengthDiskThreshold
。似乎当输入缓冲区增长超过此阈值时,它不再存储在内存中,而是存储在文件系统中。所以至少整个 100MB 的大文件没有保存在内存中(这是我最害怕的),但是,我仍然想知道是否有一些方法可以完全避免这个缓冲区。