一尘不染

将文件返回到ASP.NET MVC中的“查看/下载”

c#

我在将数据库中存储的文件发送回ASP.NET
MVC中的用户时遇到问题。我想要的是一个列出两个链接的视图,一个链接用于查看文件,并让发送给浏览器的mimetype确定应如何处理,另一个链接用于强制下载。

如果我选择查看一个名为的文件SomeRandomFile.bak,而浏览器没有用于打开此类型文件的关联程序,则默认为下载行为时,我没有任何问题。但是,如果我选择查看一个名为的文件,SomeRandomFile.pdf或者SomeRandomFile.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};

有什么建议么?


更新:
这个问题似乎引起了很多人的共鸣,所以我认为我应该发布更新。奥斯卡(Oskar)在以下有关国际字符的可接受答案上提出的警告是完全有效的,由于使用了ContentDisposition该类,我已经多次点击它。此后,我更新了实现以解决此问题。尽管下面的代码来自我最近在ASP.NET
Core(完整框架)应用程序中对该问题的化身,但由于我正在使用System.Net.Http.Headers.ContentDispositionHeaderValue该类,因此它在最小的MVC应用程序中也应能进行最小的更改。

using System.Net.Http.Headers;

public IActionResult Download()
{
    Document document = ... //Obtain document from database context

    //"attachment" means always prompt the user to download
    //"inline" means let the browser try and handle it
    var cd = new ContentDispositionHeaderValue("attachment")
    {
        FileNameStar = document.FileName
    };
    Response.Headers.Add(HeaderNames.ContentDisposition, cd.ToString());

    return File(document.Data, document.ContentType);
}

// an entity class for the document in my database 
public class Document
{
    public string FileName { get; set; }
    public string ContentType { get; set; }
    public byte[] Data { get; set; }
    //Other properties left out for brevity
}

阅读 194

收藏
2020-05-19

共1个答案

一尘不染

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-02-25

2020-05-19