Asp.Net MVC Action Result Converting Html To Pdf
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:
- Download iTextSharp
- Download this html helper class by Hugoware
- Add iTextSharp reference
- Add the helper class to your project
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