How to handle report viewer session expired exception
I have the following situation:
Microsoft Report Viewer 2010 is used to display reports (.rdlc files) in local mode in an ASP.NET web application. The report data is supplied by assigning a datasource in the code behind of an ASPX page. Here's an example:
if(!IsPostBack){
ReportViewer1.Reset();
ReportDataSource reportDataSource = new ReportDataSource();
reportDataSource.Name = "DataContainerType";
reportDataSource.Value = DatasourceOnPage;
reportDataSource.DataSourceId = "DatasourceOnPageID";
reportDataSource.DataMember = "DataSourceView";
ReportViewer1.ProcessingMode = ProcessingMode.Local;
ReportViewer1.LocalReport.DisplayName = "ReportName";
ReportViewer1.LocalReport.ReportEmbeddedResource = "Reportfile.rdlc";
ReportViewer1.LocalReport.DataSources.Add(reportDataSource);
}
Normally this works great, every report we have loads just fine.
When I leave the page open until the worker process recycles, then try to refresh the report or do any kind of postback on the report page, I get an (unhandled) exception "ASP.NET Session has expired".
Exception information: Exception type: AspNetSessionExpiredException Exception message: Die ASP.NET-Sitzung ist abgelaufen oder konnte nicht gefunden >werden. at Microsoft.Reporting.WebForms.ViewerDataOperation..ctor() at Microsoft.Reporting.WebForms.HttpHandler.GetHandler(String operationType) at Microsoft.Reporting.WebForms.HttpHandler.ProcessRequest(HttpContext context) at >System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionS>tep.Execute() at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& >completedSynchronously)
IIS is set to recycle every morning at 5 a.m. We use the InProc setting in the web.config, so obviously, the session is lost. If I understand the ASP.NET behaviour correctly, the unhandled exception should cause the worker process to terminate. There should be a new worker process when the next request arrives.
If the session timeout setting is low, it causes the same exception. This seems odd, because from what I read, the Report Viewer should ping the server to keep the session alive.
I tried to catch the exception, but it is thrown somewhere inside the ReportViewer control, before I get to access it in page load. The code above is still executed if I take out the IsPostBack, but it has no effect.
I tried using state server开发者_运维技巧 instead of keeping the session in the process, so it would not lose it's session, but this leads to other errors from the report viewer. It seemed to be unable to store it's session data in the state server.
The environment is Windows Server 2003 .NET 4.0 Report Viewer 2010
Where can I either handle the error, without having the worker process terminate, or get the report to use stateserver?
I now solved it, by using a custom page derived from the base page class. I now check if the session is new, then redirect to the same page, thereby reloading the report from scratch.
I also used a script to keep the session alive, since the report viewer is not doing this by itself. But since I'm satisfied with the session check, I disabled it.
public class ReportPage: System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
#region check for lost session
if (Context.Session != null)
{
if (Session.IsNewSession)
{
string cookieHeader = Request.Headers["Cookie"];
if ((null != cookieHeader) && (cookieHeader.IndexOf("ASP.NET_SessionId") >= 0))
{
Response.Redirect(Request.Url.ToString());
}
}
}
#endregion check for lost session
#region generate keepsessionalive script
StringBuilder sb = new StringBuilder();
sb.Append("$(function () {setInterval(KeepSessionAlive, " + GetSessionTimeoutInMs() + ");");
sb.Append("});");
sb.Append("function KeepSessionAlive() {");
sb.Append(string.Format("$.post('{0}', null);", ResolveUrl("~/KeepSessionAlive.ashx")));
sb.Append("};");
// register on page
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "SessionKeepAlive", sb.ToString(), true);
#endregion generate keepsessionalive script
}
private int GetSessionTimeoutInMs()
{
return (this.Session.Timeout * 60000) - 10000;
}
}
The keep-alive-script calls an http handler (.ashx file) that touches the session every time it's called (not sure actually if this is necessary). Here it is for the record:
public class KeepSessionAlive : IHttpHandler, IRequiresSessionState
{
public void ProcessRequest(HttpContext context)
{
context.Session["KeepSessionAlive"] = "KeepAlive!";
}
public bool IsReusable
{
get
{
return false;
}
}
}
Have you tried limiting the number of worker processes to 1?
I was having the same issue, and what fixed it for me was A) setting a specfic time of day for recycle
(which you already have) and B) limit worker processes to max of 1 in app pool settings
.
精彩评论