Come restituire PDF al browser in MVC?

Ho questo codice demo per 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(); 

Come posso ottenere il controller per restituire il documento PDF al browser?

MODIFICARE:

L’esecuzione di questo codice apre Acrobat ma viene visualizzato un messaggio di errore “Il file è danneggiato e non è stato ansible ripararlo”

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

Qualche idea sul perché questo non funziona?

Restituisce un FileContentResult . L’ultima riga nell’azione del controller sarà simile a:

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

Se si sta generando questo PDF in modo dinamico, potrebbe essere preferibile utilizzare un MemoryStream e creare il documento in memoria anziché salvare su file. Il codice sarebbe qualcosa di simile:

 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"); 

Ho capito che funziona con questo codice.

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

Devi specificare:

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

Per il file da aprire direttamente nel browser anziché essere scaricato

Se si restituisce un FileResult dal metodo di azione e si utilizza il metodo di estensione File() sul controller, fare ciò che si desidera è piuttosto semplice. Esistono delle sostituzioni sul metodo File() che prenderà il contenuto binario del file, il percorso del file o un Stream .

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

Ho incontrato problemi simili e sono incappato in una soluzione. Ho usato due post, uno da stack che mostra il metodo da restituire per il download e un altro che mostra una soluzione funzionante per ItextSharp e 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"); } 

È ansible creare una class personalizzata per modificare il tipo di contenuto e aggiungere il file alla risposta.

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

So che questa domanda è vecchia ma ho pensato di condividerla perché non riuscivo a trovare nulla di simile.

Volevo creare le mie viste / modelli normalmente usando Razor e renderli renderizzati come Pdf .

In questo modo ho avuto il controllo della presentazione in pdf usando l’output html standard invece di capire come impaginare il documento usando iTextSharp.

Il progetto e il codice sorgente sono disponibili qui con le istruzioni di installazione di nuget:

https://github.com/andyhutch77/MvcRazorToPdf

 Install-Package MvcRazorToPdf 

Normalmente farai una Response.Flush seguita da Response.Close, ma per qualche motivo la libreria iTextSharp non sembra gradire questo. I dati non arrivano e Adobe pensa che il PDF sia corrotto. Lasciare fuori la funzione Response.Close e vedere se i risultati sono migliori:

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

se si restituiscono dati var-binari da DB per visualizzare PDF su popup o browser significa seguire questo codice: –

Visualizza la pagina:

 @using (Html.BeginForm("DisplayPDF", "Scan", FormMethod.Post)) { View PDF } 

Controller di scansione:

 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 [email protected] 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 } 
 HttpContext.Response.AddHeader("content-disposition","attachment; filename=form.pdf"); 

se il nome del file sta generando dynamicmente, allora come definire il nome del file qui, sta generando tramite guida qui.