2011-04-29 36 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