2017-10-13 65 views
0

在ASP.NET MVC應用程序中,我正在通過REST API從SharePoint Online中讀取文件並將其顯示在MVC應用程序的當前瀏覽器窗口中。我有代碼適用於較小的文件,但對於「大文件」(我不知道確切的斷點),我得到一個OutOfMemoryException。這裏的控制器代碼:OutOfMemoryException當返回FileResult與流

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和互聯網,但我找不到解決方案。

我開始通過方法WebClient.DownloadData讀取所有數據到byte[]。當我得到OutOfMemoryException時,我想用方法WebClient.OpenRead代替Stream,可以解決這個問題,但我仍然遇到大文件的例外。對於較小的文件,行爲就像我想要的那樣。我如何解決這個異常?

UPDATE
上面的示例代碼不是真正的代碼。真正的代碼有一個較低級別的客戶端類檢索流,並將其傳遞給調用堆棧,最終傳遞給控制器​​。儘管如此,客戶類確實使用了using語句。如果該方法返回時流關閉,並且代碼退出using塊,那麼爲什麼它適用於較小的文件?此外,我實際上通過手動處理流並使用緩衝區寫入響應來獲得我的代碼。我當前的代碼正在關閉finally塊中的流(在控制器操作方法中 - 仍然從較低級別的客戶端類中檢索流)。 (注意:我回來後我的新代碼作爲答案,並關閉了這個問題,但現在我有點糊塗了。)

+0

您是否嘗試過? https://stackoverflow.com/questions/41961496/how-do-i-increase-maximum-download-size-in-an-mvc-application – ArhiChief

回答

1

不知道的內存溢出的問題,但你有這樣的:

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

stream在處置webClient時變得無效,除非您還有別的東西,我們無法看到第一個將整個內容讀入內存中...並且可以輕鬆解釋OutOfMemory問題。

+0

謝謝。請參閱我的更新。當WebClient對象被丟棄時,你確定這個流是無效的嗎?如果是這樣,有什麼可以解釋我的代碼正在工作?無論哪種方式,這可能是一個有爭議的問題,因爲我認爲重構是一個好主意,所以客戶端類將數據寫入使用塊中的響應。我不喜歡將流傳回堆棧,然後不得不處置它。有什麼建議麼? – neizan

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語句結束之前返回時,它可以返回流式傳輸給調用者的結果

+0

所以你說的是ASP。如果我在'using'塊中返回流,NET只會將字節讀入內存中?這似乎與我在這裏的經驗相矛盾,因爲我現在有一個工作示例,它在使用之外返回(更新中提到的棧更高)。 – neizan

+0

@neizan你確定選擇的方法OpenRead返回流不是字節數組? –

+0

是的,根據[文檔](https://msdn.microsoft.com/en-us/library/ms144209(v = vs.110).aspx#Anchor_0)。 – neizan