Handling session timeouts in ajax calls - ajax

ASP.Net MVC 5 .Net Framework 4.6.1
I just added code to detect session timeout which works fine:
public class CheckSessionTimeOutAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Mvc.ActionExecutingContext filterContext)
{
var context = filterContext.HttpContext;
if (context.Session != null)
{
if (context.Session.IsNewSession)
{
string sessionCookie = context.Request.Headers["Cookie"];
if ((sessionCookie != null) && (sessionCookie.IndexOf("ASP.NET_SessionId", StringComparison.Ordinal) >= 0))
{
string redirectTo = "~/Home/Index";
filterContext.HttpContext.Response.Redirect(redirectTo, true);
}
}
}
base.OnActionExecuting(filterContext);
}
}
As you can see, I redirect them to the home screen. I have my [CheckSessionTimeOut] as an attribute on all pertinent controllers. So, I run the app, go to a page other than the home screen, wait 1 minute for session timeout, the code runs as expected in certain situations. Case and point, I have a dropdown and when a selection is made, a redirect is taking place. Heres the method:
$('#selusers').change(function () {
var rd = $(this).find("option:selected").attr('redirect');
location.href = rd;
});
What happens here is when a user is selected from the dropdown, the redirect attribute is read and redirection to that person takes place. If the session times out, redirection to the logged in user takes place and not the newly selected user. This is correct for my app.
However, I make numerous ajax calls in my app. When the session times out and I click on an element that fires an ajax call, I get redirected to the home screen, but the error method gets called in the ajax request. I get a popup with the home screen html inside of it. Here's one example of an ajax call I'm making. I'm on a screen with a save button, the session times out and this code gets fired:
SaveButtonClicked: function (somedata) {
$.ajax({
url: url,
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: "json",
data: JSON.stringify(some data im sending),
success: function (dataResult) {
if (!dataResult.Ok) {
alert("Error occurred. Please try again");
}
},
error: function (err) {
alert(err.responseText);//this gets called
}
});
}
I have overridden the default alert so styled html will appear. The alert box has the home screen html in it. I do not want that. I want the app to be redirected to the home screen, no popup. So my first question, is there a way to do something at the server to stop the ajax call from running its complete methods(i.e I want to do something at the server so the ajax call's success, error, or complete methods will never be called)? Next question if the first one isn't an option, what would be a very good way to detect that the session has timed out in the complete methods of an ajax call so the user is gracefully redirected to the home screen? If there are any other ways of doing what i'm trying to achieve that I didn't not ask, please share them. Thank you for reading my question.
UPDATE
I removed the error function from one of my ajax calls and added a global error handler instead:
$(document).ajaxError(function (e, xhr, settings) {
debugger;
});
Now, when the session timeout, this error handler gets called, BUT, i look in the xhr variable and it contains the results of the ajax call and corresponding html. The status is a 200, the statusText says parsererror, the readystate is a 4. There is nothing here that tells me the session timed out. What can i do at the global ajaxError method to tell me session timed out?

A good starting points might be:
If your ASP.NET MVC project properly returns status code:
$.ajaxSetup({
statusCode: {
401: function() {
window.location.href = "/login/path";
}
}
});
if not you can try:
$(document).ajaxError(function (e, xhr, settings) {
debugger;
});
Review e & xhr properties and make a decision from there.

Related

$.ajax().success not working only in firefox

I have an ajax function like so:
function RunSubmit() {
$.ajax({
url: '#Url.Action("Contact", "Public")',
type: "POST",
data: $('#contactForm').serialize(),
dataType: 'jsonp',
crossDomain: true,
success: function (result) {
alert("hit success function");
if (result.validForm) {
alert("At redirect. Url is: " + result.url);
window.location.assign(result.url);
//console.log("valid form");
} else {
$('#registerForForm').html(result);
//console.log("BAD FORM");
alert("ELSE CALLED");
}
},
error : function(ob1, ob2, ob3)
{
},
complete: function(val)
{
//This is being hit but it appears no value is being returned from the controller (FireFox)
}
});
Strange thing is it works in IE and Chrome but not FF. I have tried running the post with dataType: 'json' without the dataType and without the crossDomain property. Looking at the console on FF I can see that we are having numerous cross domain request errors mainly coming from google fonts. (This does not happen on chrome or ie). In our controller we are making a hardcoded http request to another server on a different host so I can see where the issue might be arising. The way we have dealt with this issue before is by adding a crossdomain.xml file to the root of our project. Something like this
<?xml version="1.0" encoding="utf-8" ?>
<cross-domain-policy>
<allow-access-from domain="*.xyz.com"/>
<allow-access-from domain="*.abc.com"/>
<allow-access-from domain="*.123.net"/>
<allow-access-from domain="http://university.abc.com"/> //this is the site we are sending a request to in our controller
</cross-domain-policy>
So I have searched and come across multiple posts on SO where the success function was not being called on an ajax post. Check my error objects the only information I am getting back is "error". This javascript should be receiving a url back and redirecting; however, what it is doing is rendering the JSON return value to the screen.
This is the line of code that returns our Json from our controller.
return Json(new { validForm = true, url = "/Public/ContactComplete" }, JsonRequestBehavior.AllowGet);
The line looks fine to me and the Json being returned is perfect json so it should not be a parsing error on the jquery side.
This was an interesting situation. I'm adding this to my list of reasons as to why a form may not post back in MVC. The outside firm we hired to develop our product created a 'hack' to get around an issue where Chrome would not post back if you wished to disable the submit button (to prevent double post) on the click of the button itself. To get around this the developer wrote an ajax script submitting the form manually on click. This in turn blew up functionality in firefox. There was some weird double posting going on and for whatever reason FF would render JSON to the screen instead of catching the Json back and running the success function.
Long story short:
If you are disabling a submit button to prevent double post then disable it on the form submit event.
pseudo code
$('#submit-button').on('click', function() { this.attr('disabled', true);}
Is not the way to go. The below is what fixed it for me
$('form').on('submit', function() { $('#submit-button').attr('disabled', true);}

Prevent browser caching of MVC partial pages as full pages (on back/forward)

I have an iphone-style list-view system for navigation of a website that looks like this:
The URL is changed dynamically when a panel is loaded via AJAX and the same URL is placed in the browser address bar with puststate. This a allows a page refresh to reload the current page:
this.Historyjs.pushState({}, "", url);
To make this work the pages can return themselves as either a partial page, or a full page. The code to detect the difference is a base controller and looks like:
public bool IsPartialPage
{
get
{
// ListViewer will strip out HTML from a full page if this occurs
return Request.IsAjaxRequest() || !string.IsNullOrEmpty(Request["partial"]);
}
}
An example controller action looks like this (note the Partial View cache expiry):
[OutputCache(Duration=1)]
public ActionResult ListViewerDocumentation()
{
if (!base.IsPartialPage)
{
ViewBag.Layout = "~/Views/Shared/_ListViewLayout.cshtml";
}
return PartialView();
}
The problem I have is that when you navigate using the Browser's back and forward buttons, it will occasionally decide that a previously partial page is sufficient to become the entire page and does not make a call to the server (checked with Fiddler2) and so looks like this:
Any suggestions on a method that will ensure back and forward navigation always pull back a full page and not from its cache of Ajax requests? Is it simply a matter of making the Ajax calls unique, or will the vanilla URL from the back/forward still match?
Turns out the trick is to turn off caching on the Ajax request that pulls the partial pages, not on the server as that is never hit (the light suddenly came on after writing the above question):
$.ajax(
{
cache: false, // << Added this
url: url,
type: "GET",
error: function (jqXHR, textStatus: string, errorThrown: string)
{
// On error (eg. "not found") empty out the display
THIS._removeContent();
},
success: function (data: string, textStatus: string, jqXHR)
{
var $data = $(data);
THIS._insertContent($data, function ()
{
});
}
});
The cache false also apparently ensures the browser will not reuse the page on page back/forward operations.

ajax form submission - skip url processing and go directly to success function?

Haven't come across this before with ajax. On click of a button I am posting a form with ajax. In the successful return function I am opening up a modal window in bootstrap 3 with a single parameter attached from the previous form submission.
I am using the modal as a confirmation window to confirm a user deletion. I am using ajax again then in the modal to do the actual deletion of the user in the db and returning success or fail.
Since all the operations are being processed in the actual modal's ajax (confirm the username exists then perform the delete operations)... is there a way I can skip the initial form processing? In this example p_delete_user.php' really does absolutely nothing other than allow me to return and attach the username parameter to the modal I open.
Can I skip this step somehow and go straight to my success calls with the attached parameter value. I have no need to check if the param is valid or not in this step as the validation occurs in the ajax of the modal that is opened.
my ajax:
// delete user account
var deleteAccount = function() {
$('#delete-user').on('click', function () {
var $form = $(this).closest('form');
$.ajax({
type: 'post',
url: '/spc_admin/process/p_delete_user.php',
data: $form.serialize(),
dataType : 'json'
}).done(function (response) {
if (response.success) {
// user account exists so show confirmation modal
$('#modal-ajax').load('/spc_admin/modals/m_delete_user.php?username='+response.username+'');
$('#modal-ajax').modal('show');
}
else
{
// show error toast
toastr.error('An error has occurred. Please contact support.', 'Error');
}
});
});
}
Use Javascript to get the username from the form, and put that directly into the modal:
var deleteAccount = function() {
$('#delete-user').on('click', function () {
var username = $(this).closest('form').find("input[name=username]").val();
$('#modal-ajax').load('/spc_admin/modals/m_delete_user.php?username='+encodeURIComponent(username));
$('#modal-ajax').modal('show');
});
}

Backbone model save triggers error callback on Chrome/FF

Noob question here:
I'm using ASP.NET MVC 3 and I'm trying to save an entity through Backbone. Here's what I have:
I defined my Backbone model (Program) as such:
var Program = Backbone.Model.extend({
defaults: function () {
return { name: "" };
},
initialize: function (attrs) {
this.set('name', attrs.name);
},
urlRoot: '/program/add'
});
Then I hook up the model save on the click event of a button:
$('.add-program').click(function () {
var programName = $('.program-name').val();
var program = new Program({ name: programName });
program.save(null, {
success: function (model, response) {
alert('success');
},
error: function (model, response) {
alert('error');
}
});
});
It works on IE (surprisingly!) - ProgramController.Add(string name) gets called fine and I get a success response. But I'm having issues on Chrome and FF - They both trigger the error callback with the slight difference that on Chrome my Controller Action doesn't even get hit at all (it does on FF though). The funny thing is that my action breakpoint does get hit on FF, with the appropriate param value, but still get the error callback.
I'm not sure what's going on here. I tried debugging through Firebug/Chromebug and don't see much on the error callback params (the errorStatus is just ... well... "error"!). I also tried looking at the Network tab and Fiddler and I don't see anything that rings a bell (maybe I'm not looking at the right place). I also tried doing a straight jquery ajax call to the controller and still get the same weird behavior.
Just in case, here's the MVC action (although I don't think the issue is here):
[HttpPost]
public JsonResult Add(string name)
{
var stubbedResponse = new {id = Guid.NewGuid()};
return Json(stubbedResponse);
}
Any ideas what could be causing this?
A Fiddle http://jsfiddle.net/Uj5Ae/2 with your client code seems to be OK. Something with your server response? Or Backbone and Underscore versions not matching?
Or maybe the return false at the end of the click handler, if the event propagation is not handled elsewhere.
Spoiler : that was the event propagation :)

jquery ajax post - not being fired first time

I'm trying to do an ajax post after a button is clicked, and it works in firefox but not in IE the first time the page is loaded. It does work if I refresh the page and try again second time - but not first time and this is crucial.
I've scanned over various web pages - could it be anything to do with the listener? (I've just seen this mentioned mentiond somewhere) Is there something not set correctly to do with ajax and posting when page first loads?
$(document).ready(function() {
$('#btnCont').bind('click',function () {
var itm = $("#txtItm").val();
var qty = $("#txtQty").val();
var msg = $("#txtMessage").val();
var op_id = $("#txtOp_id").val();
//if i alert these values out they alert out no prob
alert(itm+'-'+qty+'-'+msg+'-'+op_id);
$.ajax({
type: "POST",
url: "do_request.php?msg="+msg+"&itm="+itm+"&qty="+qty+"&op_id="+op_id,
success: function (msg) {
document.getElementById('div_main').style.display='none';
document.getElementById('div_success').style.display='block';
var row_id = document.getElementById('txtRow').value;
document.getElementById('row'+row_id).style.backgroundColor='#b4e8aa';
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert('Error submitting request.');
}
});
});
I would start debugging the click event. I.e. if you try to put .bind into a a href tag, the tag itself has a click event that may act on an unwanted way. There exist a command that are named something like event.preventDefaults() that avoids the standard feature of click. After All, you try to manipulate the DOM last of all actions (document.load).
$('#btnCont').bind('click',function () { .. }
I would also try to debug the same functionality with adding onClientClick to the tag instead of adding bind to the document load.
I hope that bring some light.

Resources