2010-07-08 56 views
51

有没有一种方法可以在具有特定名称的浏览器中使用ASP.NET MVC FileContentResult来流式传输文件?在具有名称的浏览器中使用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时,它会显示Action Name作为文件的名称。

有没有人遇到过这个?

回答

11

这可能是不管是谁面临这个问题有帮助。我终于想出了一个解决方案。事实证明,即使我们使用内联处理“content-disposition”并指定文件名,浏览器仍然不使用文件名。浏览器会根据Path/URL尝试解释文件名。

您可以在此URL进一步阅读: Securly download file inside browser with correct filename

这给了我一个想法,我只是创造了我,将转换网址,并以文件名结束它的URL路径我想给文件。因此对于例如我的原始控制器调用只包括传递正在打印的订单的订单ID。我期待文件名格式为Order {0} .pdf,其中{0}是订单ID。同样的报价,我想报价{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, 阿努普

+0

黑客,但非常有效的黑客!谢谢! – 2013-10-15 01:17:37

+0

不幸的是,IE 11仍然需要。Chrome和Firefox不需要。 – 2016-01-25 09:47:58

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

和打开你需要设置Content-Disposition头在浏览器内的PDF:

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

你好Darin, 这就像我提到的打开一个OPEN/SAVE对话框。我希望这在浏览器中打开一个文件。 – 2010-07-09 00:55:07

+1

@Anup,请看我的更新。 – 2010-07-09 07:31:43

+0

我们可以有一个通用的值而不是“application/pdf”吗?就像我不确定文件的类型一样。它是上传它的用户我第一个地方 – neebz 2011-06-20 23:04:31

38

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

byte[] content = your_byte[]; 

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

return result; 
+1

Nah!..我的答案是最简单的,http://stackoverflow.com/a/29392930/193634 – 2015-04-01 14:10:58

+2

我会同意,如果原来的问题不包括一个字节数组。 – azarc3 2015-04-08 17:39:05

0
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; 
    } 
} 
5

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

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

...将导致多个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); 
    } 
} 

在你Controller,或在基础Controller,你可以写一个简单的辅助来实例化一个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 
    }); 
} 

现在,该文件将被发送到与文件名的浏览器选择和使用的内容处置头“内联;文件名= [文件名]“。

我希望有帮助!

+0

我已经去了'ContentDisposition' helper类的方法,只是为了实现MVC在内部也使用它,但有一些黑客正确处理utf-8文件名。 'ContentDisposition'辅助类在编码utf-8值时会出错。有关更多详情,请参阅[我的评论](/ questions/1012437/uses-of-content-disposition-in-an-http-response-header/22221217#comment57484455_22221217)。 – 2016-01-25 09:21:04

4

到流的文件到使用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

**编辑**

显然,我的 '答案' 是一样的任择议定书的问题。但我不面临他遇到的问题。可能这是ASP.NET MVC的旧版本的问题?

+0

当指定一个文件名时,它的问题可以被抽象为'MVC发送带'attachment'处理的'content-disposition'头,如何让它以'inline'的形式发送?测试你的解决方案响应头文件,你通常也会看到附件。 – 2016-01-25 09:16:32

相关问题