lkosson / reportviewercore

Recompilation of Microsoft.ReportViewer for .NET Core 3.1+
427 stars 123 forks source link

Exception when rendering RDLC with an expression in Tablix/Visibility/Hidden tag #188

Closed Mek7 closed 5 months ago

Mek7 commented 5 months ago

Hello, I am having problems rendering a report that has two Tablix elements, and inside each there is Visibility and inside Visibility is Hidden element with an expression inside it. I am attaching the problematic RDLC file. rdlc.zip

Exception: Microsoft.Reporting.NETCore.LocalProcessingException: An error occurred during local report processing. ---> Microsoft.ReportingServices.Diagnostics.Utilities.RSException: The Hidden expression for the tablix ‘SpecificationTable’ contains an error: The input string '' was not in a correct format. ---> Microsoft.ReportingServices.ReportProcessing.ReportProcessingException: The Hidden expression for the tablix ‘SpecificationTable’ contains an error: The input string '' was not in a correct format. --- End of inner exception stack trace --- at Microsoft.Reporting.NETCore.LocalReport.InternalRender(String format, Boolean allowInternalRenderers, String deviceInfo, PageCountMode pageCountMode, CreateAndRegisterStream createStreamCallback, Warning[]& warnings) at Microsoft.Reporting.NETCore.LocalReport.InternalRender(String format, Boolean allowInternalRenderers, String deviceInfo, PageCountMode pageCountMode, String& mimeType, String& encoding, String& fileNameExtension, String[]& streams, Warning[]& warnings) at Microsoft.Reporting.NETCore.LocalReport.Render(String format, String deviceInfo, PageCountMode pageCountMode, String& mimeType, String& encoding, String& fileNameExtension, String[]& streams, Warning[]& warnings) at Microsoft.Reporting.NETCore.Report.Render(String format, String deviceInfo, String& mimeType, String& encoding, String& fileNameExtension, String[]& streams, Warning[]& warnings) at Microsoft.Reporting.NETCore.Report.Render(String format, String deviceInfo) at ... blablabla (my calling code)

The problematic part of the RDLC:

                              <Visibility>
                                <Hidden>=IIF(Fields!EPCustomer2.Value=1,True,
IIF(SUM(IIF(Fields!InvoiceCustomerInvoiceSpecification.Value=0,0,IIF
 (Fields!InvoiceLineType2.Value=0,1,IIF(Fields!InvoiceLineType2.Value=1,1,0))))
  &gt;0,FALSE,TRUE))</Hidden>
                              </Visibility>

There are two such problematic parts in the RDLC file, one in each Tablix. If I remove both, the RDLC renders successfully. I have verified that in the original MS ReportViewer, there is no exception and the report renders without problems, even with the Visibility tags there. This leads me to a question - how much can I rely on ReportViewer.Core being as close as possible to the original MS ReportViewer (taking into account the stuff that reportedly isn't ported as described in README.md)? My scenario is that I need to migrate a solution to .NET 8, and am dissecting the RDLC rendering to a separate microservice. Currently my microservice is using .NET 8 as well (and uses this ReportViewer.Core library) but maybe it should still be using .NET 4.8 with the original MS library...? (that would be awful but most compatible). Thanks.

Mek7 commented 5 months ago

Btw. I have many more RDLC files that are already being used in the wild. I want to test them all to make sure they are compatible, so if the issue mentioned above is fixed, I can continue testing and together we can make this library better :)

lkosson commented 5 months ago

Inspect whether EPCustomer2, InvoiceCustomerInvoiceSpecification and InvoiceLineType2 all contain numeric value convertible to double using current CultureInfo. Also set up Visual Studio to catch first-chance System.FormatException and if it is thrown when executing the report, post the call stack here. Most likely topmost frame will be call to Double.Parse with an empty string produced when evaluating one of above-mentioned fields.

Expression engine in ReportViewerCore is based on .NET Core and Roslyn, while original package used .NET Framework and vbc. That means some features of VB/expressions might behave slightly different. Also, there might be some differences in handling culture-specific parsing. Apart from that and missing CAS/AppDomains support in .NET Core, this package should behave pretty much the same as original one.

Mek7 commented 5 months ago

I got the problem. The field EPCustomer2 is null and so rendering fails, but the original MS report viewer can somehow cope with that. I verified that the report rendered OK when I replaced the reference to EPCustomer2 with a different field that was not null(able), for example InvoiceCustomerInvoiceSpecification

FYI... EPCustomer2 is of type string InvoiceCustomerInvoiceSpecification is of type bool InvoiceLineType2 is of type int

I know this could probably be solved by rewriting the expressions in all reports to take null values into account, but as there are many existing reports, it is not possible :( Since it works OK in the original MS report viewer, it would be great if this could be fixed in ReporrViewerCore.

Mek7 commented 5 months ago

The details of the exception:

Microsoft.Reporting.NETCore.LocalProcessingException
  HResult=0x80131500
  Message=An error occurred during local report processing.
  Source=Microsoft.ReportViewer.NETCore
  StackTrace:
   at Microsoft.Reporting.NETCore.LocalReport.InternalRender(String format, Boolean allowInternalRenderers, String deviceInfo, PageCountMode pageCountMode, CreateAndRegisterStream createStreamCallback, Warning[]& warnings)
   at Microsoft.Reporting.NETCore.LocalReport.InternalRender(String format, Boolean allowInternalRenderers, String deviceInfo, PageCountMode pageCountMode, String& mimeType, String& encoding, String& fileNameExtension, String[]& streams, Warning[]& warnings)
   at Microsoft.Reporting.NETCore.LocalReport.Render(String format, String deviceInfo, PageCountMode pageCountMode, String& mimeType, String& encoding, String& fileNameExtension, String[]& streams, Warning[]& warnings)
   at Microsoft.Reporting.NETCore.Report.Render(String format, String deviceInfo, String& mimeType, String& encoding, String& fileNameExtension, String[]& streams, Warning[]& warnings)
   at Microsoft.Reporting.NETCore.Report.Render(String format, String deviceInfo)
   at (... my calling code ...)

  This exception was originally thrown at this call stack:
    Microsoft.ReportingServices.RdlExpressions.ReportRuntime.RegisterRuntimeErrorInExpression(ref Microsoft.ReportingServices.RdlExpressions.VariantResult, System.Exception, Microsoft.ReportingServices.ReportProcessing.IErrorContext, bool)
    Microsoft.ReportingServices.RdlExpressions.ReportRuntime.RegisterRuntimeErrorInExpressionAndStop(ref Microsoft.ReportingServices.RdlExpressions.VariantResult, System.Exception)
    Microsoft.ReportingServices.RdlExpressions.ReportRuntime.EvaluateStartHiddenExpression(Microsoft.ReportingServices.ReportIntermediateFormat.Visibility, Microsoft.ReportingServices.RdlExpressions.ExpressionHostObjectModel.IVisibilityHiddenExprHost, Microsoft.ReportingServices.ReportProcessing.ObjectType, string)
    Microsoft.ReportingServices.ReportIntermediateFormat.ReportItem.EvaluateStartHidden(Microsoft.ReportingServices.OnDemandReportRendering.IReportScopeInstance, Microsoft.ReportingServices.OnDemandProcessing.OnDemandProcessingContext)
    Microsoft.ReportingServices.ReportIntermediateFormat.ReportItem.ComputeStartHidden(Microsoft.ReportingServices.OnDemandReportRendering.RenderingContext)
    Microsoft.ReportingServices.ReportIntermediateFormat.Visibility.ComputeHidden(Microsoft.ReportingServices.ReportIntermediateFormat.IVisibilityOwner, Microsoft.ReportingServices.OnDemandReportRendering.RenderingContext, Microsoft.ReportingServices.ReportIntermediateFormat.ToggleCascadeDirection, out bool)
    Microsoft.ReportingServices.ReportIntermediateFormat.ReportItem.ComputeHidden(Microsoft.ReportingServices.OnDemandReportRendering.RenderingContext, Microsoft.ReportingServices.ReportIntermediateFormat.ToggleCascadeDirection)
    Microsoft.ReportingServices.OnDemandReportRendering.ReportItemVisibilityInstance.CurrentlyHidden.get()
    Microsoft.ReportingServices.Rendering.HPBProcessing.PageItem.Create(Microsoft.ReportingServices.OnDemandReportRendering.ReportItem, bool, bool, Microsoft.ReportingServices.Rendering.HPBProcessing.PageContext)
    Microsoft.ReportingServices.Rendering.HPBProcessing.PageItem.Create(Microsoft.ReportingServices.OnDemandReportRendering.ReportItem, bool, Microsoft.ReportingServices.Rendering.HPBProcessing.PageContext)
    ...
    [Call Stack Truncated]

Inner Exception 1:
RSException: The Hidden expression for the tablix ‘SpecificationTable’ contains an error: The input string '' was not in a correct format.

Inner Exception 2:
ReportProcessingException: The Hidden expression for the tablix ‘SpecificationTable’ contains an error: The input string '' was not in a correct format.
lkosson commented 5 months ago

As far as I can tell, expression =Fields!TextField.Value=1 crashes with System.FormatException when TextField has non-null non-numeric value and works fine when the field is null - both in original ReportViewer and in ReportViewerCore.

If you are sure your exact report with exactly same dataset works in original library and fails with this one, please provide a sample based on ReportViewerCore.Sample.Console project in this repo.

Also, provide a first-chance exception stack trace of thrown System.FormatException. Original call site is swallowed up by ReportViewer exception handling code.

Mek7 commented 5 months ago

Oh, it now struck me when you wrote with exactly the same dataset. I now remembered that the report was done for a specific dataset, for a customer that will always have the EPCustomer2 set in his data. I verified that it also fails the same way in MS ReportViewer when the data is not present in the dataset. So I am closing this (non)issue, sorry for the confusion.