views:

1172

answers:

6

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?

+4  A: 

You can create a custom class to modify the content type and add the file to the response.

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

Climber104
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.
NerdFury
+4  A: 

Retern a FileContentResult. So the last line in your controler would be somthing like:

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

If you are generating this PDF dynamicaly it may be better to use a Memory stream and create the document in memory instead of saving to file. The code would 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.Possition = 0; //Not sure if this is required
return File(stream, "application/pdf");
Geoff
See my edit above
Tony Borf
@Tony, you need to close the document first and flush the stream.
Geoff
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.
littlechris
Thanks @littlechris. You are right, I have edited the code to inclued pdfWriter.CloseStream = false;
Geoff
A: 

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");
}
NerdFury
+3  A: 

I got it working with this code.

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

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

    return new FileStreamResult(outputStream, "application/pdf");
}

I also needed to add a second memory stream to get it to work.

Tony Borf
A: 

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
    // http://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");
}
littlechris
A: 

You would normally do a Response.Flush followed by a Response.Close, but for some reason the iTextSharp library doesn't seem to like this. The data doesn't make it through and Adobe thinks the PDF is corrupt. Leave out the Response.Close function and see if your results are better:

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