web-dev-qa-db-fra.com

Comment retourner PDF au navigateur dans MVC?

J'ai ce code de démonstration pour iTextSharp

    Document document = new Document();
    try
    {
        PdfWriter.GetInstance(document, new FileStream("Chap0101.pdf", FileMode.Create));

        document.Open();

        document.Add(new Paragraph("Hello World"));

    }
    catch (DocumentException de)
    {
        Console.Error.WriteLine(de.Message);
    }
    catch (IOException ioe)
    {
        Console.Error.WriteLine(ioe.Message);
    }

    document.Close();

Comment faire pour que le contrôleur renvoie le document pdf au navigateur?

MODIFIER:

L'exécution de ce code ouvre Acrobat mais un message d'erreur "Le fichier est endommagé et ne peut pas être réparé"

  public FileStreamResult pdf()
    {
        MemoryStream m = new MemoryStream();
        Document document = new Document();
        PdfWriter.GetInstance(document, m);
        document.Open();
        document.Add(new Paragraph("Hello World"));
        document.Add(new Paragraph(DateTime.Now.ToString()));
        m.Position = 0;

        return File(m, "application/pdf");
    }

Des idées pourquoi cela ne fonctionne pas?

115
Tony Borf

Je l'ai obtenu avec ce code.

using iTextSharp.text;
using iTextSharp.text.pdf;

public FileStreamResult pdf()
{
    MemoryStream workStream = new MemoryStream();
    Document document = new Document();
    PdfWriter.GetInstance(document, workStream).CloseStream = false;

    document.Open();
    document.Add(new Paragraph("Hello World"));
    document.Add(new Paragraph(DateTime.Now.ToString()));
    document.Close();

    byte[] byteInfo = workStream.ToArray();
    workStream.Write(byteInfo, 0, byteInfo.Length);
    workStream.Position = 0;

    return new FileStreamResult(workStream, "application/pdf");    
}
60
Tony Borf

Retourne un FileContentResult. La dernière ligne de votre action de contrôleur serait quelque chose comme:

return File("Chap0101.pdf", "application/pdf");

Si vous générez ceci PDF dynamiquement, il peut être préférable d’utiliser un MemoryStream et de créer le document en mémoire au lieu de l’enregistrer dans un fichier. Le code ressemblerait à ceci:

Document document = new Document();

MemoryStream stream = new MemoryStream();

try
{
    PdfWriter pdfWriter = PdfWriter.GetInstance(document, stream);
    pdfWriter.CloseStream = false;

    document.Open();
    document.Add(new Paragraph("Hello World"));
}
catch (DocumentException de)
{
    Console.Error.WriteLine(de.Message);
}
catch (IOException ioe)
{
    Console.Error.WriteLine(ioe.Message);
}

document.Close();

stream.Flush(); //Always catches me out
stream.Position = 0; //Not sure if this is required

return File(stream, "application/pdf", "DownloadName.pdf");
123
Geoff

Vous devez spécifier:

Response.AppendHeader("content-disposition", "inline; filename=file.pdf");
return new FileStreamResult(stream, "application/pdf")

Pour que le fichier soit ouvert directement dans le navigateur au lieu d'être téléchargé

19
Machinegon

Si vous renvoyez un FileResult à partir de votre méthode d'action et utilisez la méthode d'extension File() sur le contrôleur, il est assez facile de faire ce que vous voulez. Il y a des substitutions sur la méthode File() qui prendra le contenu binaire du fichier, le chemin d'accès au fichier ou un Stream.

public FileResult DownloadFile()
{
    return File("path\\to\\pdf.pdf", "application/pdf");
}
16
NerdFury

J'ai rencontré des problèmes similaires et je suis tombé sur une solution. J'ai utilisé deux publications, l'une de pile qui montre la méthode de retour pour le téléchargement et l'autre n qui montre une solution de travail pour ItextSharp et MVC.

public FileStreamResult About()
{
    // Set up the document and the MS to write it to and create the PDF writer instance
    MemoryStream ms = new MemoryStream();
    Document document = new Document(PageSize.A4.Rotate());
    PdfWriter writer = PdfWriter.GetInstance(document, ms);

    // Open the PDF document
    document.Open();

    // Set up fonts used in the document
    Font font_heading_1 = FontFactory.GetFont(FontFactory.TIMES_ROMAN, 19, Font.BOLD);
    Font font_body = FontFactory.GetFont(FontFactory.TIMES_ROMAN, 9);

    // Create the heading paragraph with the headig font
    Paragraph paragraph;
    paragraph = new Paragraph("Hello world!", font_heading_1);

    // Add a horizontal line below the headig text and add it to the paragraph
    iTextSharp.text.pdf.draw.VerticalPositionMark seperator = new iTextSharp.text.pdf.draw.LineSeparator();
    seperator.Offset = -6f;
    paragraph.Add(seperator);

    // Add paragraph to document
    document.Add(paragraph);

    // Close the PDF document
    document.Close();

    // Hat tip to David for his code on stackoverflow for this bit
    // https://stackoverflow.com/questions/779430/asp-net-mvc-how-to-get-view-to-generate-pdf
    byte[] file = ms.ToArray();
    MemoryStream output = new MemoryStream();
    output.Write(file, 0, file.Length);
    output.Position = 0;

    HttpContext.Response.AddHeader("content-disposition","attachment; filename=form.pdf");


    // Return the output stream
    return File(output, "application/pdf"); //new FileStreamResult(output, "application/pdf");
}
11
littlechris

Vous pouvez créer une classe personnalisée pour modifier le type de contenu et ajouter le fichier à la réponse.

http://haacked.com/archive/2008/05/10/writing-a-custom-file-download-action-result-for-asp.net-mvc.aspx

3
Chris Kooken

Je sais que cette question est ancienne mais je pensais partager cela car je ne trouvais rien de semblable.

Je voulais créer mes vues/modèles normalement à l’aide de Razor et les faire au format Pdfs .

De cette façon, je contrôlais la présentation pdf en utilisant la sortie HTML standard plutôt que de déterminer comment mettre en page le document avec iTextSharp.

Le projet et le code source sont disponibles ici avec les instructions d’installation de nuget:

https://github.com/andyhutch77/MvcRazorToPdf

Install-Package MvcRazorToPdf
3
hutchonoid

Vous feriez normalement un Response.Flush suivi d'un Response.Close, mais pour une raison quelconque, la bibliothèque iTextSharp ne semble pas aimer ça. Les données ne parviennent pas à traverser et Adobe pense que le PDF est corrompu. Abandonnez la fonction Response.Close et voyez si vos résultats sont meilleurs:

Response.Clear();
Response.ContentType = "application/pdf";
Response.AppendHeader("Content-disposition", "attachment; filename=file.pdf"); // open in a new window
Response.OutputStream.Write(outStream.GetBuffer(), 0, outStream.GetBuffer().Length);
Response.Flush();

// For some reason, if we close the Response stream, the PDF doesn't make it through
//Response.Close();
2
JML
HttpContext.Response.AddHeader("content-disposition","attachment; filename=form.pdf");

si le nom de fichier est en train de générer dynamiquement, alors comment définir le nom de fichier ici, il est généré via guid ici.

2
S.J.Lee

FileStreamResult fonctionne certainement. Mais si vous regardez Microsoft Docs , il hérite de ActionResult -> FileResult, qui a une autre classe dérivée FileContentResult . Il "envoie le contenu d'un fichier binaire à la réponse". Donc, si vous avez déjà l'octet [], vous devriez simplement utiliser FileContentResult à la place.

public ActionResult DisplayPDF()
{
    byte[] byteArray = GetPdfFromWhatever();

    return new FileContentResult(byteArray, "application/pdf");
}
1
Weihui Guo

si vous renvoyez des données var-binary de la base de données à afficher PDF dans une fenêtre contextuelle ou un navigateur signifie que vous suivez ce code: -

Voir la page:

@using (Html.BeginForm("DisplayPDF", "Scan", FormMethod.Post))
    {
        <a href="javascript:;" onclick="document.forms[0].submit();">View PDF</a>
    }

contrôleur de numérisation:

public ActionResult DisplayPDF()
        {
            byte[] byteArray = GetPdfFromDB(4);
            MemoryStream pdfStream = new MemoryStream();
            pdfStream.Write(byteArray, 0, byteArray.Length);
            pdfStream.Position = 0;
            return new FileStreamResult(pdfStream, "application/pdf");
        }

        private byte[] GetPdfFromDB(int id)
        {
            #region
            byte[] bytes = { };
            string constr = System.Configuration.ConfigurationManager.ConnectionStrings["Connection"].ConnectionString;
            using (SqlConnection con = new SqlConnection(constr))
            {
                using (SqlCommand cmd = new SqlCommand())
                {
                    cmd.CommandText = "SELECT Scan_Pdf_File FROM PWF_InvoiceMain WHERE InvoiceID=@Id and Enabled = 1";
                    cmd.Parameters.AddWithValue("@Id", id);
                    cmd.Connection = con;
                    con.Open();
                    using (SqlDataReader sdr = cmd.ExecuteReader())
                    {
                        if (sdr.HasRows == true)
                        {
                            sdr.Read();
                            bytes = (byte[])sdr["Scan_Pdf_File"];
                        }
                    }
                    con.Close();
                }
            }

            return bytes;
            #endregion
        }
1
ethiraj