C# 使用WebAPI传输大文件(IIS上的2GB以上)
我正在尝试将非常大的文件(>2GB)上载到我的WebAPI应用程序(运行在.NET 4.5.2、Windows 2012R2上) 设置httpRuntime maxRequestLength属性没有用,因为它只处理小于2GB的文件 我目前正在使用自定义MultipartFormDataStreamProvider读取服务器上的整个流,并且已经使用自定义WebHostBufferPolicySelector关闭了缓冲 我发现ASP.NET(或WebAPI)在引擎盖下使用了一个HttpBufferlessInputStream,它有一个名为_disableMaxRequestLength的字段。如果我将该值设置为true(通过反射),我可以流式处理任何大小的文件 然而,摆弄这些互联网显然不是一个好办法 用于请求的HttpRequest类有一个名为的方法,该方法具有允许禁用maxRequestLength的重载 我的问题是:如何让WebAPI使用这个重载而不是标准重载 有没有办法替换默认的HttpRequest或HttpContext类?或者我真的需要对所有的东西使用反射吗 这是我当前用于禁用maxRequestLength的代码:C# 使用WebAPI传输大文件(IIS上的2GB以上),c#,asp.net,asp.net-web-api,C#,Asp.net,Asp.net Web Api,我正在尝试将非常大的文件(>2GB)上载到我的WebAPI应用程序(运行在.NET 4.5.2、Windows 2012R2上) 设置httpRuntime maxRequestLength属性没有用,因为它只处理小于2GB的文件 我目前正在使用自定义MultipartFormDataStreamProvider读取服务器上的整个流,并且已经使用自定义WebHostBufferPolicySelector关闭了缓冲 我发现ASP.NET(或WebAPI)在引擎盖下使用了一个HttpBufferl
private void DisableRequestLengthOnStream(HttpContent parent)
{
var streamContentProperty = parent.GetType().GetProperty("StreamContent", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (streamContentProperty == null) return;
var streamContent = streamContentProperty.GetValue(parent, null);
if (streamContent == null) return;
var contentProperty = typeof(StreamContent).GetField("content", BindingFlags.Instance | BindingFlags.NonPublic);
if (contentProperty == null) return;
var content = contentProperty.GetValue(streamContent);
if (content == null) return;
var requestLengthField = content.GetType().GetField("_disableMaxRequestLength", BindingFlags.Instance | BindingFlags.NonPublic);
if (requestLengthField == null) return;
requestLengthField.SetValue(content, true);
}
,读取无限流长度的方法是HttpRequest.GetBufferlessInputStream
。你可以这样做:
public void ReadStream(HttpContext context, string filePath)
{
using (var reader = new StreamReader(context.Request.GetBufferlessInputStream(true)))
using (var filestream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read, 4096, true))
using (var writer = new StreamWriter(filestream))
{
var readBuffer = reader.ReadToEnd();
writer.WriteAsync(readBuffer);
}
}
我想没有简单的方法可以做到这一点 对
GetBufferlessInputStream
的调用深入到HttpControllerHandler
中,这是ASP.NET Web API的最低层(它是一个HTTP处理程序,整个Web API堆栈都是在其上构建的)
你可以看到
正如您所看到的,它充满了静态、带有嵌套逻辑条件的长方法、内部和私有,因此根本不可定制。虽然Web API中的整个
HttpControllerHandler
理论上可以用自定义实现来替代(这是在HttpControllerOutehandler
内部完成的,通过重写GetHttpHandler
方法),但实际上是不可能的(您可以尝试在应用程序中内部化此代码,但最终也会拖拽大量额外的内部类)
最好的事情(我不敢说)我想到的是修改源
HttpControllerHandler
类,使用GetBufferlessInputStream
的重载来禁用请求长度限制,并重新编译System.Web.Http.WebHost
程序集,并将修改后的版本与应用程序一起部署。好的,我找到了一个非常简单的解决方案当然,来自@JustinR.的swer可以工作。但是我想继续使用MultipartFormDataStreamProvider,因为它可以处理所有MIME内容
解决方案是使用正确的无缓冲输入流创建一个新的StreamContent实例,并使用原始内容的标题填充它:
var provider = new MultipartFormDataStreamProvider(path);
var content = new StreamContent(HttpContext.Current.Request.GetBufferlessInputStream(true));
foreach (var header in Request.Content.Headers)
{
content.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
await content.ReadAsMultipartAsync(provider);
+1个非常有趣的问题。出于好奇,您是否考虑过仅使用FTP进行传输?在我的场景中,这是不可能的……所谓“标准的一个”,您的意思是使用InputString?@JustinR.No。HttpRequest类上有两个GetBufferlessInputStream方法。一个采用参数,用于打开/关闭maxRequestCheck,另一个是另一个只返回HttpBufferlessInputStream,并启用检查。@Henning Krause对此进行读取。我知道这只是一个示例,但
var readBuffer=reader.ReadToEnd();
并没有让我觉得有助于读取“无限流长度”;我对(单流)有问题大的分配,即使内存可用:(@MeirionHughes我完全同意。我有类似的代码将其逐步流式传输到文件中。它也会异步进行。但是,所有用于这样做的附加代码都会分散对函数使用的注意力,我想让示例更清楚。通过上面的代码,我得到了以下错误信息“该流当前正由流上的前一个操作使用。”没有突破2GB的障碍…所以谢谢,对我来说是可行的,我上传了一个21兆字节的xml文件(在开发中)。IIS限制在2GB…没有办法。我更改了实现以执行chuncked上传(jquery/blueimp)不管怎样,为了更容易恢复,你最好还是这样做。@HenningKrause-Thx用于共享代码。你是否尝试在Selfhost中使用Owin而不是IIS?