Getting System.OutOfMemoryException when using ReportViewer contol in Local mode


PROBLEM:

========

  1.  Consider you've a ASP.NET application that contains Report Viewer control (2005 / 2008) in Local Mode.
  2.  You have an RDLC report file, that loads large amount of data / has lots of expressions. (Both are not recommended in Local mode)
  3.  Everytime you refresh the web page, the Report Viewer stores objects in the session.
  4.  The behaviour of Report Viewer storing objects in the session is by design.
  5.  Each time the report viewer page is refreshed the complete report info object is added to session.
  6.  These objects obviously gets deeply rooted in session and so Garbage collector never collects them untill the complete app unloads itself.
  7.  And that is apparently going to increase the memory pressure in multiple folds, ending up with System.OutOfMemoryException.

WORKAROUND: (Please note: This doesn't guarantee to resolve the exception. The Out of Memory exception can be caused due to different reasons and the below workaround is for one such scenario, which can help to avoid this error to a certain extent. You should avoid using it at any given point of time and try to switch to the ExecuteReportInSandboxAppDomain mode)

===========

== In the page_load event, add this,

== VB.NET

If Session.Count > 0 Then

For i As Integer = 0 To Session.Count - 1

If Session(i).GetType().ToString() = "Microsoft.Reporting.WebForms.ReportHierarchy" Then

Session.RemoveAt(i)

End If

Next

End If

== C#,

if(Session.Count > 0)

{

for (int i = 0; i < Session.Count; i++)

{

if (Session[i].GetType().ToString() == "Microsoft.Reporting.WebForms.ReportHierarchy")

{

Session.RemoveAt(i);

}

}

}

Comments (6)

  1. jeff says:

    it made absolutely no difference. It dies even on a single report if your recordset is substantially large. The problems are much deeper-rooted than the session.

  2. Selvar says:

    The above scenario is one such and Out of memory can pop up due to different reasons. Client side reports are specifically made for lighter execution. If your report is going to have a huge amount of dataset or having too much of complex expression then, RDLC is not a recommended one. Server side reports can take much additional loads and Reporting Service 2008 has a new, optimized processing engine which is highly efficient.

    More details:

    http://blogs.msdn.com/brianhartman/archive/2008/12/05/sql-server-2008-and-the-reportviewer-controls.aspx

  3. @chio says:

    It works for me. Thanks for sharing out this useful info. 🙂

  4. Eman Lee says:

    The following works:

    If Session.Count > 0 Then

               For i As Integer = 0 To Session.Count – 1

                   If i < Session.Count AndAlso Not Session(i) Is Nothing AndAlso Session(i).GetType().ToString() = "Microsoft.Reporting.WebForms.ReportHierarchy" Then

                       Session.RemoveAt(i)

                   End If

               Next

           End If

  5. AlyKhemani says:

    Slevar,

    Thx for the code. We have been using this in our custom host ASP.NET application that leverages the local report viewer control. But this code really does not account for multiple report viewer request from multiple frames but the same session.

    For example, the host application can have x number of frames open and each one have a report control viewer, but under the same session. (Our scenario). What we are finding is that Report viewer 1 will open and kill its session, then the user will hit the 2nd report and the 2nd report will kill its session. then if the user goes back to the 1st report (changes param) or reruns again. we get the dreaded ASP.NET Session has expired  error. If we let the sessions grow (don't execute the removeat statement) we see how the sessions grow internally but because report B is not killing report A's session we don't get any error.

    We have been struggling to find a way to ONLY delete the session index of the report that is calling, but with no success. I see internally MS uses report_id and control_id, m_instanceIdentifier to keep track of the particular report but all of these seem like private properties.

    Is there a way we can only delete the particular report request from the session and not everything that is of type reporthierarchy?

    Thx in advance

  6. Seshu Adunuthula says:

    One option to try is to move the session state out of the process by using AppFabric Cache.

    msdn.microsoft.com/…/ee695849.aspx

    The link here gives you details for setting up the cache.

    http://www.hanselman.com/…/InstallingConfiguringAndUsingWindowsServerAppFabricAndTheVelocityMemoryCacheIn10Minutes.aspx

    Even if the cached session state is not being exprired for some reason, you have abilities in AppFabric to script explict  deleting of old session state.  

Skip to main content