使用Crystal Reports XI for dot net时,我遇到了一个非常奇怪的异常。我目前正在VB.Net中为企业应用程序开发报表服务。该服务使用System.AddIn (aka Managed Add-in Framework or MAF)作为插件/加载项托管在主应用程序中。主应用程序使用Win Forms,并将托管由我的加载项在WPFElementHost中提供的控件。
加载项位于其自己的应用程序域中,并使用NativeHandleContracts从加载项应用程序域将WPF控件传递到主机应用程序域,它们在运行时绑定到WPFElementHost。
加载项提供的WPF控件中包含一个Crystal Report Viewer Control。到目前为止,一切正常。我可以在我的加载项中创建几乎任何WPF控件,它在主机应用程序中完美运行。一旦我尝试向观众附上报告,这就会崩溃。
首先,我尝试使用ADO.Net DataSet作为我的数据模式来构建我的报告。每当这会尝试加载到报表查看器中时,水晶报表就会抛出架构不存在的异常。造成这种情况的原因是,由于某些原因,水晶报告需要查看主机应用程序应用程序域以及架构的命名空间。但是,架构存在于完全不同的应用程序域和命名空间中。我尝试将架构嵌入为资源,并复制本地。没有成功,我继续使用.Net Objects。
使用.Net Objects,我创建了一个针对该报告设计的XML文档。这很好,并允许我传递我的报告并在主机应用程序中查看它。这就是我现在被困住的地方。 每当我尝试为报表提供DataSource时,Crystal Reports会在crdb_adoplus.dll 中抛出一个空引用异常,这是SAP的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 DataSet,这样我就可以摆脱XML问题了?
此加载项需要存在于单独的应用程序域或进程中,以便可以在运行时动态卸载和重新加载。这是系统的要求。它也需要是自包含的,所以我不能在应用程序的主机端做任何事情,它必须在加载项中运行。
提前感谢您的帮助。
答案 0 :(得分:1)
在挖掘之后,我找到了自己问题的答案。所以我会在这里发布答案,以防其他人遇到类似的问题。
问题似乎在于报告如何解释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
希望将来可以帮助其他人。