RDLC LocalReport 导出到 Excel 真的很慢

问题描述 投票:0回答:4

我们有一个 Asp.Net 页面针对后端的 Oracle 数据库运行 RDLC 本地报告,导出到 Excel 电子表格时速度慢得离谱。我做了一些调查,并确定查询本身不应该受到指责 - 我可以使用 SQL Developer 直接针对 Oracle 运行查询,并在大约 5 秒内将结果导出到 Excel,但当我通过 asp.网页和ReportViewer控件大约需要3分钟才能返回。

有人对为什么这么慢有任何建议吗?该查询返回大约 8000 行,每行大约 30 列,因此它不是一个很小的结果集,但也不是很大。任何有关我们如何优化报告的建议将不胜感激。

我正在使用 Microsoft.ReportViewer.WebForms 版本 10.0.0.0,有谁知道 v11 是否有性能改进?

编辑:尝试了ReportViewer v11,速度没有提高。

c# asp.net oracle rdlc
4个回答
3
投票

如果您的报告中有分组。从 .NET 4 开始,当旧版 CAS 被删除时,本地处理的 RDLC 报告需要花费大量时间来执行动态分组或动态过滤器。有一个与此相关的现有讨论https://social.msdn.microsoft.com/Forums/sqlserver/en-US/6d89e2ce-3528-465f-9740-7e22aa7b7aae/slow-performance-with-dynamic-grouping-and -reportviewer-in-local-mode?forum=sqlreportingservices
我在其中找到的最好的解决方案是,
1.创建一个新的 .NET 3.5 库项目并创建一个对报表进行实际处理的文件。

using Microsoft.Reporting.WebForms;
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;

//As you would expect, the new assembly WebReportviewer.FullTrustReportviewer
//all it does is just run the report. that's it. here is the code, it should be in a separated project:

namespace WebReportviewer
{
    [Serializable]
    public class FullTrustReportviewer : MarshalByRefObject
    {
        private ReportViewer FullTrust;
        public FullTrustReportviewer()
        {
            FullTrust = new ReportViewer();
            FullTrust.ShowExportControls = false;
            FullTrust.ShowPrintButton = true;
            FullTrust.ShowZoomControl = true;
            FullTrust.SizeToReportContent = false;
            FullTrust.ShowReportBody = true;
            FullTrust.ShowDocumentMapButton = false;
            FullTrust.ShowFindControls = true;
            //FullTrust.LocalReport.SubreportProcessing += LocalReport_SubreportProcessing;
            //FullTrust.LocalReport.SetBasePermissionsForSandboxAppDomain(new PermissionSet(PermissionState.Unrestricted));
        }

        public void Initialize(string DisplayName, string ReportPath, bool Visible, ReportParameter[] reportParam, string reportRenderFormat, string deviceInfo, string repMainContent, List<string[]> repSubContent)
        {
            FullTrust.LocalReport.DisplayName = DisplayName;
            FullTrust.LocalReport.ReportPath = ReportPath;
            //FullTrust.Visible = Visible;
            //FullTrust.LocalReport.LoadReportDefinition(new StringReader(repMainContent));
            FullTrust.LocalReport.SetParameters(reportParam);

            repSubContent.ForEach(x =>
            {
                FullTrust.LocalReport.LoadSubreportDefinition(x[0], new StringReader(x[1]));
            });
            FullTrust.LocalReport.DataSources.Clear();
        }

        public byte[] Render(string reportRenderFormat, string deviceInfo)
        {
            return FullTrust.LocalReport.Render(reportRenderFormat, deviceInfo);
        }
        public void AddDataSources(string p, DataTable datatable)
        {
            FullTrust.LocalReport.DataSources.Add(new ReportDataSource(p, datatable));
        }

        public SubreportProcessingEventHandler SubreportProcessing { get; set; }

        public static void LocalReport_SubreportProcessing(object sender, SubreportProcessingEventArgs e)
        {
            LocalReport lr = (LocalReport)sender;

            e.DataSources.Clear();
            ReportDataSource rds;

            if (e.ReportPath.Contains("DataTable2"))
            {
                DataTable dt = (DataTable)lr.DataSources["DataTable2"].Value;
                DataView dv = new DataView(dt);
                dv.RowFilter = string.Format("Id={0}", e.Parameters["Id"].Values[0]);
                rds = new ReportDataSource("DataTable2", dv.ToTable());
                e.DataSources.Add(rds);
            }
        }
    }
}

2.从现有项目中调用代码

 public static byte[] GeneratePBAReport()
        {


            string l_spName = string.Empty;
            string l_reportPath = string.Empty;
            var repCol = new List<ReportDataSource>();

            var repParCol = new ReportParameter[1];
            if (id == "")
            {

                l_reportPath = HttpContext.Current.Server.MapPath("~\\.rdlc");
                l_spName = "";
            }
            else
            {
                l_reportPath = HttpContext.Current.Server.MapPath("~\\.rdlc");
                l_spName = "";
            }

            repParCol[0] = new ReportParameter("pID", "");

            var ds = new DataSet();
            using (var sqlCmd = new SqlCommand(l_spName, new SqlConnection(ConfigurationManager.ConnectionStrings[""].ConnectionString)))
            {
                sqlCmd.CommandType = CommandType.StoredProcedure;
                var sqlParam = new SqlParameter() { Value = "", ParameterName = "" };
                sqlCmd.Parameters.Add(sqlParam);
                sqlCmd.CommandTimeout = 300;
                using (var sqlAdapter = new SqlDataAdapter(sqlCmd))
                {
                    sqlAdapter.Fill(ds);
                }
            }

            var rds = new ReportDataSource();
            rds.Name = "";
            rds.Value = ds.Tables[0];
            //l_report.DataSources.Add(rds);
            repCol.Add(rds);

            rds = new ReportDataSource();
            rds.Name = "";
            rds.Value = ds.Tables[1];
            //l_report.DataSources.Add(rds);
            repCol.Add(rds);

            rds = new ReportDataSource();
            rds.Name = "";
            rds.Value = ds.Tables[2];
            //l_report.DataSources.Add(rds);
            repCol.Add(rds);

            rds = new ReportDataSource();
            rds.Name = "";
            rds.Value = ds.Tables[3];
            //l_report.DataSources.Add(rds);
            repCol.Add(rds);

            Warning[] warnings;
            string[] streamids;
            string mimeType;
            string encoding;
            string extension;
            string deviceInfo;


            deviceInfo = "<DeviceInfo><SimplePageHeaders>True</SimplePageHeaders></DeviceInfo>";

            return NewDomainReport.Render("PDF", deviceInfo, "-" , l_reportPath, true, repCol, string.Empty, new List<string[]>(), repParCol);
        }

为了真正快速测试,您可以尝试在 web.config 中添加 CAS,如文章中所述。

在 ASP Net 应用程序中,您可以在 web.config 文件的 system.web 部分中使用

<trust legacyCasModel="true" level="Full"/>
来实现相同的结果。

如果速度显示出显着改善,上述代码将表现相同。上面代码的好处是创建一个单独的AppDomain,而不是影响整个解决方案。


1
投票

添加

<trust legacyCasModel="true" level="Full"/>
对我来说不是一个选项,因为我在代码中使用
dynamic
类型。

此代码正在运行:

public class CustomReportRenderer
{
    public static byte[] RenderReport(string reportPath, string rdlcDSName, DataTable rdlcDt, ReportParameter[] rptParams, string downloadFormat, out string mimeType, out string filenameExtension)
    {
        var assemblyDir = Path.GetDirectoryName(new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);
        AppDomainSetup setup = new AppDomainSetup()
        {
            ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
            ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile,
            LoaderOptimization = LoaderOptimization.MultiDomainHost,
            PrivateBinPath = assemblyDir
        };

        setup.SetCompatibilitySwitches(new[] { "NetFx40_LegacySecurityPolicy" });
        AppDomain _casPolicyEnabledDomain = AppDomain.CreateDomain("Full Trust", null, setup);
        try
        {
            FullTrustReportviewer rpt = (FullTrustReportviewer)_casPolicyEnabledDomain.CreateInstanceFromAndUnwrap(typeof(FullTrustReportviewer).Assembly.CodeBase, typeof(FullTrustReportviewer).FullName);
            rpt.Initialize(reportPath, rptParams);
            var bytes = rpt.Render(rdlcDSName, rdlcDt, downloadFormat, out mimeType, out filenameExtension);
            return bytes;
        }
        finally
        {
            AppDomain.Unload(_casPolicyEnabledDomain);
        }
    }

}

[Serializable]
public class FullTrustReportviewer : MarshalByRefObject
{
    private ReportViewer FullTrust;
    public FullTrustReportviewer()
    {
        FullTrust = new ReportViewer();
        FullTrust.ProcessingMode = Microsoft.Reporting.WebForms.ProcessingMode.Local;
    }

    public void Initialize(string reportPath, ReportParameter[] rptParams)
    {
        FullTrust.LocalReport.ReportPath = reportPath;
        FullTrust.LocalReport.SetParameters(rptParams);

    }
    public byte[] Render(string rdlcDSName, DataTable rdlcDt, string downloadFormat, out string mimeType, out string filenameExtension)
    {
        Warning[] warnings;
        string[] streamids;
        string encoding;
        FullTrust.LocalReport.DataSources.Add(new ReportDataSource(rdlcDSName, rdlcDt));
        var bytes = FullTrust.LocalReport.Render(downloadFormat, null, out mimeType, out encoding, out filenameExtension, out streamids, out warnings);
        return bytes;

    }
}

从aspx或mvc控制器方法调用

RenderReport
方法

var bytes = CustomReportRenderer.RenderReport(rdlcFileFullPath, "ReportsDataSet", ds.Tables[0], rptParams, downloadFormat, out mimeType, out extension);
// Now that you have all the bytes representing the PDF report, buffer it and send it to the client.
Response.Buffer = true;
Response.Clear();
Response.ContentType = mimeType;
Response.AddHeader("content-disposition", "attachment; filename=" + fileName + "." + extension);
Response.BinaryWrite(bytes); // create the file
Response.Flush(); // send it to the client to download

0
投票

简单的表达式和条件格式可能是罪魁祸首。

我们的一份报告在处理大数据(20,000+ 行)时也存在非常类似的问题。该查询返回数据很快,但生成到屏幕上的速度很慢,导出到 Excel 的速度更慢。使用报表查看器 10 和 12 时出现同样的问题。

令我惊讶的是,删除 tablix 排序日期格式表达式交替背景行颜色表达式 使此报告的生成速度更快,并且导出到 Excel 的时间从半个多小时缩短到大约一分钟.


0
投票

对于 Microsoft.ReportViewer.WebForms,asp.net 中的版本=15.0.0.0 c# .net Framework 4.8,我把它放在mi代码中:

System.Security.PermissionSet secSetting =new System.Security.PermissionSet(System.Security.Permissions.PermissionState.Unrestricted); ReportViewer1.LocalReport.SetBasePermissionsForSandboxAppDomain(secSetting);

我从这里获取它https://learn.microsoft.com/en-us/answers/questions/1045072/sql-server-reporting-services-rdlc-performance-iss

© www.soinside.com 2019 - 2024. All rights reserved.