Software    csharp

Every time I go to solve the problem of converting html to pdf I am overwhelmed with the number of paid vs open source vs not-working vs 404 results I get on the topic. After my digging I decided to write an action result for asp.net mvc 3 allowing users to pass in html and css; getting a sweet pdf download.

Lets start with the libraries:

Now that we have the dependencies out of the way throw this class in your application:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using PDFBuilder;
using iTextSharp.text;

namespace SweetApp.Web
{
    /// <summary>
    /// Custom ActionResult for rendering a pdf.
    /// </summary>
    public class PdfResult : ActionResult
    {

        /// <summary>
        /// Initializes a new instance of the <see cref="PdfResult"/> class.
        /// </summary>
        /// <param name="name">The file name the user
        /// will download.</param>
        /// <param name="html">The inner HTML to render.</param>
        /// <param name="cssFiles">The list of absolute CSS file
        /// paths.</param>
        public PdfResult(string name, string html, string[] cssFiles)
        {
            this.Name = name;
            this.Html = html;
            this.CssFiles = cssFiles;
        }

        /// <summary>
        /// Enables processing of the result of an action method by a
        /// custom type that inherits from the
        /// <see cref="T:System.Web.Mvc.ActionResult"/> class.
        /// Creates a PDF file and passes it out of the response object.
        /// </summary>
        /// <param name="context">The context in which the result is executed.
        /// The context information includes the controller,
        /// HTTP content, request context, and route data.</param>
        public override void ExecuteResult(ControllerContext context)
        {
            HtmlToPdfBuilder builder = new HtmlToPdfBuilder(PageSize.LETTER);
            HtmlPdfPage page = builder.AddPage();

            foreach (var item in CssFiles)
                builder.ImportStylesheet(item);

            page.AppendHtml(this.Html);

            byte[] file = builder.RenderPdf();

            // send out the pdf file
            var response = context.HttpContext.Response;
            response.Clear();
            response.ContentType = "application/pdf";
            response.AddHeader("content-length", file.Length.ToString());
            response.AddHeader("content-disposition", "attachment; filename=" + this.Name);
            response.BinaryWrite(file);
            response.Flush();
            response.End();
        }

        /// <summary>
        /// Gets or sets the file name the user
        /// will download.
        /// </summary>
        /// <value>The file name.</value>
        public string Name { get; set; }

        /// <summary>
        /// Gets or sets the inner HTML of the pdf
        /// file.
        /// </summary>
        /// <value>The HTML.</value>
        public string Html { get; set; }

        /// <summary>
        /// Gets or sets a list of absolute CSS file paths
        /// to use to transform the file.
        /// </summary>
        /// <value>The CSS files.</value>
        public string[] CssFiles { get; set; }
    }
}

And for the implementation:

string cssUrl = Server.MapPath("~/css/contract.css");

return new PdfResult("Contract.pdf",
    myContractText,
    new string[] { cssUrl });

Note: If you get build issues with the HtmlToPdfBuilder on line 207 just comment the line out. That is what I did and it seemed to work fine.

Thanks, Hugoware for the cool pdf wrapper.

There are a ton of things that could be made better of course, but this should get someone started for sure.

Happy Coding

comments powered by Disqus