gpt4 book ai didi

c# - 为非缓冲文件上传覆盖 WebHostBufferPolicySelector

转载 作者:太空狗 更新时间:2023-10-29 22:23:07 24 4
gpt4 key购买 nike

在尝试创建非缓冲文件上传时,我扩展了 System.Web.Http.WebHost.WebHostBufferPolicySelector,覆盖了函数 UseBufferedInputStream(),如本文所述:http://www.strathweb.com/2012/09/dealing-with-large-files-in-asp-net-web-api/ .将文件发布到我的 Controller 时,我可以在跟踪输出中看到被覆盖的函数 UseBufferedInputStream() 确实按预期返回 FALSE。但是,使用诊断工具我可以看到内存随着文件的上传而增长。

大量内存使用似乎发生在我的自定义 MediaTypeFormatter 中(类似于此处的 FileMediaFormatter:http://lonetechie.com/)。正是在这个格式化程序中,我想将传入的文件增量写入磁盘,但我还需要解析 json 并使用 Content-Type:multipart/form-data 上传进行一些其他操作。因此,我正在使用 HttpContent 方法 ReadAsMultiPartAsync(),这似乎是内存增长的来源。我在“等待”之前/之后放置了跟踪输出,看起来当任务阻塞时内存使用量增加得相当快。

在 ReadAsMultiPartAsync() 返回的部分中找到文件内容后,我将使用 Stream.CopyTo() 将文件内容写入磁盘。这会按预期写入磁盘,但不幸的是此时源文件已经在内存中。

有没有人对可能出现的问题有任何想法? ReadAsMultiPartAsync() 似乎正在缓冲整个发布数据;如果这是真的,为什么我们需要 var fileStream = await 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);
}
}

最佳答案

WebHostBufferPolicySelector 仅指定底层请求是否无缓冲。这是 Web 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 上有一个例子或 here .在这些示例中,一切都发生在 Controller 中,但没有理由不在格式化程序中使用它。

另一个选择,如果你真的想玩流是实现一个自定义类继承自 MultipartStreamProvider一旦它捕获了流的一部分,它就会触发你想要的任何处理。用法类似于上述提供程序 - 您需要将其传递给 ReadAsMultipartAsync(provider) 方法。

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

            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
}

当然,这是非常严重的,因为没有更好的词“贫民窟”。

关于c# - 为非缓冲文件上传覆盖 WebHostBufferPolicySelector,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14906052/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com