使用流返回FileResult时发生OutOfMemoryException



在ASP.NET MVC应用程序中,我通过REST API从SharePoint Online读取一个文件,并将其显示在MVC应用程序的当前浏览器窗口中。我有适用于较小文件的代码,但对于"大文件"(我不知道确切的断点),我得到了OutOfMemoryException。这是控制器代码:

public ActionResult Index() {
System.IO.Stream stream = null;
string fileName = "whatever.ext";
string restUri = $"https://myhost.sharepoint.com/sites/mysite/_api/Web/GetFileByServerRelativePath('mypath/{fileName}')/openbinarystream";
string mimeType = MimeMapping.GetMimeMapping(fileName);
using (var webClient = new WebClient()) {
webClient.Credentials = myCredentials;
webClient.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
var uri = new Uri(restUri);
stream = webClient.OpenRead(uri);
}
Response.AppendHeader("Content-Disposition", "inline; filename=" + fileName);
return File(stream, mimeType);
}

我四处寻找SO和互联网,但找不到解决方案。

  • https://sharepoint.stackexchange.com/questions/186551/placing-a-sharepoint-openbinarystream-into-a-byte-array-csom
  • 读取500MB FileStream时出现OutOfMemoryException
  • 使用FileStream ASPNET发送500MB大文件时出现OutOfMemoryException

我开始通过方法WebClient.DownloadData将所有数据读取到byte[]中。当我得到OutOfMemoryException时,我认为通过方法WebClient.OpenReadStream替换会修复它,但我仍然得到了大文件的异常。对于较小的文件,行为正是我想要的。如何修复异常?

UPDATE
上面的示例代码不是真正的代码。真正的代码有一个较低级别的客户端类来检索流,并将其向上传递到调用堆栈,最终传递到控制器。不过,客户端类确实使用了using语句,如示例所示。如果在方法返回时关闭流,并且代码退出using块,那么为什么它适用于较小的文件?此外,我实际上通过使用缓冲区手动处理流并写入响应来实现代码的工作。我当前的代码是关闭finally块中的流(在控制器操作方法中——仍然从较低级别的客户端类检索流)。(注意,我回来后发布了我的新代码作为答案,并结束了这个问题,但现在我有点困惑。)

不确定OutOfMemory问题,但您有这个:

using (var webClient = new WebClient())
{
stream = webClient.OpenRead(...);
}
return File(stream, mimeType);

webClient被释放时,stream将无效,除非您有其他我们看不到的东西,它首先将整个内容读取到内存中。。。这很容易解释内存不足的问题。

您应该从using语句中返回。

public ActionResult Index() {
System.IO.Stream stream = null;
string fileName = "whatever.ext";
string restUri = $"https://myhost.sharepoint.com/sites/mysite/_api/Web/GetFileByServerRelativePath('mypath/{fileName}')/openbinarystream";
string mimeType = MimeMapping.GetMimeMapping(fileName);
Response.AppendHeader("Content-Disposition", "inline; filename=" + fileName);
using (var webClient = new WebClient()) {
webClient.Credentials = myCredentials;
webClient.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f");
var uri = new Uri(restUri);
stream = webClient.OpenRead(uri);
return File(stream, mimeType);
}
}

发生的情况是,流在using语句中被读取,之后,整个字节被读取到内存中。

当您在using语句结束前返回时,它可以将结果流式返回给调用者

最新更新