2011-04-29 57 views
241

我遇到了將存儲在數據庫中的文件發回給ASP.NET MVC中的用戶的問題。我想要的是一個視圖,列出了兩個鏈接,一個查看文件,並讓mimetype發送給瀏覽器決定如何處理,另一個強制下載。將文件返回到ASP.NET MVC中的查看/下載

如果我選擇查看名爲的文件,並且瀏覽器沒有關聯的程序來打開這種類型的文件,那麼我對它的默認下載行爲沒有任何問題。但是,如果我選擇查看名爲SomeRandomFile.pdfSomeRandomFile.jpg的文件,我只需簡單地打開該文件即可。但我也想保留一個下載鏈接,這樣我就可以強制下載提示,而不管文件類型如何。這有意義嗎?

我試過FileStreamResult它適用於大多數文件,它的構造函數默認不接受文件名,所以未知文件被分配一個基於url的文件名(它不知道基於內容類型)。如果我通過指定文件名來強制文件名,我將失去瀏覽器直接打開文件的能力,並且會得到一個下載提示。有人遇到過這種情況麼。

這些都是我到目前爲止嘗試過的例子。

//Gives me a download prompt. 
return File(document.Data, document.ContentType, document.Name); 

//Opens if it is a known extension type, downloads otherwise (download has bogus name and missing extension) 
return new FileStreamResult(new MemoryStream(document.Data), document.ContentType); 

//Gives me a download prompt (lose the ability to open by default if known type) 
return new FileStreamResult(new MemoryStream(document.Data), document.ContentType) {FileDownloadName = document.Name}; 

有什麼建議?

回答

366
public ActionResult Download() 
{ 
    var document = ... 
    var cd = new System.Net.Mime.ContentDisposition 
    { 
     // for example foo.bak 
     FileName = document.FileName, 

     // always prompt the user for downloading, set to true if you want 
     // the browser to try to show the file inline 
     Inline = false, 
    }; 
    Response.AppendHeader("Content-Disposition", cd.ToString()); 
    return File(document.Data, document.ContentType); 
} 

注:以上這個例子代碼不能正確地考慮在文件名中國際字符。有關相關標準,請參閱RFC6266。我相信最近版本的ASP.Net MVC的File()方法和ContentDispositionHeaderValue類正確地解決了這個問題。 - 奧斯卡·2016年2月25日

+1

完美的,正是我所尋找的,它的工作方式正是我想要的。我記得過去使用過ContentDisposition,但我並沒有意識到它的Inline屬性,並且我很好奇是否有更多的MVC集成選項,而不是直接設置標題。但對AppendHeader的簡單調用看起來對我來說已經足夠優雅了。謝謝您的幫助!! – 2011-04-29 15:51:25

+1

這在任何情況下都不起作用。有些瀏覽器希望引用文件名(attachment;「downloadfile.pdf」) – tgallard 2011-09-06 15:50:25

+6

如果我沒有記錯,只要文件名沒有空格就可以取消引號(我通過HttpUtility.UrlEncode()運行我的程序來實現此目的)。 – 2012-04-28 11:54:24

0

我相信這個答案是清潔,(基於 https://stackoverflow.com/a/3007668/550975

public ActionResult GetAttachment(long id) 
    { 
     FileAttachment attachment; 
     using (var db = new TheContext()) 
     { 
      attachment = db.FileAttachments.FirstOrDefault(x => x.Id == id); 
     } 

     return File(attachment.FileData, "application/force-download", Path.GetFileName(attachment.FileName)); 
    } 
+7

不推薦,爲了清晰和兼容,Content-Disposition是首選方法。 http://stackoverflow.com/questions/10615797/utility-of-http-header-content-type-application-force-download-for-mobile – 2013-11-12 19:04:52

+0

謝謝你。儘管我將MIME類型更改爲「application/octet-stream」,但仍然導致文件被下載而不是顯示,並且它似乎是兼容的。 – 2013-11-13 02:14:37

+1

說謊的內容類型聽起來像一個非常糟糕的主意。有些瀏覽器依賴正確的內容類型來在「保存或打開」對話框中爲用戶建議應用程序。 – 2016-02-25 23:51:01

0

FileVirtualPath - >研究\全球辦公室Review.pdf

public virtual ActionResult GetFile() 
{ 
    return File(FileVirtualPath, "application/force-download", Path.GetFileName(FileVirtualPath)); 
} 
+4

這已經在前面的答案中提到過了,不推薦使用。有關更多詳細信息,請參閱以下問題。 http://stackoverflow.com/questions/10615797/utility-of-http-header-content-type-application-force-download-for-mobile – 2014-01-28 22:36:35

+2

哦,謝謝你的鏈接 – 2014-01-29 02:30:18

+1

這樣它就不會使用服務器上的資源通過加載文件到服務器上的內存,我是否正確? – 2015-08-13 13:40:50

96

我由於對「文檔」變量沒有任何類型暗示,所以接受的答案有問題:var document = ...因此,我發佈了什麼對我有用,作爲替代方案以防其他人遇到問題。

public ActionResult DownloadFile() 
{ 
    string filename = "File.pdf"; 
    string filepath = AppDomain.CurrentDomain.BaseDirectory + "/Path/To/File/" + filename; 
    byte[] filedata = System.IO.File.ReadAllBytes(filepath); 
    string contentType = MimeMapping.GetMimeMapping(filepath); 

    var cd = new System.Net.Mime.ContentDisposition 
    { 
     FileName = filename, 
     Inline = true, 
    }; 

    Response.AppendHeader("Content-Disposition", cd.ToString()); 

    return File(filedata, contentType); 
} 
+3

文檔變量只是一個類(POCO),代表您想要返回的文檔的信息。在接受的答案中也提到了這個問題。它可能來自ORM,手動構建的SQL查詢,文件系統(從您的信息中提取信息)或其他數據存儲。這與你的文檔字節/文件名/ MIME類型來自原來的問題是無關緊要的,所以它被排除在不沾染代碼。感謝您貢獻一個僅使用文件系統的例子。 – 2015-06-17 17:54:13

+1

當文件名包含US-ASCII以外的國際字符時,此解決方案無法正常工作。 – 2016-02-25 23:49:23

+0

謝謝,保存了我的一天:) – Dipesh 2016-10-25 11:34:43

8

Darin Dimitrov's answer是正確的。只是增加:

Response.AppendHeader("Content-Disposition", cd.ToString());如果您的響應已經包含「Content-Disposition」標題,則可能會導致瀏覽器無法呈現文件。在這種情況下,您可能需要使用:

Response.Headers.Add("Content-Disposition", cd.ToString()); 
7

視圖文件(TXT爲例):

return File("~/TextFileInRootDir.txt", MediaTypeNames.Text.Plain); 

下載文件(TXT爲例):

return File("~/TextFileInRootDir.txt", MediaTypeNames.Text.Plain, "TextFile.txt"); 

注意:要下載文件,我們應該通過文件下載名稱參數

+0

這種方法唯一的問題是隻有在使用強制下載的方法時才提供文件名。當我想讓瀏覽器確定如何打開文件時,它不允許我發送正確的文件名。所以外部應用程序會嘗試使用我的URL作爲文件名。這通常是數據庫中文檔的某種id,通常沒有文件擴展名。這使得名稱與用於訪問該文件的URL不匹配的情況非常糟糕,因爲如果您不提供該場景,則情況就是如此。 – 2016-05-04 20:22:56

+0

使用Content-Disposition上的'Inline'屬性可以讓我將文件名的設置與強制下載的行爲分開。 – 2016-05-04 20:23:39