有没有办法在浏览器中使用ASP.NET MVC FileContentResult以特定名称流式传输文件?
我注意到您可以拥有FileDialog(打开/保存),也可以在浏览器窗口中流式传输文件,但是当您尝试保存文件时它会使用ActionName。
我有以下情况:
byte[] contents = DocumentServiceInstance.CreateDocument(orderId, EPrintTypes.Quote);
result = File(contents, "application/pdf", String.Format("Quote{0}.pdf", orderId));
当我使用它时,我可以流式传输字节,但是给用户一个OPEN / SAVE文件对话框。我想在浏览器窗口中实际传输此文件。
如果我只使用FilePathResult,它会在浏览器窗口中显示该文件,但是当我点击“保存”按钮将文件保存为PDF时,它会显示操作名称作为文件的名称。 / p>
有没有人遇到过这个?
答案 0 :(得分:85)
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");
}
答案 1 :(得分:44)
实际上,最简单的方法是执行以下操作......
byte[] content = your_byte[];
FileContentResult result = new FileContentResult(content, "application/octet-stream")
{
FileDownloadName = "your_file_name"
};
return result;
答案 2 :(得分:12)
这可能对其他人遇到此问题有帮助。我终于找到了解决方案。事实证明,即使我们使用内联“内容处理”并指定文件名,浏览器仍然不使用文件名。相反,浏览器会尝试根据路径/ URL解释文件名。
您可以在此网址上进一步阅读: Securly download file inside browser with correct filename
这给了我一个想法,我刚刚创建了我的URL路由,它将转换URL并以我想要给文件的文件名结束它。因此对于例如我的原始控制器调用只包括传递正在打印的订单的订单ID。我希望文件名的格式为Order {0} .pdf,其中{0}是Order 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, 阿努普
答案 3 :(得分:6)
以前的答案是正确的:添加行......
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
});
}
现在,文件将以您选择的文件名发送到浏览器,内容处置标题为“inline; filename = [filename]”。
我希望有所帮助!
答案 4 :(得分:4)
使用ASP.NET MVC将文件流式传输到浏览器的绝对最简单的方法是:
public ActionResult DownloadFile() {
return File(@"c:\path\to\somefile.pdf", "application/pdf", "Your Filename.pdf");
}
这比@ azarc3建议的方法更容易,因为你甚至不需要读取字节。
**编辑**
显然我的“回答”与OP的问题相同。但我没有面对他遇到的问题。可能这是旧版ASP.NET MVC的一个问题?
答案 5 :(得分: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;
}
}