I am trying to generate a pdf out of an MVC3 webpage. I've viewed all the usual tutorials, but as is often the case when one is in a hurry and doesn't really know what one is doing, I'm making a dog's breakfast of it.
When I click the action link on the view to generate the pdf, the file appears to be created, but when I try to open it, I get the ever so helpful message from Adobe Reader that "... the file is damaged and cannot be repaired".
Where have I gone wrong?
public FileStreamResult PDFGenerator()
{
Stream fileStream = GeneratePDF();
HttpContext.Response.AddHeader("content-disposition", "attachment; filename=form.pdf");
return new FileStreamResult(fileStream, "application/pdf");
}
private Stream GeneratePDF()
{
MemoryStream ms = new MemoryStream();
Document doc = new Document();
PdfWriter writer = PdfWriter.GetInstance(doc, ms);
d开发者_JAVA百科oc.Open();
doc.Add(new Paragraph("Hello"));
ms.Position = 0;
ms.Flush();
writer.Flush();
return ms;
}
You must close the document. Try like this:
public ActionResult PDFGenerator()
{
var doc = new Document();
using (var stream = new MemoryStream())
{
var writer = PdfWriter.GetInstance(doc, stream);
doc.Open();
doc.Add(new Paragraph("Hello"));
doc.Close();
return File(stream.ToArray(), "application/pdf", "test.pdf");
}
}
But that's ugly. I would recommend you a more MVCish approach which consists in writing a custom ActionResult. As an additional advantage of this is that your controller actions will be more easier to unit test in isolation:
public class PdfResult : FileResult
{
public PdfResult(): base("application/pdf")
{ }
public PdfResult(string contentType): base(contentType)
{ }
protected override void WriteFile(HttpResponseBase response)
{
var cd = new ContentDisposition
{
Inline = false,
FileName = "test.pdf"
};
response.AppendHeader("Content-Disposition", cd.ToString());
var doc = new Document();
var writer = PdfWriter.GetInstance(doc, response.OutputStream);
doc.Open();
doc.Add(new Paragraph("Hello"));
doc.Close();
}
}
and then in your controller action:
public ActionResult PDFGenerator()
{
return new PdfResult();
}
Of course this can be taken a step further and have this PdfResult
take a view model as constructor argument and generate the PDF based on some properties on this view model:
public ActionResult PDFGenerator()
{
MyViewModel model = ...
return new PdfResult(model);
}
Now things are beginning to look nice.
精彩评论