使用MVC框架破坏CrystalReportViewer按钮

时间:2020-03-06 14:56:38  来源:igfitidea点击:

我们正在使用MVC框架(版本5)和CrystalReportViewer控件来显示我们的报告。我无法使报表查看器控件顶部的任何按钮正常工作。

如果我正在使用"小时摘要"报告。如果我将鼠标悬停在IE中报表查看器上的任何按钮上,则页面底部显示的链接为" ../HoursSummary"。这将创建一个URL" http:// localhost / HoursSummary"。没有" HoursSummary"控制器,因此我一直收到404错误。

  • 我相信我想重定向到" http:// localhost / reports / HoursSummary",因为我确实有一个报告控制器。如果这是正确的方法,谁知道我应该在CrystalReportViewer控件上设置哪个属性以实现此目的?
  • 有没有更简单的方法来处理这种情况?

解决方案

如果那是服务器控件,它将无法正常工作。 ASP.NET MVC不使用任何回发,因此大多数Webforms服务器控件均不起作用。

我们可以做的是将报表查看器嵌入到iFrame中,然后将其输出到MVC视图中。 iframe可以指向MVC内容之外的页面,例如在称为"旧版"之类的子文件夹中。

我们能够使报表查看器正常工作,并且在过去的几个月中一直在生产中使用它,而没有任何问题。

  • 我们有一个报告控制器,其中列出了要运行的报告的链接
  • 单击其中一个链接将对后端进行ajax调用,并返回部分页面,我们可以在其中填写所需的所有参数。
  • 填写完参数后,我们将表格提交到" \ reports \ Name of Report"。
  • 回到Reports控制器中,我们调用SQL,返回数据,然后调用另一个名为" Full Report"的视图
  • "完整报告"视图仅具有水晶报告查看器控件,该控件会自动获取我们通过ViewData传递给它的报告数据,填充报告,呈现报告并将其发送给用户

一切似乎都很好。

更新

我已经在上面最初列出的步骤中添加了一些代码和说明。我遗漏的关键项是最终的View后面有一些代码,因此它将与Crystal Reports一起使用。后面的代码是最少的,但是是必需的。为了使Crystal Reports正常工作,我们将获得以下文件:

  • 设计报告的布局文件.rpt
  • 一个保存Crystal Reports报表控件的aspx文件。这是文件,后面会有一些代码。

有关如何创建适用于Crystal Reports的视图的详细信息:

  • 使用Crystal Reports设计器创建报告的布局。结果文件将是一个.rpt文件。为了本示例的缘故,让我们将此文件命名为AllJobsSummaryReportLayout.rpt。
  • 在设计报表时,对于"数据库字段",选择保存来自SQL的结果的业务实体或者DTO之一。
  • 顺便说一句,我们系统中有一些数据传输对象(DTO),它们仅包含标量值和字符串,这些DTO中没有智能。当调用Controller时,它将调用Model,大多数这些报告的Model返回DTO列表,然后我们将这些DTO传递给要呈现的View。这些DTO不知道如何查询自己,如何显示自己,它们仅包含从其他人随后呈现的SQL返回的实际值。
  • 布局Crystal Report文件完成后,即AllJobsSummaryReportLayout.rpt,我们将设计控制器。在Controller中,我们接受运行报告所需的任何参数,称为Model,Model返回我们的DTO列表,如下面的Controller片段所示:
var reportViewData = model.AllJobsSummaryQuery(startDate, endDate);
if (0 != reportViewData.Count())
{
    var report = new AllJobsSummaryReportLayout();
    report.SetDataSource(reportViewData);
    report.SetParameterValue("startDate", startDate);
    report.SetParameterValue("endDate", endDate);
    ViewData["ReportData"] = report;
    returnView = "AllJobsSummaryView";
}
else
    returnView = "noReportView";
return View(returnView);
  • 请注意此处的几项内容,我们正在创建一个变量"报告",它是上面创建的Crystal Report布局文件AllJobsSummaryReportLayout.rpt的一种。
  • 创建'report'变量后,我们将设置数据源值和所需的任何参数,并将该项目捆绑到ViewData中。
  • 现在,让我们看一下AllJobsSummaryView.aspx。该文件上有一个带有Crystal Reports Viewer的窗体,以及文件后面的代码:
<%@ Page Title="All Jobs Summary Report" Language="C#" AutoEventWireup="true" CodeBehind="AllJobsSummaryView.aspx.cs" Inherits="V.Views.Reports.AllJobsSummaryView"%>     
<%@ Register Assembly="CrystalDecisions.Web, Version=10.5.3700.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" Namespace="CrystalDecisions.Web" TagPrefix="CR" %> 
<form id="form1" runat="server">
<div>
<a href="/Reports" id="Report"><< Return to Report Main
    Page</a><br />
<CR:CrystalReportViewer ID="ReportViewer" runat="server" AutoDataBind="True" EnableDatabaseLogonPrompt="False"
    EnableParameterPrompt="False" HasCrystalLogo="False" DisplayGroupTree="False" 
    HasDrillUpButton="False" HasToggleGroupTreeButton="False" HasViewList="False" 
    HasSearchButton="False" EnableDrillDown="False" EnableViewState="True" 
    Height="50px" ReportSourceID="CrystalReportSource1" Width="350px" />    
<CR:CrystalReportSource ID="CrystalReportSource1" runat="server">
    <Report FileName="AllJobsSummaryReportLayout.rpt">
    </Report>
</CR:CrystalReportSource>
</div>
</form>
  • 以及文件后面的代码:
using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Web;
 using System.Web.Mvc;

 namespace V.Views.Reports
 {
    public partial class AllJobsSummaryView : ViewPage
    {
        protected void Page_Init(object sender, EventArgs e)
        {
            ReportViewer.ReportSource = ViewData["ReportData"];
        }

        protected void Page_Unload(object sender, EventArgs e)
        {
            ((AllJobsSummaryReportLayout)ViewData["ReportData"]).Close();
            ((AllJobsSummaryReportLayout)ViewData["ReportData"]).Dispose();
        }
    }
 }
  • Page_Unload是关键,否则,Crystal Reports会生成错误消息"我们已超出管理员设置的最大报告数量。"

这种方法在生产环境中至今仍使用了两年多的时间。