Як я можу представити файл для завантаження з контролера MVC?


109

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

Як виконати те саме завдання в ASP.NET MVC?

Відповіді:


181

Поверніть свою дію FileResultабо FileStreamResultвід неї, залежно від того, існує файл чи ви створюєте його під час руху.

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

14
Це чудовий приклад того, чому ASP.NET MVC приголомшливий. Те, що раніше потрібно було зробити в 9 рядках заплутаного вигляду коду, можна зробити в одному рядку. Так набагато простіше!
Джон Крюгер

Дякую tvanfosson, я шукав найкраще рішення для цього, і це чудово.
Марк Кадлец

1
Для цього потрібне розширення файлу на ім’я файлу, інакше воно повністю ігнорує ім'я файлу та тип вмісту та просто спробує передати файл у браузер. Він також просто використовуватиме ім'я веб-сторінки, якщо браузер не розпізнає тип контенту (тобто октет-потік), коли він змушує завантажувати його і не матиме розширення взагалі.
RichC

62

Щоб змусити завантажити PDF-файл, а не обробляти його плагіном PDF-браузера:

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

Якщо ви хочете дозволити браузеру керуватися за його типовою поведінкою (плагін або завантаження), просто надішліть два параметри.

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

Вам потрібно буде скористатись третім параметром, щоб вказати ім'я файлу у діалоговому вікні браузера.

ОНОВЛЕННЯ: Чарліно має рацію при передачі третього параметра (ім'я файлу завантаження), Content-Disposition: attachment;доданого до заголовка відповіді Http. Моє рішення полягало в надсиланні application\force-downloadяк mime-type, але це створює проблему з іменем файлу завантаження, тому третій параметр потрібен для того, щоб надіслати гарне ім’я файлу, тому усуваючи необхідність примусового завантаження .


6
Технічно це не те, що відбувається. Технічно при додаванні третього параметра рамка MVC додає заголовок content-disposition: attachment; filename=MyRenamedFile.pdf- ось що змушує завантаження. Я б запропонував вам повернути тип MIME до application/pdf.
Чарліно

2
Дякую Чарліно, я не зрозумів, що третій параметр це робить, я подумав, що це просто змінити ім'я файлу.
гузарт

2
+1 для оновлення відповіді та пояснення третього параметра + Content-Disposition: attachment;співвідношення.
Чарліно

7

Ви можете зробити те ж саме в Razor або в контролері, як так ..

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

Або в контролері ..

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

    return View();
}

Я спробував це в Chrome і IE9, і те, і інше - це завантаження файлу pdf.

Напевно, слід додати, що я використовую RazorPDF для створення своїх PDF-файлів. Ось блог про це: http://nyveldt.com/blog/post/Introducing-RazorPDF


4

Ви повинні подивитися на метод Файл контролера. Це саме те, для чого це потрібно. Він повертає FilePathResult замість ActionResult.


3

мгноонан,

Ви можете зробити це, щоб повернути 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");
    }
}

1

Хоча стандартні результати дій FileContentResult або FileStreamResult можуть використовуватися для завантаження файлів для їх повторного використання, створення найкращого результату дій може бути найкращим рішенням.

Як приклад, давайте створимо користувальницький результат дії для експорту даних у файли Excel на ходу для завантаження.

Клас ExcelResult успадковує абстрактний клас ActionResult і замінює метод ExecuteResult.

Ми використовуємо пакет FastMember для створення DataTable з об'єкта IEnumerable та пакет ClosedXML для створення файлу Excel з 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());
                }
            }
        }
    }
}

У контролері використовуйте спеціальний результат дії 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);
}

Оскільки ми завантажуємо файл за допомогою HttpGet, створимо порожній перегляд без моделі та порожнього макета.

Повідомлення в блозі про користувацький результат дії для завантаження файлів, створених на ходу:

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


-4

Використовуйте тип файлу .ashx і використовуйте той самий код

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.