Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/31.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用WebAPI传输大文件(IIS上的2GB以上)_C#_Asp.net_Asp.net Web Api - Fatal编程技术网

C# 使用WebAPI传输大文件(IIS上的2GB以上)

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

我正在尝试将非常大的文件(>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的代码:

    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?