65

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

我注意到您可以使用 FileDialog(打开/保存),也可以在浏览器窗口中流式传输文件,但是当您尝试保存文件时它将使用 ActionName。

我有以下情况:

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

当我使用它时,我可以流式传输字节,但会向用户提供一个打开/保存文件对话框。我想在浏览器窗口中实际流式传输此文件。

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

有没有人遇到过这个?

4

7 回答 7

96
public ActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    return File(contents, "application/pdf", "test.pdf");
}

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

public ActionResult Index()
{
    byte[] contents = FetchPdfBytes();
    Response.AddHeader("Content-Disposition", "inline; filename=test.pdf");
    return File(contents, "application/pdf");
}
于 2010-07-08T19:37:17.513 回答
60

实际上,绝对最简单的方法是执行以下操作...

byte[] content = your_byte[];

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

return result;
于 2013-04-15T10:34:44.163 回答
13

这可能对其他面临此问题的人有所帮助。我终于想出了一个解决办法。事实证明,即使我们使用“content-disposition”的内联并指定文件名,浏览器仍然不使用文件名。相反,浏览器会尝试根据路径/URL 解释文件名。

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

这给了我一个想法,我刚刚创建了我的 URL 路由,它将转换 URL 并以我想要提供文件的文件名结束它。因此,例如,我最初的控制器调用只包括传递正在打印的订单的订单 ID。我希望文件名的格式为 Order{0}.pdf,其中 {0} 是订单 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" }
            );

这几乎解决了我的问题。希望这对某人有帮助!

欢呼,阿努普

于 2010-07-15T05:16:47.530 回答
8

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

Response.AddHeader("Content-Disposition", "inline; filename=[filename]");

...将导致多个 Content-Disposition 标头被发送到浏览器。FileContentResult如果您为其提供文件名,则会发生这种情况 b/c在内部应用标题。另一种非常简单的解决方案是简单地创建一个子类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);
    }
}

在 yourController或 baseController中,您可以编写一个简单的助手来实例化 a FileContentResultWithContentDisposition,然后从您的操作方法中调用它,如下所示:

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
    });
}

现在,该文件将使用您选择的文件名和“inline; filename=[filename]”的内容处置标头发送到浏览器。

我希望这会有所帮助!

于 2013-07-26T23:07:00.550 回答
6

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

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

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

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

** 编辑 **

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

于 2015-04-01T14:05:25.753 回答
0

我使用 REST API 在 ASP.NET Core 中对其进行了调整。

public class FileContentWithFileNameResult : FileContentResult
{
    public FileContentWithFileNameResult(byte[] fileContents, string contentType, string fileName)
   : base(fileContents, contentType)
    {
        FileName = fileName;
    }

    public string FileName { get; private set; }

    public override Task ExecuteResultAsync(ActionContext context)
    {
        var response = context.HttpContext.Response;  
        response.Headers.Append("Content-Disposition", $"inline; filename={FileName}");
        response.Headers.Append("Access-Control-Expose-Headers", "Content-Disposition");
        response.Headers.Append("X-Content-Type-Options", "nosniff");
        return base.ExecuteResultAsync(context);
    }
}
于 2021-10-04T16:19:18.130 回答
-1
public FileContentResult GetImage(int productId) { 
     Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId); 
     if (prod != null) { 
         return File(prod.ImageData, prod.ImageMimeType); 
      } else { 
         return null; 
     } 
}
于 2013-07-26T11:42:58.783 回答