110 votes

Comment présenter un fichier à télécharger à partir d'un contrôleur MVC ?

Dans WebForms, j'aurais normalement un code comme celui-ci pour permettre au navigateur de présenter une fenêtre popup "Download File" avec un type de fichier arbitraire, comme un PDF, et un nom de fichier :

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

Comment puis-je accomplir la même tâche en ASP.NET MVC ?

183voto

tvanfosson Points 268301

Retourner un FileResult o FileStreamResult de votre action, selon que le fichier existe ou que vous le créez à la volée.

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

14 votes

C'est un excellent exemple de la raison pour laquelle ASP.NET MVC est génial. Ce que vous deviez faire auparavant en 9 lignes de code confus peut être fait en une seule ligne. C'est tellement plus facile !

0 votes

Merci tvanfosson, j'ai cherché la meilleure solution pour faire cela, et celle-ci est géniale.

1 votes

Il faut que le nom du fichier comporte une extension de fichier, sinon il ignorera complètement le nom du fichier et le type de contenu et tentera simplement de transmettre le fichier au navigateur. Il utilisera également le nom de la page web si le navigateur ne reconnaît pas le type de contenu (c'est-à-dire octet-stream) lorsqu'il force le téléchargement et il n'aura pas d'extension du tout.

64voto

guzart Points 2269

Pour forcer le téléchargement d'un fichier PDF, au lieu qu'il soit géré par le plugin PDF du navigateur :

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

Si vous voulez laisser le navigateur gérer par son comportement par défaut (plugin ou téléchargement), il suffit d'envoyer deux paramètres.

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

Vous devrez utiliser le troisième paramètre pour spécifier un nom pour le fichier dans la boîte de dialogue du navigateur.

UPDATE : Charlino a raison, en passant le troisième paramètre (nom du fichier de téléchargement) Content-Disposition: attachment; est ajouté à l'en-tête de la réponse Http. Ma solution était d'envoyer application\force-download comme type de fichier (mime-type), mais cela génère un problème avec le nom de fichier du téléchargement. Le troisième paramètre est donc nécessaire pour envoyer un bon nom de fichier, ce qui élimine la nécessité de l'option forcer un téléchargement .

6 votes

Techniquement, ce n'est pas ce qui se passe. Techniquement, lorsque vous ajoutez le troisième paramètre, le framework MVC ajoute l'en-tête content-disposition: attachment; filename=MyRenamedFile.pdf - c'est ce qui force le téléchargement. Je vous suggère de remettre le type MIME à application/pdf .

2 votes

Merci Charlino, je n'avais pas réalisé que le troisième paramètre faisait cela, je pensais que c'était juste pour changer le nom du fichier.

2 votes

+1 pour avoir mis à jour votre réponse et expliqué le troisième paramètre + Content-Disposition: attachment; relation.

8voto

Rosdi Kasim Points 3588

Vous pouvez faire la même chose dans Razor ou dans le contrôleur, comme suit

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

Ou dans le contrôleur..

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

    return View();
}

J'ai essayé avec Chrome et IE9, les deux téléchargeant le fichier pdf.

Je devrais probablement ajouter que j'utilise RazorPDF pour générer mes PDF. Voici un blog à ce sujet : http://nyveldt.com/blog/post/Introducing-RazorPDF

4voto

Martin Peck Points 8078

Vous devriez examiner la méthode File du contrôleur. C'est exactement ce à quoi elle sert. Elle renvoie un FilePathResult au lieu d'un ActionResult.

3voto

Leniel Macaferi Points 38324

Mgnoonan,

Vous pouvez le faire pour retourner un 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");
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X