asp.net-mvc 在带有名称的浏览器中使用 ASP.NET MVC FileContentResult 流式传输文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3206682/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Stream file using ASP.NET MVC FileContentResult in a browser with a name?
提问by Anup Marwadi
Is there a way to stream a file using ASP.NET MVC FileContentResult within the browser with a specific name?
有没有办法在具有特定名称的浏览器中使用 ASP.NET MVC FileContentResult 流式传输文件?
I have noticed that you can either have a FileDialog (Open/Save) or you can stream the file in a browser window, but then it will use the ActionName when you try to save the file.
我注意到您可以使用 FileDialog(打开/保存),也可以在浏览器窗口中流式传输文件,但是当您尝试保存文件时它将使用 ActionName。
I have the following scenario:
我有以下场景:
byte[] contents = DocumentServiceInstance.CreateDocument(orderId, EPrintTypes.Quote);
result = File(contents, "application/pdf", String.Format("Quote{0}.pdf", orderId));
When I use this, I can stream the bytes, but a OPEN/SAVE file dialog is given to the user. I would like to actually stream this file in a browser window.
当我使用它时,我可以流式传输字节,但是会向用户提供一个 OPEN/SAVE 文件对话框。我想在浏览器窗口中实际流式传输此文件。
If I just use the FilePathResult, it shows the file in a browser window, but then when I click on "Save" button to save the file in PDF, it shows me the Action Name as the name of the file.
如果我只使用 FilePathResult,它会在浏览器窗口中显示文件,但是当我单击“保存”按钮将文件保存为 PDF 时,它会向我显示操作名称作为文件的名称。
Has anyone encountered this?
有没有人遇到过这个?
采纳答案by Anup Marwadi
This might be helpful for whoever else faces this problem. I finally figured out a solution. Turns out, even if we use the inline for "content-disposition" and specify a file name, the browsers still do not use the file name. Instead browsers try and interpret the file name based on the Path/URL.
这可能对面临此问题的其他人有所帮助。我终于想出了一个解决方案。事实证明,即使我们为“content-disposition”使用内联并指定文件名,浏览器仍然不使用文件名。相反,浏览器会尝试根据路径/URL 解释文件名。
You can read further on this URL: Securly download file inside browser with correct filename
您可以在此 URL 上进一步阅读: 使用正确的文件名在浏览器中安全下载文件
This gave me an idea, I just created my URL route that would convert the URL and end it with the name of the file I wanted to give the file. So for e.g. my original controller call just consisted of passing the Order Id of the Order being printed. I was expecting the file name to be of the format Order{0}.pdf where {0} is the Order Id. Similarly for quotes, I wanted Quote{0}.pdf.
这给了我一个想法,我刚刚创建了我的 URL 路由,它将转换 URL 并以我想要提供文件的文件名结尾。因此,例如,我的原始控制器调用仅包括传递正在打印的订单的订单 ID。我希望文件名的格式为 Order{0}.pdf,其中 {0} 是订单 ID。同样,对于引号,我想要 Quote{0}.pdf。
In my controller, I just went ahead and added an additional parameter to accept the file name. I passed the filename as a parameter in the URL.Action method.
在我的控制器中,我只是继续添加了一个额外的参数来接受文件名。我在 URL.Action 方法中将文件名作为参数传递。
I then created a new route that would map that URL to the format: http://localhost/ShoppingCart/PrintQuote/1054/Quote1054.pdf
然后我创建了一个新路由,将该 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" }
);
This pretty much solved my issue. Hoping this helps someone!
这几乎解决了我的问题。希望这对某人有所帮助!
Cheerz, Anup
干杯,阿纳普
回答by Darin Dimitrov
public ActionResult Index()
{
byte[] contents = FetchPdfBytes();
return File(contents, "application/pdf", "test.pdf");
}
and for opening the PDF inside the browser you will need to set the Content-Disposition
header:
要在浏览器中打开 PDF,您需要设置Content-Disposition
标题:
public ActionResult Index()
{
byte[] contents = FetchPdfBytes();
Response.AddHeader("Content-Disposition", "inline; filename=test.pdf");
return File(contents, "application/pdf");
}
回答by azarc3
Actually, the absolutely easiest way is to do the following...
实际上,绝对最简单的方法是执行以下操作...
byte[] content = your_byte[];
FileContentResult result = new FileContentResult(content, "application/octet-stream")
{
FileDownloadName = "your_file_name"
};
return result;
回答by Kevin Babcock
Previous answers are correct: adding the line...
以前的答案是正确的:添加行...
Response.AddHeader("Content-Disposition", "inline; filename=[filename]");
...will causing multiple Content-Disposition headers to be sent down to the browser. This happens b/c FileContentResult
internally applies the header if you supply it with a file name. An alternative, and pretty simple, solution is to simply create a subclass of FileContentResult
and override its ExecuteResult()
method. Here's an example that instantiates an instance of the System.Net.Mime.ContentDisposition
class (the same object used in the internal FileContentResult
implementation) and passes it into the new class:
...将导致多个 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);
}
}
In your Controller
, or in a base Controller
, you can write a simple helper to instantiate a FileContentResultWithContentDisposition
and then call it from your action method, like so:
在您的Controller
或 base 中Controller
,您可以编写一个简单的帮助程序来实例化 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
});
}
Now the file will be sent to the browser with the file name you choose and with a content-disposition header of "inline; filename=[filename]".
现在,文件将使用您选择的文件名和“inline; filename=[filename]”的内容处置标题发送到浏览器。
I hope that helps!
我希望这有帮助!
回答by Rosdi Kasim
The absolute easiest way to stream a file into browser using ASP.NET MVC is this:
使用 ASP.NET MVC 将文件流式传输到浏览器的绝对最简单的方法是:
public ActionResult DownloadFile() {
return File(@"c:\path\to\somefile.pdf", "application/pdf", "Your Filename.pdf");
}
This is easier than the method suggested by @azarc3 since you don't even need to read the bytes.
这比@azarc3 建议的方法更容易,因为您甚至不需要读取字节。
Credit goes to: http://prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response
归功于:http: //prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response
** Edit **
** 编辑 **
Apparently my 'answer' is the same as the OP's question. But I am not facing the problem he is having. Probably this was an issue with older version of ASP.NET MVC?
显然,我的“答案”与 OP 的问题相同。但我没有面对他遇到的问题。这可能是旧版本 ASP.NET MVC 的问题?
回答by Felix K. Mantini
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;
}
}