最近做过一个将页面表格导出至PDF的功能,现在将它整理出来,以备不时之需。
PDF模板是用的是.net报表文件(.rdlc),原理就是将数据填充到报表文件中,利用Microsoft.Reporting.WebForms.LocalReport类的方法,输出PDF字节流,然后,通过定义Response的HTTP标头定义,在浏览器输出PDF文件。
以下是关键部分的代码:
1. 首先,准备一个输出PDF字节流的方法:
using System; using System.Collections.Generic; using ATA.Toeic.Models; using ATA.Toeic.DAL; using System.IO; using Microsoft.Reporting.WebForms; namespace ATA.Toeic.BLL { public class AdmissionTicketBLL { private RegistrationDAL dal = new RegistrationDAL(); /// <summary> /// 『单个导出』 /// 导出包含一张准考证的pdf文件 /// </summary> /// <param name="addmissionFormId">准考证号</param> /// <param name="reportPath">报表模板路径</param> /// <returns>pdf文件字节流</returns> public byte[] ExportTicket(string addmissionFormId, string reportPath, out string mimeType) { List<string> arrId = new List<string>(); arrId.Add(addmissionFormId); return ExportTicket(arrId, reportPath, out mimeType); } /// <summary> /// 『批量导出』 /// 导出多张准考证的pdf文件 /// </summary> /// <param name="arrAddmissionFormId">需要导出的准考证号</param> /// <returns>pdf文件字节流</returns> public byte[] ExportTicket(List<string> arrAddmissionFormId, string reportPath, out string mimeType) { LocalReport localReport = new LocalReport(); localReport.ReportPath = reportPath; // 报表对象的模板文件的路径 // 报表对象的数据源 ReportDataSource reportDataSource = new ReportDataSource("dsList", GetAdmissionTicketList(arrAddmissionFormId.ToArray()) // 这个方法返回一个IList<Model>对象 ); localReport.DataSources.Add(reportDataSource); string reportType = "PDF"; string encoding; string fileNameExtension; //The DeviceInfo settings should be changed based on the reportType //http://msdn2.microsoft.com/en-us/library/ms155397.aspx string deviceInfo = "<DeviceInfo><OutputFormat>PDF</OutputFormat></DeviceInfo>"; Warning[] warnings; string[] streams; byte[] renderedBytes; //Render the report renderedBytes = localReport.Render( reportType, deviceInfo, out mimeType, out encoding, out fileNameExtension, out streams, out warnings); return renderedBytes; } } }
2. 在action中定义HTTP标头,输出PDF文件,在这里批量和单个已经没有区别了,区别包含在byte[]的字节流中。
[CheckServiceExpire] public ActionResult GetAdmissionForms(int serviceid, string Condition) { List<RegistrationEn> list = new RegistrationBLL().GetExamineeByCondi(serviceid, Condition); if (list == null || list.Count == 0) return Alert("目前没有准考证信息!", "~/Views/ExamService/SaveSuccess.aspx", new { action = "GetExamineeByPage", controller = "Registration", serviceid = serviceid }); List<string> sl = new List<string>(); foreach (RegistrationEn ren in list) sl.Add(ren.fAdmissionFormId); try { AdmissionTicketBLL bll = new AdmissionTicketBLL(); string rdlcPath = Server.MapPath("~/Resources/AdmissionTicket.rdlc"); string mimeType; byte[] renderedBytes = bll.ExportTicket(sl, rdlcPath, out mimeType); Response.AddHeader("content-disposition", "attachment; filename=AdmissionTicket.pdf"); return File(renderedBytes, mimeType); } catch { return Alert("获取准考证信息出错!", "~/Views/ExamService/SaveSuccess.aspx", new { action = "GetExamineeByPage", controller = "Registration", serviceid = serviceid }); } }
这样就可以正常导出PDF文件了。
总结:
微软推出的报表语言Report Definition Language, RDL语言,确实比较实用,而且微软为此开发出一套图形化设计界面,比较好用,也值得去学习,以前没有接触过,等真正项目中要用到了,再去研究,时间就等不及了,上周还在CSDN上发帖,为调整布局而苦恼。
总之,如果有空,不妨研究下。
补充:
如果想在页面中直接打开PDF(要求机器已安装adobe reader),则只需要修改HTTP标头的参数:
将“Response.AddHeader("content-disposition", "attachment; filename=AdmissionTicket.pdf");”替换成“Response.AddHeader("content-disposition", string.Format("inline;filename={0}.pdf", admissionFormId));”