Skip to content

Instantly share code, notes, and snippets.

@kmpm
Created January 10, 2014 12:17
Show Gist options
  • Save kmpm/8350981 to your computer and use it in GitHub Desktop.
Save kmpm/8350981 to your computer and use it in GitHub Desktop.
Filter for an MVC4 application to render all views as PDF if AcceptTypes contains "application/pdf" or querystring contains asPDF=1. Uses wkthml2pdf via Pechkin. Currently requires https://github.com/gmanny/Pechkin/pull/42
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Text;
using System.IO;
using System.Web.UI;
using Pechkin;
using System.Text.RegularExpressions;
namespace Utils.PDF
{
/*
protected void Application_Start()
{
...
GlobalFilters.Filters.Add(new PdfFilterAttribute());
RegisterGlobalFilters(GlobalFilters.Filters);
...
}
*/
public class PdfFilterAttribute:ActionFilterAttribute
{
// Regular expression for an HTML title
static string regex = @"(?<=<title.*>)([\s\S]*)(?=</title>)";
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
bool acceptPdf = (filterContext.RequestContext.HttpContext.Request.AcceptTypes != null &&
filterContext.RequestContext.HttpContext.Request.AcceptTypes.Contains("application/pdf"));
bool requestPdf = (filterContext.RequestContext.HttpContext.Request.QueryString.AllKeys.Contains("asPDF"));
if(acceptPdf || requestPdf)
{
var sb = new StringBuilder();
var sw = new StringWriter(sb);
var tw = new HtmlTextWriter(sw);
var output = (HttpWriter)filterContext.RequestContext.HttpContext.Response.Output;
filterContext.RequestContext.HttpContext.Response.Output = tw;
filterContext.HttpContext.Items["__private_value__sb"] = sb;
filterContext.HttpContext.Items["__private_value__output"] = output;
}
else
{
base.OnActionExecuting(filterContext);
}
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.HttpContext.Items.Contains("__private_value__sb"))
{
var sb = (StringBuilder)filterContext.HttpContext.Items["__private_value__sb"];
var output = (HttpWriter)filterContext.HttpContext.Items["__private_value__output"];
string html = sb.ToString();
//response processing
//get the document path
var Request = filterContext.RequestContext.HttpContext.Request;
var uri = Request.Url.AbsoluteUri;
//get the title
Regex ex = new Regex(regex, RegexOptions.IgnoreCase);
string title = ex.Match(html).Value.Trim();
//make sure we have absolute paths to css
var urlHelper = new UrlHelper(filterContext.RequestContext);
var baseUri = string.Format("{0}://{1}", Request.Url.Scheme, Request.Url.Authority);
html = html.Replace("link href=\"/", "link href=\"" + baseUri + "/");
//configure pechkin
var pechkin = Factory.Create(new GlobalConfig()
.SetPaperSize(System.Drawing.Printing.PaperKind.A4)
.SetCopyCount(1)
.SetOutlineGeneration(true)
);
//generate pdf
var pdf = pechkin.Convert(new ObjectConfig()
.SetAllowLocalContent(true)
.SetRenderDelay(1000)
.SetIntelligentShrinking(false)
.SetRunJavascript(true)
.SetLoadImages(true) //.SetZoomFactor(1.5)
.SetPrintBackground(true)
.SetScreenMediaType(false) //use print instead
.SetCreateExternalLinks(false)
.SetPageUri(uri), html);
//prepare the response
var Response = filterContext.HttpContext.Response;
Response.Clear();
Response.ClearContent();
Response.ClearHeaders();
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", string.Format("attachment;filename={1}.pdf; size={0}", pdf.Length, title));
output.WriteBytes(pdf, 0, pdf.Length);
}
else
{
base.OnResultExecuted(filterContext);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment