1
votes

I have come across a very strange exception when using Crystal Reports XI for dot net. I'm currently developing a reporting service in VB.Net for an enterprise application. The service is hosted in the main application as a plugin/add-in using System.AddIn (aka Managed Add-in Framework or MAF). The main application utilizes Win Forms, and will be hosting controls provided by my add-in in a WPFElementHost.

The add-in resides in it's own app domain and passes WPF controls using NativeHandleContracts from the add-in app domain, to the host app domain where they are bound at runtime to the WPFElementHost.

The WPF control the add-in provides has a Crystal Report Viewer Control in it. Up to this point, everything works fine. I can create nearly any WPF control in my Add-in and it works flawlessly in the host application. This falls apart as soon as I try and attach a report to the viewer.

First I tried using and ADO.Net DataSet as my data schema to build my report against. Whenever this would try and load into the report viewer, crystal reports would throw an exception that the schema didn't exist. This was caused because for some reason crystal report want's to look in the host applications app domain, as well as namespace for the schema. However The schema exists in an entirely different app domain and namespace. I tried embedding the schema as a resource, and copying local. With no success I moved on to using .Net Objects.

With .Net Objects I created an XML document that the report is designed against. This worked fine and allowed me to pass my report and view it in the host application. This is where I am stuck at the moment. Whenever I try and supply a DataSource for the report Crystal Reports throws a null reference exception in the crdb_adoplus.dll which is SAP's DLL and gives me no indication of what caused the exception. All of my objects are properly instantiated, the report, viewer, wpf element host, and the wpf control. My dataset, which is served using entity framework, is being converted to a DataSet so there are no nullable types in it, only dbnull values. There is no reason this exception should be throwing at this point. No additional output is provided other than the exception being thrown.

Additionally, the report object that is created will have portions of it time out during this loading process. This will happen without any exceptions or errors of any kind being thrown.

Here is the code that is retrieving the data, attempting to bind data to the report, and binding the report to the viewer.

        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

The report.SetDataSource(dataSet) bit of code is where the exception is being thrown.

Am I overlooking somthing obvious? Is there a way to convince Crystal Reports to use an ADO.Net DataSet in the correct app domain so I can get away from the XML issue?

This add-in needs to exist in a separate app domain, or process, so that it can be unloaded and reloaded dynamically at runtime. This is a requirement for the system. It also needs to be self contained, so I can't do anything on the host side of the application, it all must operate within the add-in.

Thanks in advance for the help.

1
Just as an added note, ToDataSet is a generic extesion that converts and IList set to a DataSet. That works just fine and was needed to convert Entity Framework Nullable types to DBNull.Values.Brian S

1 Answers

2
votes

After digging around I figured out an answer to my own question. So i'll post the answer here just in case someone else comes across a similar problem.

The problem seems to lie in how the report interprets the DataSet object. For some reason it get's lost when looking for data. So you have to point it to the actual first table entry.

So I changed this bit of code:

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

I replaced report.SetDataSource(dataSet) with report.SetDatSource(dataSet.Tables(0)). So now it looks like this

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

Hopefully this will help someone else out in the future.