asp.net-mvc 如何提供从 MVC 控制器下载的文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/730699/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-07 23:28:50  来源:igfitidea点击:

How can I present a file for download from an MVC controller?

asp.net-mvcdownload

提问by mgnoonan

In WebForms, I would normally have code like this to let the browser present a "Download File" popup with an arbitrary file type, like a PDF, and a filename:

在 WebForms 中,我通常会有这样的代码,让浏览器显示一个“下载文件”弹出窗口,其中包含任意文件类型,如 PDF 和文件名:

Response.Clear()
Response.ClearHeaders()
''# Send the file to the output stream
Response.Buffer = True

Response.AddHeader("Content-Length", pdfData.Length.ToString())
Response.AddHeader("Content-Disposition", "attachment; filename= " & Server.HtmlEncode(filename))

''# Set the output stream to the correct content type (PDF).
Response.ContentType = "application/pdf"

''# Output the file
Response.BinaryWrite(pdfData)

''# Flushing the Response to display the serialized data
''# to the client browser.
Response.Flush()
Response.End()

How do I accomplish the same task in ASP.NET MVC?

如何在 ASP.NET MVC 中完成相同的任务?

回答by tvanfosson

Return a FileResultor FileStreamResultfrom your action, depending on whether the file exists or you create it on the fly.

从您的操作中返回 aFileResultFileStreamResult,具体取决于文件是否存在或您即时创建。

public ActionResult GetPdf(string filename)
{
    return File(filename, "application/pdf", Server.UrlEncode(filename));
}

回答by guzart

To force the download of a PDF file, instead of being handled by the browser's PDF plugin:

要强制下载 PDF 文件,而不是由浏览器的 PDF 插件处理:

public ActionResult DownloadPDF()
{
    return File("~/Content/MyFile.pdf", "application/pdf", "MyRenamedFile.pdf");
}

If you want to let the browser handle by its default behavior (plugin or download), just send two parameters.

如果您想让浏览器按其默认行为(插件或下载)进行处理,只需发送两个参数即可。

public ActionResult DownloadPDF()
{
    return File("~/Content/MyFile.pdf", "application/pdf");
}

You'll need to use the third parameter to specify a name for the file on the browser dialog.

您需要使用第三个参数在浏览器对话框中指定文件的名称。

UPDATE: Charlino is right, when passing the third parameter (download filename) Content-Disposition: attachment;gets added to the Http Response Header. My solution was to send application\force-downloadas the mime-type, but this generates a problem with the filename of the download so the third parameter is required to send a good filename, therefore eliminating the need to force a download.

更新:Charlino 是对的,当传递第三个参数(下载文件名)Content-Disposition: attachment;被添加到 Http 响应头时。我的解决方案是application\force-download作为 mime 类型发送,但这会产生下载文件名的问题,因此需要第三个参数来发送一个好的文件名,因此无需强制下载

回答by Rosdi Kasim

You can do the same in Razor or in the Controller, like so..

你可以在 Razor 或 Controller 中做同样的事情,就像这样..

@{
    //do this on the top most of your View, immediately after `using` statement
    Response.ContentType = "application/pdf";
    Response.AddHeader("Content-Disposition", "attachment; filename=receipt.pdf");
}

Or in the Controller..

或者在控制器中..

public ActionResult Receipt() {
    Response.ContentType = "application/pdf";
    Response.AddHeader("Content-Disposition", "attachment; filename=receipt.pdf");

    return View();
}

I tried this in Chrome and IE9, both is downloading the pdf file.

我在 Chrome 和 IE9 中尝试过这个,两者都在下载 pdf 文件。

I probably should add I am using RazorPDFto generate my PDFs. Here is a blog about it: http://nyveldt.com/blog/post/Introducing-RazorPDF

我可能应该添加我正在使用RazorPDF生成我的 PDF。这是一个关于它的博客:http: //nyveldt.com/blog/post/Introducing-RazorPDF

回答by Martin Peck

You should look at the File method of the Controller. This is exactly what it's for. It returns a FilePathResult instead of an ActionResult.

您应该查看控制器的 File 方法。这正是它的用途。它返回 FilePathResult 而不是 ActionResult。

回答by Leniel Maccaferri

mgnoonan,

米努南,

You can do this to return a FileStream:

您可以这样做以返回 FileStream:

/// <summary>
/// Creates a new Excel spreadsheet based on a template using the NPOI library.
/// The template is changed in memory and a copy of it is sent to
/// the user computer through a file stream.
/// </summary>
/// <returns>Excel report</returns>
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult NPOICreate()
{
    try
    {
        // Opening the Excel template...
        FileStream fs =
            new FileStream(Server.MapPath(@"\Content\NPOITemplate.xls"), FileMode.Open, FileAccess.Read);

        // Getting the complete workbook...
        HSSFWorkbook templateWorkbook = new HSSFWorkbook(fs, true);

        // Getting the worksheet by its name...
        HSSFSheet sheet = templateWorkbook.GetSheet("Sheet1");

        // Getting the row... 0 is the first row.
        HSSFRow dataRow = sheet.GetRow(4);

        // Setting the value 77 at row 5 column 1
        dataRow.GetCell(0).SetCellValue(77);

        // Forcing formula recalculation...
        sheet.ForceFormulaRecalculation = true;

        MemoryStream ms = new MemoryStream();

        // Writing the workbook content to the FileStream...
        templateWorkbook.Write(ms);

        TempData["Message"] = "Excel report created successfully!";

        // Sending the server processed data back to the user computer...
        return File(ms.ToArray(), "application/vnd.ms-excel", "NPOINewFile.xls");
    }
    catch(Exception ex)
    {
        TempData["Message"] = "Oops! Something went wrong.";

        return RedirectToAction("NPOI");
    }
}

回答by Ahmetcan Ozturk

Although standard action results FileContentResult or FileStreamResult may be used for downloading files, for reusability, creating a custom action result might be the best solution.

尽管标准操作结果 FileContentResult 或 FileStreamResult 可用于下载文件,但为了可重用性,创建自定义操作结果可能是最佳解决方案。

As an example let's create a custom action result for exporting data to Excel files on the fly for download.

作为示例,让我们创建一个自定义操作结果,用于将数据即时导出到 Excel 文件以供下载。

ExcelResult class inherits abstract ActionResult class and overrides the ExecuteResult method.

ExcelResult 类继承抽象 ActionResult 类并覆盖 ExecuteResult 方法。

We are using FastMember package for creating DataTable from IEnumerable object and ClosedXML package for creating Excel file from the DataTable.

我们使用 FastMember 包从 IEnumerable 对象创建数据表,并使用 ClosedXML 包从数据表创建 Excel 文件。

public class ExcelResult<T> : ActionResult
{
    private DataTable dataTable;
    private string fileName;

    public ExcelResult(IEnumerable<T> data, string filename, string[] columns)
    {
        this.dataTable = new DataTable();
        using (var reader = ObjectReader.Create(data, columns))
        {
            dataTable.Load(reader);
        }
        this.fileName = filename;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        if (context != null)
        {
            var response = context.HttpContext.Response;
            response.Clear();
            response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
            response.AddHeader("content-disposition", string.Format(@"attachment;filename=""{0}""", fileName));
            using (XLWorkbook wb = new XLWorkbook())
            {
                wb.Worksheets.Add(dataTable, "Sheet1");
                using (MemoryStream stream = new MemoryStream())
                {
                    wb.SaveAs(stream);
                    response.BinaryWrite(stream.ToArray());
                }
            }
        }
    }
}

In the Controller use the custom ExcelResult action result as follows

在控制器中使用自定义 ExcelResult 操作结果如下

[HttpGet]
public async Task<ExcelResult<MyViewModel>> ExportToExcel()
{
    var model = new Models.MyDataModel();
    var items = await model.GetItems();
    string[] columns = new string[] { "Column1", "Column2", "Column3" };
    string filename = "mydata.xlsx";
    return new ExcelResult<MyViewModel>(items, filename, columns);
}

Since we are downloading the file using HttpGet, create an empty View without model and empty layout.

由于我们使用 HttpGet 下载文件,因此创建一个没有模型和空布局的空视图。

Blog post about custom action result for downloading files that are created on the fly:

关于下载动态创建的文件的自定义操作结果的博客文章:

https://acanozturk.blogspot.com/2019/03/custom-actionresult-for-files-in-aspnet.html

https://acanozturk.blogspot.com/2019/03/custom-actionresult-for-files-in-aspnet.html

回答by 0100110010101

Use .ashx file type and use the same code

使用 .ashx 文件类型并使用相同的代码