How to return PDF to browser in MVC?

227,099

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");
}
Share:
227,099
Tony Borf
Author by

Tony Borf

Updated on September 13, 2020

Comments

  • Tony Borf
    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
    Geoff over 14 years
    @Tony, you need to close the document first and flush the stream.
  • encore2097
    encore2097 over 14 years
    As 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
    littlechris over 14 years
    Geoff, 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
    Geoff over 14 years
    Thanks @littlechris. You are right, I have edited the code to inclued pdfWriter.CloseStream = false;
  • michael
    michael almost 13 years
    Document,PdfWriter and Paragraph are unrecognized .What namespace to be added?
  • Kobi
    Kobi over 12 years
    I 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
    Alberto León almost 12 years
    Yes @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
    DigiOz Multimedia almost 12 years
    Excellent Example! This was exactly what i was looking for! -- Pete --
  • vbullinger
    vbullinger over 11 years
    Yes, using statements are good. If this is a production app with more than, say... ONE person using it, this may cause problems...
  • vbullinger
    vbullinger over 11 years
    Usings? Close? Dispose? Flush? Who cares about memory leaks?
  • Ed Spencer
    Ed Spencer about 10 years
    The FileSteamResult will close the stream for you. See this answer stackoverflow.com/a/10429907/228770
  • CountMurphy
    CountMurphy about 9 years
    Cannot implicitly convert type 'System.Web.Mvc.FileStreamResult' to 'System.Web.Mvc.FileContentResult'
  • Percy
    Percy about 8 years
    @Geoff thanks for this - the stream.flush(); and stream.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
    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
    Scottie over 7 years
    Thank you! I was searching everywhere on how to do this!!
  • ThanhLD
    ThanhLD over 5 years
    The important thing is set Position = 0. haha. thank you @TonyBorf
  • Jeff Reddy
    Jeff Reddy over 4 years
    I think for the first example you give, the return type should be FilePathResult.
  • redwards510
    redwards510 over 2 years
    and obviously, you can do return File(yourByteArray, "application/pdf"); if you have a byte array instead of a stream.