【问题标题】:Crystal Reports Viewer with MVC3带有 MVC3 的 Crystal Reports 查看器
【发布时间】:2019-08-02 00:11:27
【问题描述】:

我正在构建一个 ASP.NET MVC3 Web 应用程序,我想使用水晶报表构建一些报表并使用水晶报表查看器显示它们。 我在网上搜索,但在 MVC3 Web 应用程序中没有找到任何可靠的方法。 您对如何操作有任何提示/想法吗?

【问题讨论】:

    标签: asp.net-mvc-3 crystal-reports


    【解决方案1】:

    如果你不介意一些黑客攻击,它实际上很容易。 (假设 CR4VS2010)

    首先在您的项目中添加一个 WebForms 页面,然后向其中添加水晶报表查看器控件。

    验证它添加了对以下内容的引用:

    CrystalDescisions.CrystalReports.Engine, CrystalDescisions.ReportSource, CrystalDescisions.Shared, 和CrystalDescisions.Web

    然后将 PageRoute 添加到您的应用程序中,指向新添加的页面。

    最后,这是 BLANK 最大的痛点,您需要让 Crystal 的图像处理程序正常工作。有很多假设的方法,无论是在网上还是在 SO,都没有真正适合我,所以我求助于作弊:

    public class CrystalImageHandlerController : Controller
    {
        //
        // GET: /CrystalImageHandler.aspx
    
        public ActionResult Index()
        {
            return Content("");
        }
    
        protected override void OnActionExecuted(ActionExecutedContext filterContext)
        {
    
            var handler = new CrystalDecisions.Web.CrystalImageHandler();
            var app = (HttpApplication)filterContext.RequestContext.HttpContext.GetService(typeof(HttpApplication));
            if (app == null) return;
    
            handler.ProcessRequest(app.Context);
    
        }
    }
    

    将此控制器的路由添加为 /CrystalReportsImageHandler.aspx,这是 CR 期望它的处理程序所在的位置。这也可以在Areas中使用,只需根据需要更改处理程序和页面路由即可。

    请记住,您将无法使用 Razor 布局。因此,您需要借助其他方式来获得视觉连续性。 (我使用了 IFrame)

    【讨论】:

    • 谢谢。我从here 获得了 Webform 部分,并将它与您的控制器结合起来,我设法查看了我的报告。
    • 太棒了!我还应该让您了解这个花絮:使用 Web 查看器时,它在浏览器中有一个 JS API。还没有找到任何关于它的文档,但是当它与我的网站布局一起使用时,使用 iframe,我发现它的 resize 方法非常宝贵。对象名称是 _UI.
    • 您提到:“将路由添加到此控制器作为 /CrystalReportsImageHandler.aspx”。我该怎么做?
    • 通过向 RouteTable 添加 Route,Scott Guthrie 在这里为您提供了帮助:weblogs.asp.net/scottgu/archive/2007/12/03/…
    【解决方案2】:

    在我们的项目中,我们直接以 PDF 格式返回报告。我们选择不在同一个项目中同时使用 WebForms 和 MVC,主要是因为保持代码库干净。

    报表是针对手动创建的“哑”数据集生成的,数据由服务类填充,该服务类通过 NHibernate 检索所需的所有信息(因为我们使用了一层 ORM 持久性和 DB 抽象,Crystal Reports 必须不直接连接到数据库)。

    如果您的项目不需要在浏览器中将报表显示为“预览模式”,这是我针对这种情况编写的自定义 ActionResult:

    public class PdfReportResult : ViewResult
    {
      /// <summary>
      /// Crystal Report filename
      /// </summary>
      public string reportFileName { get; set; }
    
      /// <summary>
      /// DataSet used in the report
      /// </summary>
      public DataSet reportDataSet { get; set; }
    
      /// <summary>
      /// Report parameters
      /// </summary>
      IDictionary<string, object> parameters { get; set; }
    
      public PdfReportResult(string reportFileName, DataSet reportDataSet, IDictionary<string, object> parameters)
      {
        if (string.IsNullOrEmpty(reportFileName))
          throw new ArgumentException("Report filename not informed", "reportFileName");
    
        if (reportDataSet == null)
          throw new ArgumentException("DataSet not informed", "reportDataSet");
    
        if (parameters == null)
          this.parameters = new Dictionary<string, object>();
        else
          this.parameters = parameters;
    
        this.reportDataSet = reportDataSet;
        this.reportFileName = reportFileName;
      }
    
      public PdfReportResult(string reportFileName, DataSet reportDataSet)
        : this(reportFileName, reportDataSet, null)
      { }
    
      public override void ExecuteResult(ControllerContext context)
      {
        if ( context == null )
          throw new ArgumentNullException("context");
    
        if ( string.IsNullOrEmpty(this.ViewName) )
          this.ViewName = context.RouteData.GetRequiredString("action");
    
        // Alias to make the code more legible
        HttpResponseBase response = context.HttpContext.Response;
    
        // Generating the report
        using ( ReportDocument report = new ReportDocument() )
        {
          // Load the report
          report.Load(context.HttpContext.Server.MapPath("~/Reports/" + reportFileName));
    
          // Set the dataset
          report.SetDataSource(reportDataSet);
    
          // Set the parameters (if any)
          foreach (var parameter in parameters)
            report.SetParameterValue(parameter.Key, parameter.Value);
    
          // Send back the PDF to the user
          using ( MemoryStream oStream = (MemoryStream)report.ExportToStream(ExportFormatType.PortableDocFormat) )
          {
            response.Clear();
            response.Buffer = true;
            response.AddHeader("Content-Disposition", this.ViewName + ".pdf");
            response.ContentType = "application/pdf";
            response.BinaryWrite(oStream.ToArray());
            response.End();
          }
        }
      }
    }
    

    【讨论】:

      【解决方案3】:

      由于水晶报表是一个服务器控件,我们需要一个网页/用户控件来显示报表。并且永远不要把这个 webform/user 控件放在 mvc 中的 views 文件夹中,你会在 CrViewer 中得到带有 404 的坏按钮。您还可以在 razor 视图中使用 Iframe 来显示报告。以下是一个工作模型[VS2010],请通过。

      第 1 步:设置水晶报表
      1.在网站根目录创建顶级文件夹。
      2. 将您的 Crystal report.rpt 文件放入此文件夹
      3. 将网页 (.aspx) 添加到此文件夹。此页面用作报表查看器页面。在此页面中添加 CrystalReportViewer 控件。

      <div align="center" style="width:100%; height:100%;">
              <CR:CrystalReportViewer ID="crViewer" runat="server" AutoDataBind="true" />
      </div>
      
      1. 以下程序集注册将添加到 aspx 页面的顶部。

        &lt;%@ Register Assembly="CrystalDecisions.Web, Version=13.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304" Namespace="CrystalDecisions.Web" TagPrefix="CR" %&gt;

      2. 检查 CrystalReportViewer 的版本。为此,请从 VS 侧边栏的工具箱中选择“选择项目”。将此版本与 aspx 页面顶部的 CrystalDecisions.Web 版本进行比较。如果两者相同,则保留它,否则更改与 CRViewer 相同的程序集注册版本。

      3. 进入网站根目录下的web.config文件;检查标签下以“CrystalDecisions”开头的程序集。更改与 CrystalReportViewer 版本相同的版本(此处为 Version=13.0.2000.0)。

      第 2 步:设置控制器、动作和视图
      1. 在报表控制器类中添加一个新动作。
      2. 编写从数据库/文件加载数据的必要步骤。
      3. 将数据设置为Session。
      4. 不要为此操作添加视图。而是使用 Response.Redirect 方法。

        public class ReportController : Controller
        {
        public ActionResult reportView(string id)
        {
        Session["ReportSource"] = GetdataFromDb();
        Response.Redirect("~/Reports/WebForm1.aspx");
        return View();
        }
        }
      
      1. 将页面加载事件添加到 .aspx 页面。

         protected void Page_Load(object sender, EventArgs e) 
         {
         CrystalDecisions.CrystalReports.Engine.ReportDocument report = 
         new CrystalDecisions.CrystalReports.Engine.ReportDocument();
         report.Load(Server.MapPath("~/Reports/CR_report.rpt"));
         report.SetDataSource(Session["ReportSource"]);
         crViewer.ReportSource =report; 
         }
        

      第 3 步:Global.asax 中的小技巧
      1. 避免“Session state has created a session id, but cannot save it because response has been flushed by the application.”错误或“blank Crystal report page output” i> 在 Global.asax 中添加以下代码。

        void Session_Start(object sender, EventArgs e)
        {
           string sessionId = Session.SessionID;
        }
      

      现在您可以调用 ReportController 中的 reportView() 操作来显示 Crystal Report。
      祝你有美好的一天!

      【讨论】:

        猜你喜欢
        • 2012-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多