1

在将 Crystal Reports XI 用于 dot net 时,我遇到了一个非常奇怪的异常。我目前正在为企业应用程序在 VB.Net 中开发报告服务。该服务使用System.AddIn(又名托管加载项框架或 MAF)作为插件/加载项托管在主应用程序中。主应用程序使用 Win Forms,并将在 WPFElementHost 中托管由我的加载项提供的控件。

加载项驻留在它自己的应用程序域中,并使用NativeHandleContracts将 WPF 控件从加载项应用程序域传递到它们在运行时绑定到 WPFElementHost 的宿主应用程序域。

外接程序提供的 WPF 控件中有一个 Crystal Report Viewer 控件。到目前为止,一切正常。我可以在我的加载项中创建几乎任何 WPF 控件,并且它在主机应用程序中完美运行。一旦我尝试向查看器附加报告,这就会崩溃。

首先,我尝试使用 ADO.Net DataSet 作为我的数据模式来构建我的报告。每当这将尝试加载到报表查看器中时,水晶报表都会抛出架构不存在的异常。这是因为由于某种原因水晶报告想要查看主机应用程序应用程序域以及模式的命名空间。但是,架构存在于完全不同的应用程序域和命名空间中。我尝试将架构嵌入为资源,并复制本地。没有成功,我转而使用 .Net Objects。

使用 .Net Objects,我创建了一个用于设计报告的 XML 文档。这工作得很好,让我可以通过我的报告并在主机应用程序中查看它。这就是我现在卡住的地方。每当我尝试为报表提供 DataSource 时,Crystal Reports 都会在 SAP 的 DLL crdb_adoplus.dll 中引发空引用异常,并且没有告诉我导致异常的原因。我的所有对象、报表、查看器、wpf 元素宿主和 wpf 控件都已正确实例化。我的数据集使用实体框架提供服务,正在转换为 DataSet,因此其中没有可为空的类型,只有 dbnull 值。没有理由此时应该抛出这个异常。除了抛出异常之外,没有提供额外的输出。

此外,在此加载过程中,创建的报表对象的部分内容将超时。这将在没有任何异常或任何类型的错误被抛出的情况下发生。

下面是检索数据、尝试将数据绑定到报表以及将报表绑定到查看器的代码。

        Try
            Dim messages As String = Nothing

            If report Is Nothing Then
                report = New BOMPartsListWithStandard
            End If

            Using conn = BOMReportingService.BOMReportingServiceClient.CreateConnection()
                Dim dataSet As DataSet = conn.Proxy.GetBOMTreePartsListElements(5339, messages).ToDataSet
                report.SetDataSource(dataSet)
            End Using

            reportViewer.ViewerCore.ReportSource = report
            reportViewer.ViewerCore.RefreshReport()
            Debug.WriteLine($"Created and attached report succesfully. With {IIf(String.IsNullOrEmpty(messages), "no messages.", messages)}")
        Catch ex As Exception
            Debug.WriteLine(ex.ToString)
        End Try

这段report.SetDataSource(dataSet)代码是抛出异常的地方。

我是否忽略了一些明显的东西?有没有办法说服 Crystal Reports 在正确的应用程序域中使用 ADO.Net 数据集,这样我就可以摆脱 XML 问题?

此加载项需要存在于单独的应用程序域或进程中,以便可以在运行时动态卸载和重新加载。这是对系统的要求。它还需要是自包含的,所以我不能在应用程序的主机端做任何事情,这一切都必须在加载项内运行。

在此先感谢您的帮助。

4

1 回答 1

2

在四处挖掘之后,我找到了自己问题的答案。所以我会在这里发布答案,以防其他人遇到类似的问题。

问题似乎在于报表如何解释 DataSet 对象。由于某种原因,它在查找数据时会丢失。所以你必须将它指向实际的第一个表条目。

所以我改变了这段代码:

        Using conn = BOMReportingService.BOMReportingServiceClient.CreateConnection()
            Dim dataSet As DataSet = conn.Proxy.GetBOMTreePartsListElements(5339, messages).ToDataSet
            report.SetDataSource(dataSet)
        End Using

我替换report.SetDataSource(dataSet)report.SetDatSource(dataSet.Tables(0)). 所以现在看起来像这样

        Using conn = BOMReportingService.BOMReportingServiceClient.CreateConnection()
            Dim dataSet As DataSet = conn.Proxy.GetBOMTreePartsListElements(5339, messages).ToDataSet
            report.SetDataSource(dataSet.Tables(0))
        End Using

希望这将在未来帮助其他人。

于 2016-04-07T21:17:16.677 回答