Asp.net MVC3使用Reporting Services生成PDF解决Web在线打印

目前产品上一直使用的是微软的SQL Server Reporting Services给用户输出报表。可是在WEB打印上一直是一个心病,因为要调用微软的RSClient控件,可是这个控件在浏览器上存在兼容性问题,在谷歌或者火狐浏览器就肯定不能调出客户端打印界面。咨询过微软,好像又说RSClient控件最新版本能支持谷歌或者火狐浏览器,不过目前SQL Server2012是未能支持。

于是最近看到FineReport,看到FineReport最推荐的是PDF打印,于是产生新的想法,微软的Reporting Services是能够导出PDF功能,利用现有Report viewer控件,增加PDF在线打印功能,然后将报表导出PDF在服务器上临时目录,将浏览器指向临时生成PDF文件,由浏览器在线打开PDF文件。从目前测试效果看,由于目前客户端都支持打开PDF控件,效果非常好不错。

从实现角度来看,主要解决两个关键问题:
1、Report viewer生成PDF文件。
2、定期将临时目录PDF文件删除。

这个都比较简单,下面是服务器代码:


        /// <summary>
        /// PDF在线打印(理论上支持IE浏览器和谷歌浏览器)
        /// </summary>
        /// <returns></returns>
        public ActionResult PrintPdf()
        {
            var serverReport = new ServerReport();
            serverReport.ReportServerUrl = Engine.ReportServer;
            serverReport.ReportPath = Engine.ReportPath;
            serverReport.ReportServerCredentials = Engine.Credentials;

            if (Engine.Parames != null)
            {
                foreach (var item in Engine.Parames)
                {
                    item.Visible = false;
                    serverReport.SetParameters(item);
                }

            }

            //导出打印PDF

            string mimeType;
            string encoding;
            string fileNameExtension;
             Warning[] warnings;
            string[] streams;

            var rptBytes = serverReport.Render("PDF",
                                deviceInfo,
                                out mimeType,
                                out encoding,
                                out fileNameExtension,
                                out streams,
                                out warnings);

            //将1天以前的临时文件全部删除
            DeleteTempPdfFile();

            //将PDF文件保存到磁盘
            var fileName = SavePdf2Disk(rptBytes);

            //在浏览器上输出直接打开
            return Content(fileName);
         }

        /// <summary>
        /// 将PDF文件保存到磁盘
        /// </summary>
        /// <param name="pdfContent">pdf内容</param>
        /// <returns></returns>
        public string SavePdf2Disk(byte[] pdfContent)
        {
            Random random = new Random();

            //保存到磁盘的临时文件,按日期加随机数,可以每次调用的时候,删除临时文件。
            //文件名为:6位日期+5位随机数.pdf

            var dateString = DateTime.Now.ToString("yyyyMMdd");
            var fileName = dateString + random.Next(99999, 1000000).ToStr() + ".pdf";

            var fileTempPath = Server.MapPath("~/") + "//FileTemp//" + fileName;
            FileStream writeStream = new FileStream(fileTempPath, FileMode.Create, FileAccess.Write);

            MemoryStream readStream = new MemoryStream(pdfContent);
            int Length = 256;
            Byte[] buffer = new Byte[Length];
            int bytesRead = readStream.Read(buffer, 0, Length);
            // write the required bytes
            while (bytesRead > 0)
            {
                writeStream.Write(buffer, 0, bytesRead);
                bytesRead = readStream.Read(buffer, 0, Length);
            }
            readStream.Close();
            writeStream.Close();
            return fileName;
        }

        /// <summary>
        /// 删除临时PDF文件
        /// </summary>
        /// <returns></returns>
        public void DeleteTempPdfFile()
        {
            var fileTempPath = Server.MapPath("~/") + "//FileTemp//";
            string[] files = Directory.GetFiles(fileTempPath, "*.pdf");

            int dateString = int.Parse(DateTime.Now.ToString("yyyyMMdd"));

            FileInfo fi;

            //文件名为:6位日期,如果现在日期大于临时文件日期,则删除
            //将1天以前的临时文件全部删除。

            foreach (var file in files)
            {
                fi = new FileInfo(file);
                if(fi.Name.Length>8)
                {
                    var fileDateName = fi.Name.Substring(0, 8);
                    try
                    {
                        if (dateString > int.Parse(fileDateName))
                        {
                            fi.Delete();
                        }
                    }
                    catch
                    {

                    }

                }

            }
        }

接下来是客户端代码,就几句js脚本。

“`

$(document).ready(function () {
    printPdf();
});

 function printPdf() {
     var aj = $.ajax({
         url: "/Common/Report/PrintPdf", // 跳转到 action 
            data: { code: reportCode },
            type: 'post',
            cache: false,
            dataType: 'text',
            success: function(data) {
                var pdfUrl = "/FileTemp/" + data;
                ShowReport(pdfUrl);
            },
            error: function() {
                alert("异常!");
            }
        });

  }

  function ShowReport(url) {
      window.location.href = url;
      //$("#ReportFrame").attr("src", url);

  }



<div id="dvmask" style="position: absolute; z-index: 999999; top: 0px; left: 0px;
    width: 100%; height: expression(document.body.clientHeight); min-height: 100%;
    background-color: #ddd; text-align: center; opacity: 0.8; filter: alpha(opacity=80);">
    <div style="position: relative; top: 50px; filter: alpha(opacity=100); opacity: 1;
        color: Red; text-align: center;">
        <img src='@Url.Content("~/Images/wait1.gif")' alt="请稍候" style="margin: auto auto 10px auto;" />
        <br />
        正在加载PDF数据,请稍候... 如果没有安装PDF阅读器,请安装<a href="https://acrobat.adobe.com/us/en/products/pdf-reader.html">PDF阅读器</a>
    </div>
</div>

下面是FineReport的效果,查看截图。
这里写图片描述
这里写图片描述

本地效果差不多见下图:
这里写图片描述
这里写图片描述