4

I've got a partial view, i'm trying to use ITextSharp to convert the html to pdf. How can I convert the html to string so I can use ItextSharps HtmlParser?

I've tried something like this with no luck...any ideas?:

 var contents = System.IO.File.ReadAllText(Url.Action("myPartial", "myController", new { id = 1 }, "http"));
newbie_86
  • 4,520
  • 17
  • 58
  • 89

1 Answers1

8

I have created a special ViewResult class that you can return as the result of an Action.

You can see the code on bitbucket (look at the PdfFromHtmlResult class).

So what it basically does is:

  • Render the view through the Razor engine (or any other registered engine) to Html
  • Give the html to iTextSharp
  • return the pdf as the ViewResult (with correct mimetype, etc).

My ViewResult class looks like:

 public class PdfFromHtmlResult : ViewResult {

    public override void ExecuteResult(ControllerContext context) {
        if (context == null) {
            throw new ArgumentNullException("context");
        }
        if (string.IsNullOrEmpty(this.ViewName)) {
            this.ViewName = context.RouteData.GetRequiredString("action");
        }

        if (this.View == null) {
            this.View = this.FindView(context).View;
        }

        // First get the html from the Html view
        using (var writer = new StringWriter()) {
            var vwContext = new ViewContext(context, this.View, this.ViewData, this.TempData, writer);
            this.View.Render(vwContext, writer);

            // Convert to pdf

            var response = context.HttpContext.Response;

            using (var pdfStream = new MemoryStream()) {
                var pdfDoc = new Document(); 
                var pdfWriter = PdfWriter.GetInstance(pdfDoc, pdfStream);

                pdfDoc.Open();

                using (var htmlRdr = new StringReader(writer.ToString())) {

                    var parsed = iTextSharp.text.html.simpleparser.HTMLWorker.ParseToList(htmlRdr, null);

                    foreach (var parsedElement in parsed) {
                        pdfDoc.Add(parsedElement);
                    }
                }

                pdfDoc.Close();

                response.ContentType = "application/pdf";
                response.AddHeader("Content-Disposition", this.ViewName + ".pdf");
                byte[] pdfBytes = pdfStream.ToArray();
                response.OutputStream.Write(pdfBytes, 0, pdfBytes.Length);
            }
        }
     }
 }

With the correct extension methods (see BitBucket), etc, the code in my controller is something like:

 public ActionResult MyPdf(int id) {
       var myModel = findDataWithID(id);

       // this assumes there is a MyPdf.cshtml/MyPdf.aspx as the view
       return this.PdfFromHtml(myModel);
 }

Note: Your method does not work, because you will retrieve the Html on the server, thereby you loose all cookies (=session information) that are stored on the client.

GvS
  • 52,015
  • 16
  • 101
  • 139
  • would this work with a view not created using the Razor engine? – newbie_86 Aug 05 '11 at 09:08
  • I didn't test without razor, but I also don't reference Razor. I expect that the ViewContext is intelligent enough to use another renderer when needed. – GvS Aug 05 '11 at 09:10
  • Ok, i'll give it a shot...I'm getting a compile error "Cannot implicitly convert iTextSharp.text.pdf.PdfWriter to System.IDisposable" on these 2 lines: using (var pdfDoc = new Document()) using (var pdfWriter = PdfWriter.GetInstance(pdfDoc, pdfStream)) – newbie_86 Aug 05 '11 at 09:19
  • Strange, maybe, you have another iTextSharp version? I'll change the code example to not use the `using`, since `pdfDoc.Close` is explicitly called, they are not 100% needed, just nicer. – GvS Aug 05 '11 at 09:25
  • Ok, great! One last issue: return this.PdfFromHtml(myModel); doesn't seem to work for some reason :( It doesn't resolve PdfFromHtml, i've got all references, using itextxharp 4.1.6, MyPdf in my case is an ascx or partial view...any ideas? – newbie_86 Aug 05 '11 at 09:32
  • Also add the ControllerExtension class from the BitBucket site (https://bitbucket.org/gvs/imvcpdf/src/d4131aa15b45/iMvcPdf/ControllerExtensions.cs). I'm using the bitbucket code myself, so bitbucket is also where updates will appear. – GvS Aug 05 '11 at 09:41
  • Excellent solution!. Any possibility this can be converted to use partial views? – Rossco Apr 25 '16 at 13:37