views:

342

answers:

3

I need to be notified any time a largeish asp.net mvc web application makes an ajax call to the server. We're using both jquery, and the built-in Ajax.* methods to do the remote calls, and I would like a global way of knowing when we make a call without having to manually inject some sort of "IsMakingCall" method to every request.

The root problem we're trying to solve is session timeout. If the user leaves a page up and goes to lunch (for example), they get errors when they get back because the ajax call is returning the login page instead of the expected json or partial html result.

My idea was to have a js timer which would be reset any time we make an ajax call. That way, if the timer runs out (ie. their session has now timed out) I can just auto-log them out. This is how sites like bank of america and mint.com work.

Thanks!

A: 

I guess you should create default handler functions for success or begin in the jQuery Ajax framework, depending on when you want the notification to be sent...

Ropstah
+2  A: 

I handle the problem you describe in a different fashion, client-side. I have a jQuery plugin on my master page that will prompt the user to renew their session via a dialog just before it is set to expire. If the user doesn't respond (or clicks logout), it calls the logout action on the application. If the user "renews" their session, it makes an AJAX call back to the server, resetting the sliding window server-side.

You can find code on my blog, http://farm-fresh-code.blogspot.com. Right now it doesn't take account of AJAX actions that may renew the session, but you could instrument it so that jQuery AJAX, via a global ajaxStart would reset the timer. It uses ajaxStart to reset the timer when a jQuery AJAX request is made. I don't use MS AJAX much so I'm not sure if there's a global hook you can use. It doesn't appear so from inspecting the code, but you could manually add one via AjaxOptions to each request. You might investigate adding a handler to the Sys.Net.WebRequestManager, too.

tvanfosson
ajaxStart sounds perfect for the jquery entries. Now if only there is something like that for the ms ajax stuff
Joel Martinez
Your second clue worked out as well: Sys.Net.WebRequestManager.add_invokingRequest( function() { // do stuff in here on every ajax call} );http://msdn.microsoft.com/en-us/library/bb397421.aspx
Joel Martinez
+3  A: 

Basically, the problem here is the default behavior returns back a login page. The result of that is a 200 OK, which to jQuery is a successful call. Correct this handling for ajax calls from MVC and you should be good.

I think the most straight-forward way to handle this is to change the way the Authorize works for ajax scenarios. You can tell if a request is Ajax at that point, and return a similar status code that ASP.NET doesn't invoke the login redirect for(403). Then jQuery will interpret as a failure and fall into that code on the client script.

You can then easily have a shared function in a common js file to handle a friendly way to tell the user they have expired their session.

Something like this might do it

public class AjaxAuthorize : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.RequestContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new ContentResult();
            filterContext.HttpContext.Response.StatusCode = 403; // 401 would make ASP.NET return the login page and a 200 OK status
        }
        else
            base.HandleUnauthorizedRequest(filterContext);
    }
}
Jab
Yeah, if we had realized this when we started development, this would have been the ideal solution.
Joel Martinez