Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 673|回复: 0

在ASP.NET MVC 无需Web Form和Report Viewer 预览SSRS报表解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-4-21 17:35:07 | 显示全部楼层 |阅读模式

    环境

    ASP.NET MVC 4.0 + SQL Server Reporting Services

    需求

    在保存报表为文件(如PDF)之前,可以预览报表(支持图片)。

    分析

    网络上的解决方案,都是告诉你用最原始的办法:结合ASP.NET Web Form+Report Viewer控件。因为SQL Server Reporting Services (SSRS) 只有Web Form的Report Viewer控件,没对ASP.NET MVC进行特别支持。

    我们不能直接在ASP.NET MVC用Report Viewer是因为Report Viewer依赖View State,而View State正是MVC要解决的问题。。。

    因为不满意这种整合Web Form的解决方案,今晚思考了一下,既然SSRS支持渲染结果为MHTML(MIME HTML),那么,如果我们解决浏览器不显示MHTML内容(需要另存再本地打开),就可以实现预览的办法:先渲染成MHTML,再解释MIME,再把图片附件转成data嵌入。

    步骤

    1. 设计页面

    因为预览结果是完整的HTML,我在报表页面嵌入了一个iframe。。。。。。src指向一个Web API,该Web API会返回渲染后的html内容(包括图片)。

    2. 下载文件

    添加一个Web API 函数,用以渲染MHTML并返回text/html结果。为了简化操作,我把报表参数拼接起来,键值用“|”分隔,参数用“`”分隔。实际使用请根据自己的情况修改。。。

            public HttpResponseMessage DownloadReportContent(string ReportFileName, string Parameters)
            {
                var parameters = new Dictionary<string, string>();
                Parameters.Split('`').ForEach(p =>
                {
                    var parts = p.Split('|');
                    parameters.Add(parts[0], parts[1]);
                });
    
                byte[] reportContent;
                string fileExtension, mimeType;
                ReportGenerator.GenerateReport("ReportServer", "ReportServerExecutionURL", "ReportServerUserName", "ReportServerPassword", "ReportServerDomain", ReportFileName, ExportFormat.MHTML, parameters, string.Empty, out reportContent, out fileExtension, out mimeType);
                reportContent = ReportConvertor.Convert(reportContent);
    
                var resultStream = new System.IO.MemoryStream(reportContent);
                resultStream.Position = 0;
                var response = new HttpResponseMessage();
                response.StatusCode = HttpStatusCode.OK;
                response.Content = new StreamContent(resultStream);
                return response;
            }
    

      

    3. 渲染报表为MHTML

    下面的方法可以用作渲染其它格式,如最常见的PDF

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Principal;
    //using YOUR_IMPORTED_WEB_REFERENCE_FOR_SSRS_EXECUTION_SERVICE_HERE
    
    namespace Org.SSRSPreview
    {
        /// <summary>
        /// Export Formats
        /// </summary>
        public enum ExportFormat
        {
            /// <summary>XML</summary>
            XML,
            /// <summary>Comma Delimitted File
            CSV,
            /// <summary>TIFF image</summary>
            Image,
            /// <summary>PDF</summary>
            PDF,
            /// <summary>HTML (Web Archive)</summary>
            MHTML,
            /// <summary>HTML 4.0</summary>
            HTML4,
            /// <summary>HTML 3.2</summary>
            HTML32,
            /// <summary>Excel</summary>
            Excel,
            /// <summary>Word</summary>
            Word
        }
    
        public class ReportGenerator
        {
            /// <summary>
            /// Gets the string export format of the specified enum.
            /// </summary>
            /// <param name="Format">export format enum</param>
            /// <returns>enum equivalent string export format</returns>
            private string GetExportFormatString(ExportFormat Format)
            {
                switch (Format)
                {
                    case ExportFormat.XML: return "XML";
                    case ExportFormat.CSV: return "CSV";
                    case ExportFormat.Image: return "IMAGE";
                    case ExportFormat.PDF: return "PDF";
                    case ExportFormat.MHTML: return "MHTML";
                    case ExportFormat.HTML4: return "HTML4.0";
                    case ExportFormat.HTML32: return "HTML3.2";
                    case ExportFormat.Excel: return "EXCEL";
                    case ExportFormat.Word: return "WORD";
                    default:
                        return "PDF";
                }
            }
    
            /// <summary>
            /// generate a report
            /// </summary>
            /// <param name="ReportServer">report server</param>
            /// <param name="ReportServerExecutionURL">rendering execution url of report server</param>
            /// <param name="ReportServerUserName">user name to access report server</param>
            /// <param name="ReportServerPassword">password of the user name</param>
            /// <param name="ReportServerDomain">domain of the report server (for active directory)</param>
            /// <param name="ReportServerSubDir">folder of the report in the report server</param>
            /// <param name="FileFormat">output of the report</param>
            /// <param name="Parameters">parameters for the report</param>
            /// <param name="ReportContent">rendered report content</param>
            /// <param name="FileExtension">file extension of the report</param>
            /// <param name="MimeType">mime type of the generated file</param>
            public void GenerateReport(string ReportServer,
                string ReportServerExecutionURL,
                string ReportServerUserName,
                string ReportServerPassword,
                string ReportServerDomain,
                string ReportServerSubDir,
                string ReportFileName,
                ExportFormat FileFormat,
                Dictionary<string, string> Parameters,
                string DeviceInfo,
                out byte[] ReportContent,
                out string FileExtension,
                out string MimeType)
            {
    
                using (var reportExecutionService = new ReportExecutionService.ReportExecutionServiceSoapClient("ReportExecutionServiceSoap", ReportServerExecutionURL))
                {
                    reportExecutionService.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
                    reportExecutionService.ClientCredentials.UserName.UserName = ReportServerUserName;
                    reportExecutionService.ClientCredentials.UserName.Password = ReportServerPassword;
                    reportExecutionService.ClientCredentials.Windows.ClientCredential = new System.Net.NetworkCredential(ReportServerUserName, ReportServerPassword, ReportServerDomain);
    
                    var parameters = Parameters.Select(p => new ParameterValue { Name = p.Key, Value = p.Value }).ToList();
                    // Init Report to execute
                    ServerInfoHeader serverInfoHeader;
                    ExecutionInfo executionInfo;
                    ExecutionHeader executionHeader = reportExecutionService.LoadReport(null, ReportFileName, null, out serverInfoHeader, out executionInfo);
    
                    // Attach Report Parameters
                    reportExecutionService.SetExecutionParameters(executionHeader, null, parameters.ToArray(), null, out executionInfo);
    
                    // Render
                    string encoding;
                    Warning[] warnings;
                    string[] streamIds;
                    reportExecutionService.Render(executionHeader, null, GetExportFormatString(FileFormat), DeviceInfo, out ReportContent, out FileExtension, out MimeType, out encoding, out warnings, out streamIds);
    
                }
            }
        }
    }
    

     

    4. 解释MIME,转换图片附件为data嵌入式

    这是整个解决方案的核心思想。SSRS会把修改图片的标识,譬如<img src="cid:SOME_ID_HERE">,我们要做的就是取得图片附件的原始base64内容,构造成如下的格式:

    data:image/png;base64,[ENCODED_DATA_HERE]

    MIME解释用到了OpenPop.NET (通过Pop3协议收取邮件),这是我10年前参与开发的第一个开源项目,不过几年前把项目移交给别的开发人员,我当年写的代码部分都荡然无存了。。。在这里吐槽一下接手的开发人员,你太不给偶面子了。。。 :-)

    为了优化性能,我改动了一下MessagePart.cs文件。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using OpenPop.Mime;
    
    namespace Org.SSRSPreview
    {
        public class ReportConvertor
        {
            public static byte[] Convert(byte[] Content)
            {
                var message = new Message(Content);
                var body = message.FindFirstHtmlVersion();
                var bodyText = body.BodyEncoding.GetString(body.Body, 0, body.Body.Length);
                message.FindAllAttachments().ForEach(a =>
                    {
                        if (!a.IsText)
                        {
                            var key = "Content-Location";
                            var url = a.Headers.UnknownHeaders[key];
                            if (string.IsNullOrEmpty(url) && a.ContentDisposition != null)
                                url = a.ContentDisposition.Inline ? "cid:" + a.FileName : a.FileName;
                            var attachment = a.Body;
    
                            var embedImage = new StringBuilder("data:");
                            embedImage.Append(a.ContentType.MediaType + ";");
                            embedImage.Append(a.ContentTransferEncoding.ToString().ToLowerInvariant() + ",");
                            embedImage.Append(a.BodyEncoding.GetString(a.RawBody));
                            bodyText = bodyText.Replace(url, embedImage.ToString());
                        }
                    });
                return body.BodyEncoding.GetBytes(bodyText);
            }
        }
    }
    

      

    限制

    没有Report Viewer那些控制,譬如缩放,分页等。。。。我不需要啊。。。

    代码

    点击这里下载。代码不是完整的解决方案,只包括关键的代码,如果你打开运行,只会解释一个例子MHTML,因为相关的函数和类都在这里贴了。

    总结

    至此,大功告成。SQL Server团队对ASP.NET MVC不重视啊,这么多年还不考虑一下支持ASP.NET MVC。

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-22 17:01 , Processed in 0.057028 second(s), 28 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表