Bagaimana cara menampilkan file untuk diunduh dari pengontrol MVC?

109

Di WebForms, saya biasanya memiliki kode seperti ini agar browser menampilkan munculan "Unduh File" dengan jenis file yang berubah-ubah, seperti PDF, dan nama file:

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()

Bagaimana cara menyelesaikan tugas yang sama di ASP.NET MVC?

mgnoonan.dll
sumber

Jawaban:

181

Kembalikan a FileResultatau FileStreamResultdari tindakan Anda, bergantung pada apakah file tersebut ada atau Anda membuatnya dengan cepat.

public ActionResult GetPdf(string filename)
{
    return File(filename, "application/pdf", Server.UrlEncode(filename));
}
tvanfosson.dll
sumber
14
Ini adalah contoh yang bagus mengapa ASP.NET MVC mengagumkan. Apa yang sebelumnya harus Anda lakukan dalam 9 baris kode yang tampak membingungkan dapat dilakukan dalam satu baris. Jauh lebih mudah!
Jon Kruger
Terima kasih tvanfosson, saya mencari solusi terbaik untuk melakukan ini, dan ini bagus.
Mark Kadlec
1
Ini membutuhkan ekstensi file pada nama file atau sebaliknya itu akan sepenuhnya mengabaikan nama file dan jenis konten dan hanya mencoba untuk mengalirkan file ke browser. Ini juga hanya akan menggunakan nama halaman web jika browser tidak mengenali jenis konten (yaitu aliran oktet) ketika memaksa unduhan dan tidak akan memiliki ekstensi sama sekali.
RichC
62

Untuk memaksa mengunduh file PDF, alih-alih ditangani oleh plugin PDF browser:

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

Jika Anda ingin membiarkan browser menangani perilaku defaultnya (plugin atau download), cukup kirimkan dua parameter.

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

Anda harus menggunakan parameter ketiga untuk menentukan nama file pada dialog browser.

PEMBARUAN: Charlino benar, ketika meneruskan parameter ketiga (nama file unduhan) Content-Disposition: attachment;akan ditambahkan ke Header Respons Http. Solusi saya adalah mengirim application\force-downloadsebagai tipe pantomim, tetapi ini menimbulkan masalah dengan nama file unduhan sehingga parameter ketiga diperlukan untuk mengirim nama file yang baik, oleh karena itu menghilangkan kebutuhan untuk memaksa unduhan .

guzart
sumber
6
Secara teknis bukan itu yang terjadi. Secara teknis ketika Anda menambahkan parameter ketiga, kerangka kerja MVC menambahkan tajuk content-disposition: attachment; filename=MyRenamedFile.pdf- inilah yang memaksa unduhan. Saya sarankan Anda mengembalikan tipe MIME application/pdf.
Charlino
2
Terima kasih Charlino, saya tidak menyadari parameter ketiga melakukan itu, saya pikir itu hanya untuk mengubah nama file.
guzart
2
+1 untuk memperbarui jawaban Anda dan menjelaskan parameter + Content-Disposition: attachment;hubungan ketiga .
Charlino
7

Anda dapat melakukan hal yang sama di Razor atau di Controller, seperti ..

@{
    //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");
}

Atau di Controller ..

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

    return View();
}

Saya mencoba ini di Chrome dan IE9, keduanya mengunduh file pdf.

Saya mungkin harus menambahkan saya menggunakan RazorPDF untuk menghasilkan PDF saya. Ini adalah blog tentang itu: http://nyveldt.com/blog/post/Introducing-RazorPDF

Rosdi Kasim
sumber
4

Anda harus melihat metode File dari Controller. Untuk itulah tepatnya. Ini mengembalikan FilePathResult, bukan ActionResult.

Martin Peck
sumber
3

mgnoonan,

Anda dapat melakukan ini untuk mengembalikan 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");
    }
}
Leniel Maccaferri
sumber
1

Meskipun hasil tindakan standar FileContentResult atau FileStreamResult dapat digunakan untuk mengunduh file, agar dapat digunakan kembali, membuat hasil tindakan kustom mungkin merupakan solusi terbaik.

Sebagai contoh, mari buat hasil tindakan kustom untuk mengekspor data ke file Excel dengan cepat untuk diunduh.

Kelas ExcelResult mewarisi kelas ActionResult abstrak dan menggantikan metode ExecuteResult.

Kami menggunakan paket FastMember untuk membuat DataTable dari objek IEnumerable dan paket ClosedXML untuk membuat file Excel dari DataTable.

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

Di Kontroler gunakan hasil tindakan ExcelResult kustom sebagai berikut

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

Karena kita mendownload file menggunakan HttpGet, buat View kosong tanpa model dan layout kosong.

Posting blog tentang hasil tindakan kustom untuk mendownload file yang dibuat dengan cepat:

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

Ahmetcan Ozturk
sumber
-4

Gunakan jenis file .ashx dan gunakan kode yang sama

0100110010101
sumber