11

I know this is duplicate but I could not get reliable solution(for asp.net web).

I just want to redirect to the login page if session expires. I have tried following:

1. using jquery status code

    $.ajax({
     type: "POST",
     url: "stream.asmx/SomeMethod",
     contentType: "application/json; charset=utf-8",
     dataType: "json",
     success: function (msg) {
        //success msg
     },
     error: function (request, status, error) {
        if (status = 403) {
            location.href = 'login.aspx';
        }
     }
    });

Problem: this returns same status code(403) for other errors too, which I only expect for session timeout.

2. Sending json message whether session expired

code behind:

    if (!object.Equals(HttpContext.Current.Session["User"], null))
    {
        Id = int.Parse(HttpContext.Current.Session["User"].ToString());
    }
    else
    {
        result = from row in dtscrab.AsEnumerable()
                 select new
                 {
                     redirectUrl = "login.aspx",
                     isRedirect = true
                 };
    }

on $.ajax success:

    success: function (msg) {
        if (msg.d[0].isRedirect) {
            window.location.href = msg.d[0].redirectUrl;
        }
        else {
            //load containt
        }
     }

Problem: It's somehow desn't invoke ajax success line if session expires(it does return correct json). And even this is not a proper way if I have many number of ajax request in the page(should be handled globally).

However, I saw this post which is really good soltion but it's for mvc using AuthorizeAttribute: handling-session-timeout-in-ajax-calls

So, Is there I can use same concept used in mvc using AuthorizeAttribute in asp.net web api? If not, how I can troubleshoot those issue which I'm facing (any of above two mentioned)?

Community
  • 1
  • 1
Ashwini Verma
  • 7,477
  • 6
  • 36
  • 56
  • 1
    `if (status = 403)` is missing at least one '=' to be a test. That's why you believed status was always 403 ! ^^ – Laurent.B Aug 28 '14 at 10:48
  • Similar question here - https://stackoverflow.com/questions/1653493/what-http-status-code-is-supposed-to-be-used-to-tell-the-client-the-session-has . – Victor Yarema Dec 05 '17 at 10:13

6 Answers6

3

A 403 status code is going to cause jQuery to call the failure method. Keep the same code behind from your second try, but move the redirect handler to the failure method instead of the success method. In the success method, treat it as you normally would.

Alex Schultz
  • 210
  • 1
  • 9
3

Problem:

I had same problem in my Razor MVC Application throwing exceptions while ajax calls made when session timed out.

The way I have managed to get this issue sorted is by monitoring each ajax requests by using a simple light weight Action Method (RAZOR MVC) returning a bool variable whether the Request is Authenticated or not. Please find the code below..

Layout/Master Page / Script file:

<script>
var AuthenticationUrl = '/Home/GetRequestAuthentication';
var RedirectUrl = '/Account/Logon';

function SetAuthenticationURL(url) {
AuthenticationUrl = url;
}

function RedirectToLoginPage() {
window.location = RedirectUrl; 
}

 $(document).ajaxStart(function () {
 $.ajax({
    url: AuthenticationUrl,
    type: "GET",
    success: function (result) {
        if (result == false) {
            alert("Your Session has expired.Please wait while redirecting you to login page.");
            setTimeout('RedirectToLoginPage()', 1000);
        }
    },
    error: function (data) { debugger; }
});

})

Then in Home Controller/Server side you need a method to verify the request and return the boolean variable..

    public ActionResult GetAuthentication ( )
    {
        return Json(Request.IsAuthenticated, JsonRequestBehavior.AllowGet);
    }

This will validate each ajax request and if the session got expired for any ajax request, it will alert the user with a message and redirect the user to the login page.

I would also suggest not to use standard Alert to Alert. User some Tool tip kind of formatted div Alerts. Standard JS Alerts might force the user to click OK before redirection.

Hope it helps.. :)

Thanks, Riyaz

Riyaz Hameed
  • 1,087
  • 12
  • 10
3

Finally, I ended up following.

public class IsAuthorizedAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                var sessions = filterContext.HttpContext.Session;
                if (sessions["User"] != null)
                {
                    return;
                }
                else
                {
                    filterContext.Result = new JsonResult
                    {
                        Data = new
                        {
                            status = "401"
                        },
                        JsonRequestBehavior = JsonRequestBehavior.AllowGet
                    };

                    //xhr status code 401 to redirect
                    filterContext.HttpContext.Response.StatusCode = 401;

                    return;
                }
            }

            var session = filterContext.HttpContext.Session;
            if (session["User"] != null)
                return;

            //Redirect to login page.
            var redirectTarget = new RouteValueDictionary { { "action", "LogOn" }, { "controller", "Account" } };
            filterContext.Result = new RedirectToRouteResult(redirectTarget);
        }
    }

Handling client side

<script type="text/javascript">
    $(document).ajaxComplete(
       function (event, xhr, settings) {
           if (xhr.status == 401) {
               window.location.href = "/Account/LogOn";
           }
    });
</script>
Ashwini Verma
  • 7,477
  • 6
  • 36
  • 56
1

you can set session time out expire warning some thing like ....

<script type="text/javascript"> 

//get a hold of the timers
var iddleTimeoutWarning = null;
var iddleTimeout = null;

//this function will automatically be called by ASP.NET AJAX when page is loaded and partial postbacks complete
function pageLoad() { 

    //clear out any old timers from previous postbacks
    if (iddleTimeoutWarning != null)
        clearTimeout(iddleTimeoutWarning);
    if (iddleTimeout != null)
        clearTimeout(iddleTimeout);
    //read time from web.config
    var millisecTimeOutWarning = <%= int.Parse(System.Configuration.ConfigurationManager.AppSettings["SessionTimeoutWarning"]) * 60 * 1000 %>;
    var millisecTimeOut = <%= int.Parse(System.Configuration.ConfigurationManager.AppSettings["SessionTimeout"]) * 60 * 1000 %>; 

    //set a timeout to display warning if user has been inactive
    iddleTimeoutWarning = setTimeout("DisplayIddleWarning()", millisecTimeOutWarning);
    iddleTimeout = setTimeout("TimeoutPage()", millisecTimeOut);
} 

function DisplayIddleWarning() {
    alert("Your session is about to expire due to inactivity.");
} 

function TimeoutPage() {
    //refresh page for this sample, we could redirect to another page that has code to clear out session variables
    location.reload();
} 

Manibhadra
  • 400
  • 4
  • 6
  • thanks Manibhadra for quick reply, but I'm looking a reliable way of finding session timeout on client side(on ajax call). – Ashwini Verma Dec 31 '12 at 11:34
0

4xx are HTTP error status codes and would cause jquery to execute the onFailure callback.

Also, beware of using 3xx for redirects when you want to process the payload. Internet Explorer, in my experience, just does a redirect (without looking at the payload) when a 3xx status code is returned.

I'd say, throw a 403 and handle the situation. To the client 403 implies the resource access is forbidden. There can be multiple reasons, which is OK I guess.

Srikanth Venugopalan
  • 9,011
  • 3
  • 36
  • 76
0

For those using a ScriptManager, you can easily check for ajax request and then redirect with the following code:

private void AjaxRedirect(string url)
    {
        Response.StatusCode = 200;
        Response.RedirectLocation = url;
        Response.Write("<html></html>");
        Response.End();
    }

Then check for request type and redirect accordingly (using routes here):

if (ScriptManager.GetCurrent(Page).IsInAsyncPostBack)
{
    var redirectUrl = RouteTable.Routes.GetVirtualPath(null, "Default", null).VirtualPath;                            
    AjaxRedirect(redirectUrl);
}
else
{
    Response.RedirectToRoute("Default");
}   

The "Default" route is a route defined in the routes collection:

routes.MapPageRouteWithName("Default", "", "~/default.aspx");

If you prefer, instead of using ScriptManager for ajax request check, you can use:

if (Request.Headers["X-Requested-With"] == "XMLHttpRequest") { 
   code here...
}
Hugo A.
  • 218
  • 2
  • 12