WPF 4 SQL Server Reporting Services processing application Memory Leak
Oct
11
WRITTEN BY:
11/10/2010 11:37 PM
I recently upgraded a report generation and emailing solution written in MS Access to .net 4 to address issues with SMTP email crashes. The VBA solution was also taking 3 hours to generate and sent 2,800 reports and it was very hard to narrow down the SMTP exceptions that were occurring.
There were a number of technical issues involved with running the new Visual Studio 2010 report viewer in a WPF screen.
Firstly the control is Windows Forms technology, so you have to host it.
<WindowsFormsHost Name="ReportViewerWindowsFormsHost" Grid.IsSharedSizeScope="False">
<viewer:ReportViewer x:Name ="MyReportViewer" />
WindowsFormsHost>
Secondly when running a long reporting batch job, you really want to let the user know what's going on and allow them to do other things in the application. We implemented a Background worker to loop through all the reports and pass parameters to the ReportViewer.xaml screen.
01.Private Sub _BackgroundWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles _BackgroundWorker.DoWork
02.
03. ' The Dispatcher method seems to interfere with this call
04. _BackgroundWorker.ReportProgress(progress, "Generating report files for " & FullBatchList.Item(myLoop).HeadOfficeCode & " ...")
05.
06. For myReportLoop As Integer = 0 To myReports.Length - 1
07. Try
08.
09. ' LL: 3 - Ok, so lets use a syncronous Dispatcher (UI Thread) to execute this code.
10. ' If you don't do this you get a "The calling thread must be STA, because many UI components require this." exception.
11. Me.Dispatcher.Invoke(DispatcherPriority.Background, New ExecuteReportDelegate(AddressOf GenerateReports.ExecuteReport), CInt(myReports(myReportLoop)))
12.
13. Catch ex As Exception
14. ExceptionFree = False
15.
16. End Try
17. Next
18. End Sub
So we use the background worker to do some processing, but have to use the dispatcher.Invoke method to execute the report because it's going to open the ReportViewer.xaml, run the report and export the results to PDF, Excel etc. However the Dispatcher seems to hog the UI thread, so our background worker progress bar never seems to update during this process. :(
Executing a report simply does the following and the ReportViewer.xaml automatically closes once the PDF file is generated.
01.frm = New ReportViewer
02.With frm
03. .Visibility = Windows.Visibility.Hidden
04. .ReportHistoryID = reportHistoryID
05. .ReportHeaderExists = True
06. .ReportOutputTo = ReportViewer.eReportOutputType.PDF
07. .PdfFileFullPath = mDestinations(2)
08. .ShowDialog()
09.End With
Finally, the most frustrating result is the profiling results, where it looks like the whole solution generates a slow memory leak. You can see here that we get these weak references and every instance of the ReportViewer.xaml screen is retained in memory.
I've got to resolve the memory issue before releasing to our customer, because they are unlikely to have the x64 and 4GB memory set that most development PC's have. We upgraded the technology stack for this solution to address one problem and now we are faced with another.