[MVC]PdfResult custom ActionResult in ASP.NET MVC

转载:http://www.jimzimmerman.com/blog/CommentView,guid,0649294f-cece-4fca-8d29-080435bd10bb.aspx

I have been very bad about not blogging and not posting code from my recent talks.  For that I apologize.  Let me say just one thing on that.  4 kids, ADD, and shiny new toys. 🙂

Ok, so several people have asked about generating pdf’s from html and css.  At work, we needed this for receipts for registration among other things.  We found a great tool from Winnovative Software that works great with css and html and spitting out an almost perfect pdf. 

We are using mvc in our solution, so we decided to come up with a custom ActionResult so that it would make it very easy to return a pdf from an action call.

Here is what the action looks like:

public PdfResult PdfForm()
{
string html = this.CaptureActionHtml(this, c => (ViewResult)c.PrintForm());
return new PdfResult(html, "PdfForm", true);
}
public ActionResult PrintForm()
{
var db = new NorthwindDataContext();
List<Customer> customers = db.Customers.ToList<Customer>();
ViewData["customers"] = customers;
return View("PrintForm");
}

 

Notice the CaptureActionHtml.  I found this code on this blog post as I was trying to figure out a way to use ASP.NET mvc as the template engine to save time for generating the html which the html to pdf tool needed.

Here is the CaptureActionHtml class:

using System;
using System.IO;
using System.Web;
using System.Web.Mvc;
namespace HtmlHelperExamples
{
public static class ControllerExtensions
{
/// <summary>
/// Captures the HTML output by a controller action that returns a ViewResult
/// </summary>
/// <typeparam name="TController">The type of controller to execute the action on</typeparam>
/// <param name="controller">The controller</param>
/// <param name="action">The action to execute</param>
/// <returns>The HTML output from the view</returns>
public static string CaptureActionHtml<TController>(
this TController controller,
Func<TController, ViewResult> action)
where TController : Controller
{
return controller.CaptureActionHtml(controller, null, action);
}
/// <summary>
/// Captures the HTML output by a controller action that returns a ViewResult
/// </summary>
/// <typeparam name="TController">The type of controller to execute the action on</typeparam>
/// <param name="controller">The controller</param>
/// <param name="masterPageName">The master page to use for the view</param>
/// <param name="action">The action to execute</param>
/// <returns>The HTML output from the view</returns>
public static string CaptureActionHtml<TController>(
this TController controller,
string masterPageName,
Func<TController, ViewResult> action)
where TController : Controller
{
return controller.CaptureActionHtml(controller, masterPageName, action);
}
/// <summary>
/// Captures the HTML output by a controller action that returns a ViewResult
/// </summary>
/// <typeparam name="TController">The type of controller to execute the action on</typeparam>
/// <param name="controller">The current controller</param>
/// <param name="targetController">The controller which has the action to execute</param>
/// <param name="action">The action to execute</param>
/// <returns>The HTML output from the view</returns>
public static string CaptureActionHtml<TController>(
this Controller controller,
TController targetController,
Func<TController, ViewResult> action)
where TController : Controller
{
return controller.CaptureActionHtml(targetController, null, action);
}
/// <summary>
/// Captures the HTML output by a controller action that returns a ViewResult
/// </summary>
/// <typeparam name="TController">The type of controller to execute the action on</typeparam>
/// <param name="controller">The current controller</param>
/// <param name="targetController">The controller which has the action to execute</param>
/// <param name="masterPageName">The name of the master page for the view</param>
/// <param name="action">The action to execute</param>
/// <returns>The HTML output from the view</returns>
public static string CaptureActionHtml<TController>(
this Controller controller,
TController targetController,
string masterPageName,
Func<TController, ViewResult> action)
where TController : Controller
{
if (controller == null)
{
throw new ArgumentNullException("controller");
}
if (targetController == null)
{
throw new ArgumentNullException("targetController");
}
if (action == null)
{
throw new ArgumentNullException("action");
}
// pass the current controller context to orderController
var controllerContext = controller.ControllerContext;
targetController.ControllerContext = controllerContext;
// replace the current context with a new context that writes to a string writer
var existingContext = System.Web.HttpContext.Current;
var writer = new StringWriter();
var response = new HttpResponse(writer);
var context = new HttpContext(existingContext.Request, response) {User = existingContext.User};
System.Web.HttpContext.Current = context;
// execute the action
var viewResult = action(targetController);
// change the master page name
if (masterPageName != null)
{
viewResult.MasterName = masterPageName;
}
// we have to set the controller route value to the name of the controller we want to execute
// because the ViewLocator class uses this to find the correct view
var oldController = controllerContext.RouteData.Values["controller"];
controllerContext.RouteData.Values["controller"] = typeof(TController).Name.Replace("Controller", "");
// execute the result
viewResult.ExecuteResult(controllerContext);
// restore the old route data
controllerContext.RouteData.Values["controller"] = oldController;
// restore the old context
System.Web.HttpContext.Current = existingContext;
return writer.ToString();
}
}
}

Here is the PdfResult class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Winnovative.WnvHtmlConvert;
using System.Text.RegularExpressions;
namespace System.Web.Mvc
{
public class PdfResult : ViewResult
{
public string ContentType { get; set; }
public string Content { get; set; }
public string OutputFileName { get; set; }
public bool ReturnAsAttachment { get; set; }
public PdfResult(string html, string outputFileName, bool returnAsAttachment)
{
// ViewResult vr = ar as ViewResult;
this.ContentType = "application/pdf";
this.Content = html;
this.OutputFileName = outputFileName;
this.ReturnAsAttachment = returnAsAttachment;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.ContentType = ContentType;
string baseURL = "";
string htmlString = this.Content;
bool selectablePDF = true;
// Create the PDF converter. Optionally you can specify the virtual browser width as parameter.
//1024 pixels is default, 0 means autodetect
PdfConverter pdfConverter = new PdfConverter();
// set the license key
pdfConverter.LicenseKey = "yourkeyhere";
// set the converter options
pdfConverter.PdfDocumentOptions.PdfPageSize = PdfPageSize.A4;
pdfConverter.PdfDocumentOptions.PdfCompressionLevel = PdfCompressionLevel.Normal;
pdfConverter.PdfDocumentOptions.PdfPageOrientation = PDFPageOrientation.Portrait;
pdfConverter.PdfDocumentOptions.ShowHeader = false;
pdfConverter.PdfDocumentOptions.ShowFooter = false;
// set to generate selectable pdf or a pdf with embedded image
pdfConverter.PdfDocumentOptions.GenerateSelectablePdf = selectablePDF;
// Performs the conversion and get the pdf document bytes that you can further
// save to a file or send as a browser response
// The baseURL parameterhelps the converter to get the CSS files and images
// referenced by a relative URL in the HTML string. This option has efect only
// if the HTML string contains a valid HEAD tag.
// The converter will automatically inserts a <BASE HREF="baseURL"> tag.
byte[] pdfBytes = null;
if (baseURL.Length > 0)
{
pdfBytes = pdfConverter.GetPdfBytesFromHtmlString(htmlString, baseURL);
}
else
{
pdfBytes = pdfConverter.GetPdfBytesFromHtmlString(htmlString);
}
// send the PDF document as a response to the browser for download
// System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
context.HttpContext.Response.Clear();
// this.OutputFileName = Regex.Replace(this.OutputFileName, " ", "_", RegexOptions.IgnoreCase);
// this.OutputFileName = StringHelper.StripNonAlphaNumeric(this.OutputFileName);
context.HttpContext.Response.AddHeader("Content-Type", "application/pdf");
if (this.ReturnAsAttachment)
{
context.HttpContext.Response.AddHeader("Content-Disposition", "attachment; filename=" + this.OutputFileName + ".pdf; size=" + pdfBytes.Length.ToString());
}
context.HttpContext.Response.Flush();
context.HttpContext.Response.BinaryWrite(pdfBytes);
context.HttpContext.Response.Flush();
context.HttpContext.Response.End();
}
}
}

 

Hopefully this will help those of you who are wanting to generate the pdf’s using html and css along with using the default mvc view engine as your template engine. Enjoy!

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏