Ext JS with ASP.NET MVC: Session Timeout Notifications

In this article I will explain one approach you can take when you need to handle session timeouts in your ExtJS + ASP.NET MVC applications. The goal of this approach is simply to alert the user when her server session has timed out.

These are the basic steps you will follow when implementing this approach:

  1. Before an AJAX request is handled on the server side, determine if the session timed out. If the session timed out, respond with a “session timed out” code. If it didn’t, proceed to handle the AJAX request.
  2. Intercept the AJAX responses on the client side. When the “session timed out” code is detected, inform the user.

Intercepting ExtJS AJAX requests on the server

Suppose you have a FeesBilled and AccountsReceivable ExtJS data stores like so:

App.DetailsStore = function (config) {
    var config = config || {};
    Ext.applyIf(config, {
        fields: ['Id', 'Name', 'Amount'],
        root: 'records',
        totalProperty: 'total',
        remoteSort: true,
        sortInfo: {field:'name',direction:'asc'}
    });
    App.DetailsStore.superclass.constructor.call(this, config);
};
Ext.extend(App.DetailsStore, Ext.data.JsonStore);

var feesBilledStore = new FeesStore ({
    url: 'accounting/feesbilled
});
var accountsReceivableStore = new FeesStore ({
    url: 'accounting/accountsreceivable
});

Requests sent from these stores will be handled by the following ASP.NET MVC action methods:

public ActionResult FeesBilled(int start = 0, int limit = 0, string sort = "name", string dir = "asc")
{
    EmployeeModel empl = Session["empl"] as EmployeeModel;
    return DL.GetFeesBilled(start, limit, sort, dir, empl);
}

public ActionResult AccountsReceivable(int start = 0, int limit = 0, string sort = "name", string dir = "asc")
{
    EmployeeModel empl = Session["empl"] as EmployeeModel;
    return DL.GetAccountsReceivable(start, limit, sort, dir, empl);
}

As you can see, these action methods need an EmployeeModel instance that is stored in a session variable. And you need to guarantee that the session exists and is valid before passing the EmployeeModel instance to the data access layer of the system.

 

Then, how do you determine if the user’s session has timed out before these requests are processed?

You can accomplish this in ASP.NET MVC with a custom action filter. Action filters are custom attributes that allow you to perform logic either before an action method is called, or after an action method runs.

This is an action filter you can use to check for session timeouts:

public class AjaxSessionExpiredFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpContext context = HttpContext.Current;
        // Check if session is supported.
        if (context.Session != null)
        {
            if (context.Session.IsNewSession)
            {
                // If this is a new session and an old session cookie exists, then old session timed out.
                string sessionCookie = context.Request.Headers["Cookie"];
                if ((null != sessionCookie) && (sessionCookie.IndexOf("ASP.NET_SessionId") > -1))
                {
                    context.Response.Write("error=sessiontimeout");
                    context.Response.End();
                }
            }
        }

        base.OnActionExecuting(filterContext);
    }
}

Notice that you need to override the filter’s OnActionExecuting method. This method is fired before the action method executes.

 

Armed with this custom action filter, you can simply decorate the controller methods like so:

[AjaxSessionExpiredFilter]
public ActionResult FeesBilled(int start = 0,
            int limit = 0, string sort = "name", string dir = "asc")
{
    EmployeeModel empl = Session["empl"] as EmployeeModel;

    return DL.GetFeesBilled(start, limit, sort, dir, empl);
}

[AjaxSessionExpiredFilter]
public ActionResult AccountsReceivable(int start = 0,
            int limit = 0, string sort = "name", string dir = "asc")
{
    EmployeeModel empl = Session["empl"] as EmployeeModel;

    return DL.GetAccountsReceivable(start, limit, sort, dir, empl);
}

After decorating the methods with the custom action filter, every time the methods are called and the session has timed out, the response generated will be “error:sessiontimeout”.

 

Your ExtJS application needs to catch and handle this response. Let’s see how it’s done.

Handling session timeout in ExtJS

In your ExtJS application, you can check for the session timeout code utilizing a handler function for the requestcomplete event of the Ext.Ajax class. As Ext.Ajax is a singleton, your requestcomplete handler will run for any AJAX requests that completed successfully.

A simplified version of the handler could look like this:

Ext.Ajax.on('requestcomplete', function (conn, response, options) {
    if (response.responseText.indexOf("error=sessiontimeout") > -1) {
        Ext.Msg.alert('Session Timeout', 'Your session has timed out. Please refresh this page to start a new session.');
    }
});

And that’s all it takes. Want to give it a try?

About Jorge

Jorge is the author of Building a Sencha Touch Application, How to Build a jQuery Mobile Application, and the Ext JS 3.0 Cookbook. He runs a software development and developer education shop that focuses on mobile, web and desktop technologies.
If you'd like to work with Jorge, contact him at ramonj[AT]miamicoder.com.

Comments

  1. Hi Jorge,

    I am not able to figure out how to set a timeout for jsonp request so that if the server is down then it should return some sort of alert. This is the code I have however the failure does not work in the ext.util.jsonp request

    Ext.util.JSONP.request({
    url: “http://”+serverAdd+”:”+ port+”/users/searchresults.json”,
    format: ‘json’,
    callbackKey: ‘callback’,
    params : searchCriteria,
    callback: function(data) {

    store.getProxy().clear();
    store.data.clear();
    store.sync();
    if(data.length < 10){
    store.add({title: 'No Results found.'},
    {company: 'Please try again !!'},
    {posting_date: new Date()});
    }
    else{store.add(data);}
    },
    failure: function ( result) {
    alert('Failed');
    console.log( 'Server not connected, please try again .. ');
    }
    });

Speak Your Mind

*