How to return PDF to browser in MVC?
Solution 1
I got it working with this 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");
}
Solution 2
Return a FileContentResult
. The last line in your controller action would be something like:
return File("Chap0101.pdf", "application/pdf");
If you are generating this PDF dynamically, it may be better to use a MemoryStream
, and create the document in memory instead of saving to file. The code would be something like:
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");
Solution 3
You must specify :
Response.AppendHeader("content-disposition", "inline; filename=file.pdf");
return new FileStreamResult(stream, "application/pdf")
For the file to be opened directly in the browser instead of being downloaded
Solution 4
If you return a FileResult
from your action method, and use the File()
extension method on the controller, doing what you want is pretty easy. There are overrides on the File()
method that will take the binary contents of the file, the path to the file, or a Stream
.
public FileResult DownloadFile()
{
return File("path\\to\\pdf.pdf", "application/pdf");
}
Solution 5
I've run into similar problems and I've stumbled accross a solution. I used two posts, one from stack that shows the method to return for download and another one that shows a working solution for ItextSharp and 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");
}
Tony Borf
Updated on September 13, 2020Comments
-
Tony Borf over 3 years
I have this demo code for 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();
How do I get the controller to return the pdf document to the browser?
EDIT:
Running this code does open Acrobat but I get an error message "The file is damaged and could not be repaired"
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"); }
Any ideas why this does not work?
-
Geoff over 14 years@Tony, you need to close the document first and flush the stream.
-
encore2097 over 14 yearsAs stated at the top of that blog post, the FileResult comes out of the box with Asp.Net MVC, so coding your own is no longer necessary.
-
littlechris over 14 yearsGeoff, I 'm try to achieve this, but having similar problems. I get an error at run time "Cannot access a closed Stream" But if I don't close it nothing is returned.
-
Geoff over 14 yearsThanks @littlechris. You are right, I have edited the code to inclued pdfWriter.CloseStream = false;
-
michael almost 13 yearsDocument,PdfWriter and Paragraph are unrecognized .What namespace to be added?
-
Kobi over 12 yearsI am a little concerned there is not a single
using
statement in any example I can find... Is it not needed here? I think you have at least 3 disposable objects... -
Alberto León almost 12 yearsYes @Geoff stream.Possition = 0; is required, if you do not write it, at the moment of open the PDF Acrobat throws an error "File damaged"
-
DigiOz Multimedia almost 12 yearsExcellent Example! This was exactly what i was looking for! -- Pete --
-
vbullinger over 11 yearsYes, using statements are good. If this is a production app with more than, say... ONE person using it, this may cause problems...
-
vbullinger over 11 yearsUsings? Close? Dispose? Flush? Who cares about memory leaks?
-
Ed Spencer about 10 yearsThe FileSteamResult will close the stream for you. See this answer stackoverflow.com/a/10429907/228770
-
CountMurphy about 9 yearsCannot implicitly convert type 'System.Web.Mvc.FileStreamResult' to 'System.Web.Mvc.FileContentResult'
-
Percy about 8 years@Geoff thanks for this - the
stream.flush();
andstream.Position = 0;
are both required. Yours is the only example I found that had these.... Without these lines an empty document is returned. -
Julien N almost 8 years@Rick
stream.Flush()
is useless with MemoryStream, but necessary with other kinds of streams. From documentation : "Overrides the Stream.Flush method so that no action is performed." -
Scottie over 7 yearsThank you! I was searching everywhere on how to do this!!
-
ThanhLD over 5 yearsThe important thing is set Position = 0. haha. thank you @TonyBorf
-
Jeff Reddy over 4 yearsI think for the first example you give, the return type should be FilePathResult.
-
redwards510 over 2 yearsand obviously, you can do
return File(yourByteArray, "application/pdf");
if you have a byte array instead of a stream.