使用Stream

时间:2017-10-13 19:19:55

标签: asp.net-mvc

在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和互联网,但我找不到解决方案。

我开始通过方法byte[]将所有数据读入WebClient.DownloadData。当我得到OutOfMemoryException时,我认为通过方法Stream替换WebClient.OpenRead会修复它,但我仍然会获得大文件的异常。对于较小的文件,行为就像我想要的那样。如何修复异常?

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

2 个答案:

答案 0 :(得分:1)

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

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

stream被处置时,webClient无效,除非你有其他东西我们无法看到首先将整个内容读入内存......这可以很容易地解释OutOfMemory问题。

答案 1 :(得分:0)

您应该从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语句结束之前返回时,它可以返回流式传输给调用者的结果