Handling ASP .NET session expired message in SharePoint 2010 through javascript

There are situations when one needs to handle session expiring in SharePoint solution. This error can occur either because of Session time out after some time as specified in Web.Config, or due to some external control that is being used in the SharePoint site.

An example is using SQL Server 2008 Reporting Services report viewer web part to display SSRS reports. The default timeout of report server is 10 minutes. So if you try to view the report second time after being idle for 10 minutes, it will return you a message “ASP.NET session has expired or could not be found”. This is a more ‘Technical’ message that business users might find unusual.

In order to handle this we might want to either: Give a more specific message and tell user to refresh the page, or redirect to a login or error page. That can be customized as per your requirement; I will just show an
error message with a button to refresh the page.

To handle this situation I will be using JavaScript and apply it to master page so that it will be applicable to all the pages in the application.

Step 1: Open your master page in SharePoint designer and start editing.

Step 2: Add the div that will appear as popup. You can add it anywhere in the page, I will add it just before the div containing <SharePoint:SPRibbon>

<div id="SessionTimeMessageDiv" style="height:0px; display:none;">
     <div id="SessionTimeOutDiv" style=" position:relative; display:none; top: 0px; height: 100%;
         background-color: White; opacity: 0.75; filter: alpha(opacity=75); vertical-align: middle;
         left: 0px; z-index: 99998; width: 100%; position: absolute;  text-align:center;"></div>             
 
     <div style="width:400px; text-align:center; position:relative;  filter: alpha(opacity=100);
          vertical-align:middle; top:200px; left:40%; height:80px; border:thin lightBlue solid;
          background-color:white; z-index:99999;">
       <br/>
       <asp:Label ID="lblSessionTimeOut" runat="server" 
                  Text="You session has expired, please press Refresh button or refresh the page">
       </asp:Label>
       <br /><br />
       <asp:Button ID="Button1" runat="server" Text="Refresh" OnClientClick="refreshPage();"/>
    </div>
</div>

I have added 3 <div>s to have the effect of grayed out disabled page and Refresh message on top of that. Please note that on click of Refresh button, I am calling another JavaScript function to refresh the page.

 

Step 3: Add JavaScript functions to the master page

       //Global variable to hold the timeout time
       var sessionTimeout;
 
      // Reset the timeout to a static value. Will get this from web config later
       function resetTimer()
       {
         sessionTimeout=5;
       }
 
      // function to refresh the page
      function refreshPage()
      {         
        location.reload(true);
      }
 
      // Counter function. It is a recursive function that will keep calling itself each minute, you can reduce the time to few seconds for debugging
 
      function countTimeout()
      {
        sessionTimeout = sessionTimeout - 1;
        if(sessionTimeout >= 0)
        {
           //call the function again after 1 minute delay        
             
          window.setTimeout("countTimeout()", 60000);
        }
        else
        {
          //show message box
           document.getElementById("SessionTimeOutDiv").style.display = "block";                
           document.getElementById("SessionTimeMessageDiv").style.display = "block";            
        }
      }

 

Now we need to initialize the timer on page load and reset it whenever user is doing some activity on the page. We will reset the timer each time user clicks anywhere or presses some key. For this we need to call javascript on body load.

 Step 4: Handle Body onload event: 

Usually body load event of master page is already handled in SharePoint master page, so now we need to call multiple functions on body load. There is a crack for this. Taking example of NightAndDay.master:

<body scroll="no" onload="if(typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();" class="nightandday">

Change this to: 

<body scroll="no" onload=”BodyLoad();"class="nightandday">

Move old code to bodyLoad() function.

function bodyLoad()
{
     if (typeof(_spBodyOnLoadWrapper)!= 'undefined') _spBodyOnLoadWrapper();

Now we can call our timer from this function. So the final function should look like:

function bodyLoad()
{
    if (typeof(_spBodyOnLoadWrapper)!= 'undefined') _spBodyOnLoadWrapper();
    resetTimer();
    countTimeout();

Reset the timer when a user clicks on the screen or press any key. For this, add 2 more events on <body>: onclick="resetTimer()" and onkeypress="resetTimer()" 

Step 5: Read the session timeout: 

Now everything is ready except that the timeout is hardcoded. We will get it from Session.Timeout property. session timeout property can be fetched from following web.config entry:

<sessionState mode="InProc" timeout="10" />

Try reading sessionTimeout using code block in master page as: <%=Session.Timeout%>. This will throw an exception saying: “Code blocks are not allowed in this file” .

So I will write a custom control, add it to the master page and read the value in javascript.

Note: There can be other ways to read this value but I have not explored them. 

Add user control:

Create a new SharePoint solution in visual studio.

  • Add SharePoint mapped “ControlTemplates” folder.
  • Add a new User control – SessionTimeOut.ascx.
  • Add following code to the ascx file:
    <div id ="timeout"><%=Session.Timeout%></div>
  • Deploy the solution. 

Include the user control in master page: 

Register the TagPrefix. Add following line before <html> tag:

<%@ Register TagPrefix="useruc" TagName="SessionTimeOut" src="~/_CONTROLTEMPLATES/Sharepoint.UI.Webparts/SessionTimeOut.ascx"%>

Add following <div> in the master page body:

      <div style="display:none;" id="SessionDetails">
           <useruc: SessionTimeOut id="Idsession" runat="server" EnableViewState="false"> </useruc:AdminUser>       
      </div> 

Now we will have the session timeout available on the master page inside a hidden div named "timeout". This is what we added in the user control and can be read as:

document.getElementById("timeout").innerText;  

 

Now we have everything in place. The final JavaScript will look like: 

<script type="text/javascript">    var sessionTimeout;     function bodyLoad()   {      if(typeof(_spBodyOnLoadWrapper) != 'undefined') _spBodyOnLoadWrapper();      resetTimer();      countTimeout();   }    function resetTimer()  {   //Read timeout from custom control    sessionTimeout=document.getElementById("timeout").innerText;   }    function refreshPage()    {        location.reload(true);  }    function countTimeout()  {    sessionTimeout = sessionTimeout - 1;     if(sessionTimeout >= 0)     {        //call the function again after 1 minute delay                       window.setTimeout("countTimeout()", 60000);     }     else     {       //show message box        document.getElementById("SessionTimeOutDiv").style.display = "block";        document.getElementById("SessionTimeMessageDiv").style.display = "block";                  } } </script> 

 

  

The <body> tag of master page should look like:

<body scroll="no"  onload="bodyLoad()" onclick="resetTimer()"  onkeypress="resetTimer()" class="nightandday">

 

And the code to add in the <body> of master page: 

    <div style="display:none;" id="SessionDetails">        <useruc: SessionTimeOut id="Idsession" runat="server" EnableViewState="false">        </useruc:AdminUser>          </div>     <div id="SessionTimeMessageDiv" style="height:0px; display:none;">       <div id="SessionTimeOutDiv" style=" position:relative;display:none; top: 0px; height: 100%;background-color: White; opacity: 0.75;             filter: alpha(opacity=75); vertical-align: middle;left: 0px; z-index: 99998; width: 100%; position: absolute;  text-align: center;">      </div>                      <div style="width:400px; text-align:center; position:relative; filter:alpha(opacity=100); vertical-align:middle; top:200px;               left:40%; height:80px; border:thin lightBlue solid; background-color:white; z-index:99999;">          <br/>          <asp:Label ID="lblSessionTimeOut" runat="server" Text="You session has expired, please press Refresh button or refresh the page">          </asp:Label>          <br /><br />          <asp:Button ID="Button1" runat="server" Text="Refresh" OnClientClick="refreshPage();" />       </div>   </div>

  

Thats all the coding. For debugging, try reducing the timeout in web.config and reduce the time from 60000 to 15000 in window.setTimeout("countTimeout()", 60000).

Important note: If you are using some external control in your pages that has its own timeout, then we need to make sure that the timeout mentioned in web.config should be less than or equal to that of enternal.

For example, you are using SQL Server Reporting Services ReportViewer to show SSRS reports that are hosted on a report server. Now the default time out of report server is 10 minutes, and if you set timeout in web.config as 30 minutes, then this approach will not work as we are reading from web.config.

In this case, there are 2 options:

  1. Decrease the timeout in web.config to match to report server.
  2. Increase the timeout in report server to have timeout more than or equal to that of web.config.