在具有名称的浏览器中使用ASP.NET MVC FileContentResult流文件?

Anu*_*adi 58 asp.net-mvc filecontentresult fileresult

有没有办法在浏览器中使用具有特定名称的ASP.NET MVC FileContentResult来流式传输文件?

我注意到你可以有一个FileDialog(打开/保存),或者你可以在浏览器窗口中流式传输文件,但是当你尝试保存文件时它会使用ActionName.

我有以下场景:

byte[] contents = DocumentServiceInstance.CreateDocument(orderId, EPrintTypes.Quote);
result = File(contents, "application/pdf", String.Format("Quote{0}.pdf", orderId));
Run Code Online (Sandbox Code Playgroud)

当我使用它时,我可以流式传输字节,但是给用户提供了一个OPEN/SAVE文件对话框.我想在浏览器窗口中实际传输此文件.

如果我只使用FilePathResult,它会在浏览器窗口中显示该文件,但是当我单击"保存"按钮将文件保存为PDF时,它会显示操作名称作为文件的名称.

有没有遇到过这个?

Dar*_*rov 90

public ActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    return File(contents, "application/pdf", "test.pdf");
}
Run Code Online (Sandbox Code Playgroud)

要在浏览器中打开PDF,您需要设置Content-Disposition标题:

public ActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    Response.AddHeader("Content-Disposition", "inline; filename=test.pdf");
    return File(contents, "application/pdf");
}
Run Code Online (Sandbox Code Playgroud)

  • 我们使用这种方法,它会导致MVC3向浏览器发送2个内容处理标头,这会导致Chrome和Firefox无法显示该文件.http://stackoverflow.com/q/8616691/304832 (3认同)
  • @AnilSoman,调用一个用AJAX返回文件的控制器动作是没有意义的.如果使用AJAX,您永远不会打开任何文件框. (2认同)
  • @AnilSoman,抱歉用AJAX是不可能的.您可以使用提交表单的普通图像按钮,而无需任何AJAX调用. (2认同)

aza*_*rc3 48

实际上,绝对最简单的方法是做以下事情......

byte[] content = your_byte[];

FileContentResult result = new FileContentResult(content, "application/octet-stream") 
{
  FileDownloadName = "your_file_name"
};

return result;
Run Code Online (Sandbox Code Playgroud)

  • 如果原始问题不包含字节数组,我会同意. (2认同)

Anu*_*adi 12

这可能对其他人遇到此问题有帮助.我终于找到了解决方案.事实证明,即使我们使用内联"内容处理"并指定文件名,浏览器仍然不使用文件名.相反,浏览器会尝试根据路径/ URL解释文件名.

您可以在此URL上进一步阅读: 使用正确的文件名在浏览器中安全下载文件

这给了我一个想法,我刚创建了我的URL路由,它将转换URL并以我想要给文件的文件名结束它.因此,例如我的原始控制器调用只包括传递正在打印的订单的订单ID.我希望文件名的格式为Order {0} .pdf,其中{0}是Order Id.同样,对于报价,我想要Quote {0} .pdf.

在我的控制器中,我只是继续并添加了一个额外的参数来接受文件名.我将文件名作为参数传递给了URL.Action方法.

然后我创建了一个新路由,将该URL映射到以下格式: http://localhost/ShoppingCart/PrintQuote/1054/Quote1054.pdf


routes.MapRoute("", "{controller}/{action}/{orderId}/{fileName}",
                new { controller = "ShoppingCart", action = "PrintQuote" }
                , new string[] { "x.x.x.Controllers" }
            );

这几乎解决了我的问题.希望这有助于某人!

Cheerz,Anup


Kev*_*ock 8

以前的答案是正确的:添加行...

Response.AddHeader("Content-Disposition", "inline; filename=[filename]");
Run Code Online (Sandbox Code Playgroud)

...将导致多个Content-Disposition标头向下发送到浏览器.这种情况发生在b/c FileContentResult内部应用标头,如果您提供文件名.另一种非常简单的解决方案是简单地创建一个子类FileContentResult并覆盖其ExecuteResult()方法.这是一个实例化System.Net.Mime.ContentDisposition类的实例(内部FileContentResult实现中使用的相同对象)并将其传递给新类的示例:

public class FileContentResultWithContentDisposition : FileContentResult
{
    private const string ContentDispositionHeaderName = "Content-Disposition";

    public FileContentResultWithContentDisposition(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
        : base(fileContents, contentType)
    {
        // check for null or invalid ctor arguments
        ContentDisposition = contentDisposition;
    }

    public ContentDisposition ContentDisposition { get; private set; }

    public override void ExecuteResult(ControllerContext context)
    {
        // check for null or invalid method argument
        ContentDisposition.FileName = ContentDisposition.FileName ?? FileDownloadName;
        var response = context.HttpContext.Response;
        response.ContentType = ContentType;
        response.AddHeader(ContentDispositionHeaderName, ContentDisposition.ToString());
        WriteFile(response);
    }
}
Run Code Online (Sandbox Code Playgroud)

在你ControllerController你的基础中,你可以编写一个简单的帮助器来实例化a FileContentResultWithContentDisposition然后从你的action方法中调用它,如下所示:

protected virtual FileContentResult File(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
{
    var result = new FileContentResultWithContentDisposition(fileContents, contentType, contentDisposition);
    return result;
}

public ActionResult Report()
{
    // get a reference to your document or file
    // in this example the report exposes properties for
    // the byte[] data and content-type of the document
    var report = ...
    return File(report.Data, report.ContentType, new ContentDisposition {
        Inline = true,
        FileName = report.FileName
    });
}
Run Code Online (Sandbox Code Playgroud)

现在,文件将以您选择的文件名发送到浏览器,并且内容处置标题为"inline; filename = [filename]".

我希望有所帮助!


Ros*_*sim 6

使用 ASP.NET MVC 将文件流式传输到浏览器的绝对最简单的方法是:

public ActionResult DownloadFile() {
    return File(@"c:\path\to\somefile.pdf", "application/pdf", "Your Filename.pdf");
}
Run Code Online (Sandbox Code Playgroud)

这比@azarc3 建议的方法更容易,因为您甚至不需要读取字节。

归功于:http : //prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response

** 编辑 **

显然,我的“答案”与 OP 的问题相同。但我没有面对他遇到的问题。这可能是旧版本 ASP.NET MVC 的问题?