在Web开发中,经常需要将数据报告或打印友好的文档(如发票、收据等)转换成PDF格式。过去,习惯于设计Crystal Report文档,然后评估并将其转换为PDF格式。设计部分还算顺利,但部署过程中遇到的问题常常让头疼不已,版本不匹配尤其让人头疼。
最近,开始使用一个优秀的工具wkhtmltopdf,它能够将HTML内容转换为PDF。这个工具使用WebKit引擎(Chrome和Safari浏览器也使用这个引擎)来渲染HTML。它的一个优点是,可以利用对HTML和CSS的知识来获得一个好看的PDF,而且速度相当快。
wkhtmltopdf是一个可执行文件(EXE),而不是一个动态链接库(DLL)。虽然DLL确实存在,但它不是托管代码,而且在多线程应用程序中使用时会遇到一些问题。它需要从ASP.NET应用程序中执行,因此需要一些不寻常的编码方式,从Web开发的角度来看。另一个缺点是,它需要一些设置工作:复制EXE和DLL文件到Web应用程序解决方案中,确保在构建和发布时它们被复制过去,以及一些配置工作,以便它可以访问经过身份验证的操作。
在看来,它非常适合成为一个Nuget包。构建它相当容易,只是在尝试修改包属性时遇到了一些奇怪的问题。给它命名为Rotativa,这是意大利语中的旋转印刷机。有了Rotativa,打印PDF只需要:
Install-Package Rotativa
在C#中,可以这样编写一个动作:
public ActionResult Invoice(int invoiceId)
{
var invoiceViewModel;
// 从数据库检索数据的代码
return View(invoiceViewModel);
}
这里没有什么特别的,只是一个动作。也许使用的视图会有与其他Web应用程序视图不同的主页面(或布局页面),或者会为打印媒体定义一个单独的CSS(参见)。可以使用浏览器测试和“预览”结果,因为正在处理一个常规动作,返回HTML结果。
在C#中,可以这样编写一个动作:
public ActionResult PrintInvoice(int invoiceId)
{
return new ActionAsPdf("Invoice", new { invoiceId = invoiceId }) { FileName = "Invoice.pdf" };
}
使用Nuget包管理器安装(搜索Rotativa),或者更方便地,使用包管理器控制台,输入:
Install-Package Rotativa
编写一个控制器动作来返回表示所需PDF输出的视图。这意味着像往常一样编码,以提供数据作为常规MVC动作。例如:
当HTML准备好后,只需要设置一个特殊的动作返回自定义的ActionResult:
ActionAsPdf
代码看起来像这样:
ActionAsPdf 需要一个string参数,表示要转换为PDF的动作名称。它可以接收一个包含其他路由数据的参数,在这种情况下,定义了invoiceId参数。可以使用FileName属性指定返回的文件名。
要在其他视图中链接到PDF文件,只需要插入一个常规链接到PrintInvoice动作。如果使用的是razor视图,可以这样:
@Html.ActionLink("PrintInvoice")