DavidAvery
asked on
asp.net usage of web viewer and postback problems
Hello all
I am getting the error: The maximum report processing jobs limit configured by your system administrator has been reached, using CRW XI R2.
Problem Description
This error is occuring on a custom web reporting application previously running well in crystal 10 (Enterprise). I have researched the problem to be my lack of calling a reportdoc.dispose on page_unload. Here's my problem. I am using asp.net 1.1, and I am using the crystal reportviewer. Most reports are multi-page, so the users run the report and browse around it as needed. To keep the report from re-running as they page through, I am caching the reportdocument to a session variable, and restoring it if the session variable is intact. My problem is that if I do not call reportdocument.dispose in page_unload, I get the The maximum report processing jobs limit configured by your system administrator has been reached error. If I call the dispose, when pagination occurs, I cannot rely upon my cached reportdocument, and I get another error (invalid object). I think it’s pretty inefficient to re-run the report between every page, some take 15-20 seconds to process. I also launch one of 12 different reports to separate popup windows for viewing, so it is important that each popup window retain it’s own state. Can you assist me with a strategy for doing this effectively? BO samples that are distributed with the report tool do not dispose their reportdocuments at all.
I have thought about pulling the dataset first, and caching that and pushing it at the report, but I would prefer not to rewrite the reports. One BO tech came up with a solution where JS onclose launched a cleanup which was pretty ugly. I am hoping that there are perhaps techniques for caching the report object that can make this work.
Note that expanding the number of reports using the registry key is not a valid solution, without a dispose, the sessions are closing leaving the reportdocuments open.
Thanks!
I am getting the error: The maximum report processing jobs limit configured by your system administrator has been reached, using CRW XI R2.
Problem Description
This error is occuring on a custom web reporting application previously running well in crystal 10 (Enterprise). I have researched the problem to be my lack of calling a reportdoc.dispose on page_unload. Here's my problem. I am using asp.net 1.1, and I am using the crystal reportviewer. Most reports are multi-page, so the users run the report and browse around it as needed. To keep the report from re-running as they page through, I am caching the reportdocument to a session variable, and restoring it if the session variable is intact. My problem is that if I do not call reportdocument.dispose in page_unload, I get the The maximum report processing jobs limit configured by your system administrator has been reached error. If I call the dispose, when pagination occurs, I cannot rely upon my cached reportdocument, and I get another error (invalid object). I think it’s pretty inefficient to re-run the report between every page, some take 15-20 seconds to process. I also launch one of 12 different reports to separate popup windows for viewing, so it is important that each popup window retain it’s own state. Can you assist me with a strategy for doing this effectively? BO samples that are distributed with the report tool do not dispose their reportdocuments at all.
I have thought about pulling the dataset first, and caching that and pushing it at the report, but I would prefer not to rewrite the reports. One BO tech came up with a solution where JS onclose launched a cleanup which was pretty ugly. I am hoping that there are perhaps techniques for caching the report object that can make this work.
Note that expanding the number of reports using the registry key is not a valid solution, without a dispose, the sessions are closing leaving the reportdocuments open.
Thanks!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
This is interesting:
http://msdn2.microsoft.com/en-us/library/ms225490(VS.80).aspx
Crystal Reports for Visual Studio 2005
Use the Close() Method to free up the report
Another way to optimize scalability in a Crystal Reports for Visual Studio 2005 project is to use one of the available Close() methods to release the memory that is used by the report.
Two Close() methods are available:
ReportDocument.Close() that is used with Crystal Reports.
ReportClientDocument.Close () that is used with unmanaged RAS or managed RAS.
The ReportDocument.Close() method
When using Crystal Reports for Visual Studio 2005, you can use the ReportDocument.Close() method to release the memory that the Crystal report consumes on the Web server.
How the ReportDocument.Close() method is accessed depends on whether the report is embedded or non-embedded:
If the report is embedded, a report wrapper class is generated to represent the report in code. This report wrapper class inherits from ReportDocument, and the Close() method is accessed by inheritance.
If the report is not embedded, it is loaded from the file directory into an instance of ReportDocument, and the Close() method is accessed directly from the ReportDocument class.
Note For more information on embedded and non-embedded reports, see Should I Use Embedded or Non-embedded Reports?.
Both the Crystal report and the instance of the ReportDocument each consume memory. When the ReportDocument is freed from memory, the report continues to use memory.
For example, the ReportDocument instance falls out of scope when the Web page finishes loading. When the garbage collection for .NET disposes of the ReportDocument instance, the memory that is used by the ReportDocument instance is released from the Web server.
However, the report itself remains in memory on the Web server. It cannot be removed, because a ReportDocument instance no longer exists to access the report. When those circumstances are repeated in a highly scaled situation, the memory on the Web server fills with reports that are no longer being accessed.
To resolve that problem, call the ReportDocument.Close() method. The report itself is closed on the Web server and the memory is released for further reports.
When to call the ReportDocument.Close() method
The ReportDocument.Close() method should not be called on the page before the report has been displayed because, even if the report has been closed, ReportDocument will reopen the report if it is referenced again. The Close() method should only be called after the display process is complete.
The right time to call the Close() method is during the Page_Unload event.
The ReportClientDocument.Close () method
When using an unmanaged RAS or managed RAS server, reports are stored on the Report Application Server, but they are represented on the Web server by an instance of ReportClientDocument. If the ReportClientDocument instance passes out of scope without calling the ReportClientDocument.Close () method, the Report Application Server keeps the report open in memory, even though the report can no longer be accessed. When those circumstances are repeated in a highly scaled situation, the memory on the Report Application Server fills with reports that are no longer being accessed on the Web server.
To resolve that problem, call the ReportClientDocument.Close () method. The report is closed on the Report Application Server and the memory is released for further reports.
When to call the ReportClientDocument.Close () method
The Close() method should not be called on the page before the report has been displayed, because the report must remain open on the server until the display process has been completed.
For a ReportClientDocument instance, the Close() method immediately closes the report and the report cannot be reopened. Therefore, if the Close() method is called before the report is displayed, the report will be inaccessible and an exception will be thrown.
The right time to call the Close() method is during the Page_Unload event.
http://msdn2.microsoft.com/en-us/library/ms225490(VS.80).aspx
Crystal Reports for Visual Studio 2005
Use the Close() Method to free up the report
Another way to optimize scalability in a Crystal Reports for Visual Studio 2005 project is to use one of the available Close() methods to release the memory that is used by the report.
Two Close() methods are available:
ReportDocument.Close() that is used with Crystal Reports.
ReportClientDocument.Close
The ReportDocument.Close() method
When using Crystal Reports for Visual Studio 2005, you can use the ReportDocument.Close() method to release the memory that the Crystal report consumes on the Web server.
How the ReportDocument.Close() method is accessed depends on whether the report is embedded or non-embedded:
If the report is embedded, a report wrapper class is generated to represent the report in code. This report wrapper class inherits from ReportDocument, and the Close() method is accessed by inheritance.
If the report is not embedded, it is loaded from the file directory into an instance of ReportDocument, and the Close() method is accessed directly from the ReportDocument class.
Note For more information on embedded and non-embedded reports, see Should I Use Embedded or Non-embedded Reports?.
Both the Crystal report and the instance of the ReportDocument each consume memory. When the ReportDocument is freed from memory, the report continues to use memory.
For example, the ReportDocument instance falls out of scope when the Web page finishes loading. When the garbage collection for .NET disposes of the ReportDocument instance, the memory that is used by the ReportDocument instance is released from the Web server.
However, the report itself remains in memory on the Web server. It cannot be removed, because a ReportDocument instance no longer exists to access the report. When those circumstances are repeated in a highly scaled situation, the memory on the Web server fills with reports that are no longer being accessed.
To resolve that problem, call the ReportDocument.Close() method. The report itself is closed on the Web server and the memory is released for further reports.
When to call the ReportDocument.Close() method
The ReportDocument.Close() method should not be called on the page before the report has been displayed because, even if the report has been closed, ReportDocument will reopen the report if it is referenced again. The Close() method should only be called after the display process is complete.
The right time to call the Close() method is during the Page_Unload event.
The ReportClientDocument.Close
When using an unmanaged RAS or managed RAS server, reports are stored on the Report Application Server, but they are represented on the Web server by an instance of ReportClientDocument. If the ReportClientDocument instance passes out of scope without calling the ReportClientDocument.Close
To resolve that problem, call the ReportClientDocument.Close
When to call the ReportClientDocument.Close
The Close() method should not be called on the page before the report has been displayed, because the report must remain open on the server until the display process has been completed.
For a ReportClientDocument instance, the Close() method immediately closes the report and the report cannot be reopened. Therefore, if the Close() method is called before the report is displayed, the report will be inaccessible and an exception will be thrown.
The right time to call the Close() method is during the Page_Unload event.
No, I don't know of a way to see usage - I suspect there is one but I've never gone looking for it. I am certain that you are correct that destroying the session object does not dispose the reportdocument object - they are completely different objects. You'll probably have better luck destroying the reportdocumentobject because that I believe is the one hanging on to your threads - the session is just data.
Honestly, what I typically do in my web applications is avoid all of the paging and caching issues completely. My typical approach is to create the report and use the ExportToStream function to stream the results to the browser in PDF format. My user base is comfortable navigating within a PDF, the Acrobat Reader has better search functionality than the Crystal viewer, and there are no threading or paging problems. I do this routinely on all but the simplest reports.
Honestly, what I typically do in my web applications is avoid all of the paging and caching issues completely. My typical approach is to create the report and use the ExportToStream function to stream the results to the browser in PDF format. My user base is comfortable navigating within a PDF, the Acrobat Reader has better search functionality than the Crystal viewer, and there are no threading or paging problems. I do this routinely on all but the simplest reports.
ASKER
Yeah, I'm getting tired of fighting this battle.
Truly, I would like to be able to offer the user dashboard style reports for home pages with drill down and other functions, which is in all of the flash crystal adverts. I also have a paid incident into BO right now. It just bothers me that they tout interactive web reporting, and IMO, it just doesn't work.
Truly, I would like to be able to offer the user dashboard style reports for home pages with drill down and other functions, which is in all of the flash crystal adverts. I also have a paid incident into BO right now. It just bothers me that they tout interactive web reporting, and IMO, it just doesn't work.
I've heard the same comments many times in this forum and I share those feelings...
ASKER
I'm going to try session_end. I was thinking of using a ht of session keys, and looping through each, directcasting it to reportdocument and disposing. Wish me luck!
ASKER
Looking good... testing found it running for all sessions, cast back to reportdocument worked :) Doing a load test now.
Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
' Fires when the session ends
'kill off any reporting objects
Dim ht As Hashtable
Dim rdc As ReportDocument
ht = Session("sessRpt")
If Not ht Is Nothing Then
For Each sKey As String In ht.Keys
If Not Session(sKey) Is Nothing Then
rdc = CType(Session(sKey), ReportDocument)
rdc.Close()
rdc.dispose()
End If
Next
End If
End Sub
Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
' Fires when the session ends
'kill off any reporting objects
Dim ht As Hashtable
Dim rdc As ReportDocument
ht = Session("sessRpt")
If Not ht Is Nothing Then
For Each sKey As String In ht.Keys
If Not Session(sKey) Is Nothing Then
rdc = CType(Session(sKey), ReportDocument)
rdc.Close()
rdc.dispose()
End If
Next
End If
End Sub
ASKER
Cool!!! it works!
I drop the report into session as standard with crystal, but also maintain a HT of sesskeys to unpack later. I'm certain this can be improved on, but it works for me. It's a shame that a paid call to CRW couldn't net a solution.
Private Sub ConfigureCrystalReports()
Dim sk As String = Request.QueryString("SK")
If (Session(sk) Is Nothing) Then
rdoc = New ReportDocument
setupReport()
Session(sk) = rdoc
Dim HT As New Hashtable
If Not Session("sessRpt") Is Nothing Then
HT = CType(Session("sessRpt"), Hashtable)
End If
HT.Add(sk, System.DBNull.Value)
Session("sessRpt") = HT
Else
rdoc = CType(Session(sk), ReportDocument)
End If
crv.ReportSource = rdoc
End Sub
I have no dispose in my form_unload. I set the number of printjobs down to 1 and ran reports using a bot until it gave me the error. I waited a moment, and watched in debug mode as it unpacked and disposed all of the hanging reportdocuments.
Thanks frodoman for giving me some food for thought.
I drop the report into session as standard with crystal, but also maintain a HT of sesskeys to unpack later. I'm certain this can be improved on, but it works for me. It's a shame that a paid call to CRW couldn't net a solution.
Private Sub ConfigureCrystalReports()
Dim sk As String = Request.QueryString("SK")
If (Session(sk) Is Nothing) Then
rdoc = New ReportDocument
setupReport()
Session(sk) = rdoc
Dim HT As New Hashtable
If Not Session("sessRpt") Is Nothing Then
HT = CType(Session("sessRpt"), Hashtable)
End If
HT.Add(sk, System.DBNull.Value)
Session("sessRpt") = HT
Else
rdoc = CType(Session(sk), ReportDocument)
End If
crv.ReportSource = rdoc
End Sub
I have no dispose in my form_unload. I set the number of printjobs down to 1 and ran reports using a bot until it gave me the error. I waited a moment, and watched in debug mode as it unpacked and disposed all of the hanging reportdocuments.
Thanks frodoman for giving me some food for thought.
Sure thing - glad you've got it working!
frodoman
frodoman
ASKER
I am hitting the max 75 connections only because I am not disposing at all to keep the viewer live. I guess the problem is that I believe that simply destroying the session object is not releasing the usage of the reportdocument. Therefore as the sessions die, there is a handle to a reportdocument still live that is not being collected.
My solution launches reports in popup windows which retain autonomy to page/rerun, etc. I guess with your suggestion I would build in a JS onclose that could launch another page whose sole purpose was to unpack session, release the reportdocument, and kill the sessvar.
Do you know of a way to see usage? This would certainly help test your theory. There used to be a way to do it with CRW10. Thank you!