重写WebHostBufferPolicySelector的非缓冲文件上传(Overriding W

2019-08-17 00:31发布

在如本文中描述试图创建一个非缓冲文件上传我已经延长System.Web.Http.WebHost.WebHostBufferPolicySelector,覆盖函数UseBufferedInputStream(): http://www.strathweb.com/2012/09/dealing -with-大的文件,在-ASP网的Web-API / 。 当一个文件被贴到我的控制,我可以跟踪输出按预期的方式重写功能UseBufferedInputStream()肯定返回FALSE看到。 但是,使用诊断工具,我可以看到越来越多的文件,内存被上传。

沉重的内存使用量出现在我的自定义MediaTypeFormatter要发生的(有点像FileMediaFormatter这里: http://lonetechie.com/ )。 正是在这样的格式,我想以增量写入传入的文件到硬盘,但我也需要解析JSON和做一些其他的操作与内容类型:多部分/表单数据上传。 因此我使用HttpContent方法ReadAsMultiPartAsync(),它似乎是存储器增长的来源。 我把跟踪输出前/后的“等待”,看来,虽然任务是阻止内存使用量相当迅速增加。

一旦我发现通过ReadAsMultiPartAsync返回的部分文件内容(),我以文件内容写入到磁盘使用Stream.CopyTo()。 如预期,但不幸的是,源文件已经在内存由这点该写入磁盘。

有没有人有什么可能会错误的任何想法? 看来,ReadAsMultiPartAsync()正在缓冲后整体数据; 如果这是真的,为什么我们需要VAR FILESTREAM =等待fileContent.ReadAsStreamAsync()来获取文件内容是什么? 是否有另一种方式来完成零件的分裂不读他们到内存? 在我MediaTypeFormatter的代码看起来是这样的:

// save the stream so we can seek/read again later
Stream stream = await content.ReadAsStreamAsync();  

var parts = await content.ReadAsMultipartAsync(); // <- memory usage grows rapidly

if (!content.IsMimeMultipartContent())
{
    throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);               
}

//
// pull data out of parts.Contents, process json, etc.
//

// find the file data in the multipart contents
var fileContent = parts.Contents.FirstOrDefault(
x => x.Headers.ContentDisposition.DispositionType.ToLower().Trim() == "form-data" && 
x.Headers.ContentDisposition.Name.ToLower().Trim() == "\"" + DATA_CONTENT_DISPOSITION_NAME_FILE_CONTENTS + "\"");

// write the file to disk
using (var fileStream = await fileContent.ReadAsStreamAsync())
{
    using (FileStream toDisk = File.OpenWrite("myUploadedFile.bin"))
    {
        ((Stream)fileStream).CopyTo(toDisk);
    }
}

Answer 1:

WebHostBufferPolicySelector仅当底层请求是无缓冲器指定。 这是网络API将在引擎盖下做的:

IHostBufferPolicySelector policySelector = _bufferPolicySelector.Value;
bool isInputBuffered = policySelector == null ? true : policySelector.UseBufferedInputStream(httpContextBase);
    Stream inputStream = isInputBuffered
                  ? requestBase.InputStream
          : httpContextBase.ApplicationInstance.Request.GetBufferlessInputStream();

所以,如果您的实现返回false,那么请求是无缓冲。

然而, ReadAsMultipartAsync()加载到一切MemoryStream -因为如果你不指定供应商,则默认为MultipartMemoryStreamProvider。

要获得这些文件的每一个部分进行处理使用自动保存到磁盘MultipartFormDataStreamProvider (如果你处理的文件和表单数据)或MultipartFileStreamProvider (如果你处理的只是文件)。

上有一个例子asp.net或这里 。 这些例子中的一切发生在控制器,但没有任何理由,你为什么会不即格式化使用它。

另一种选择,如果你真的想和流播放是实现从一个自定义类inheritng MultipartStreamProvider会解雇你一旦想要的任何处理,因为它抓住流的一部分。 用法将类似于上述供应商-你需要将它传递给ReadAsMultipartAsync(provider)的方法。

最后 - 如果你想自杀 - 因为底层请求流是无缓冲理论上,你可以在你的控制器或格式化使用这样的:

            Stream stream = HttpContext.Current.Request.GetBufferlessInputStream();
            byte[] b = new byte[32*1024];
            while ((n = stream.Read(b, 0, b.Length)) > 0)
            {
                //do stuff with stream bit
            }

但是,当然这是非常中,对于没有更好的词中,“贫民窟”。



文章来源: Overriding WebHostBufferPolicySelector for Non-Buffered File Upload