AJax call not consistently returning data under IE for all users in MVC 4 application
I have a very interesting and frustrating problem. I have a web application developed using MVC 4, JQuery and Bootstrap. One of the forms prompts for some information and then makes an AJax call to see if any records already exist for the information entered.
Here is the problem. When a user enters a new record and then go back to see if it exists, the AJax call returns with no data (or so it seems). If I try and see if a record exists from a user that reports this problem, it works for me and I am able to find the record. Most users are using IE 9. Those users on Chrome are not reporting the error.
Here is the AJax call:
$("#RequestSearch").click(function (e) { $("#modal-wrapper").hide(); $("#loading").show(); var numkeys = $("#uniqueKeyCounter").val(); if (numkeys > 0) { $(".error").empty(); var haserrors = 0; var uniquekeyfields = ""; var dateval = ""; for (i = 0; i < numkeys; i++) { //if the value is blank $("#uniquekeygroup" + i).removeClass("has-error has-feedback"); $("#uniquekeyadd" + i).empty(); // first look for the datepicker class & validate the dates dateval = ""; if ($("#uniquekey" + i).val() == '') { $(".error").append("You must supply a value for <strong>" + $("#uniquekeyname" + i).text() + "</strong><br />"); $("#uniquekeygroup" + i).addClass("has-error has-feedback"); $("#uniquekeyadd" + i).append("<span class='glyphicon glyphicon-warning-sign form-control-feedback'></span>"); haserrors = 1; } else { // see if the field is a date dateval = $('.datepicker' + i).val(); //supposed to be a date field --> // if (dateval != 'undefined') if ($('.datepicker' + i).val()) { // alert("dateval = "+dateval); if (Date.parse(dateval)) // if false the date is mal formed { } else { $(".error").append("You must supply a correctly formatted DATE value for " + $("#uniquekeyname" + i).text() + "<br />"); $("#uniquekeygroup" + i).addClass("has-error has-feedback"); $("#uniquekeyadd" + i).append("<span class='glyphicon glyphicon-warning-sign form-control-feedback'></span>"); haserrors = 1; } } //This is where we're currently formulating the Unique Key string. // we need to pass in the Referral Type along with the keys if (uniquekeyfields == "") { uniquekeyfields = encodeURIComponent($("#uniquekey" + i).val()); } else { uniquekeyfields = uniquekeyfields + "," + encodeURIComponent($("#uniquekey" + i).val()); } } } var uniquekeysreturned; if (haserrors == 0) { var ReferralTypeID = $('#ReferralTypeID').val(); // generate the Unique Key String for the unique fields and the Referral Type uniquekeysreturned = generateUniqueKeystring(ReferralTypeID, uniquekeyfields); //uniquekeyfields needs to match what the database is storing ---> // hide the bottom section, in case it currently is appearing $('#dupesection').hide(); // empty out any text in the output area -- where the dupes will show up $('#outputarea').empty(); var UniqueKeyValue = $('#UniqueKeyValue').val(); //return the duplicates for the Referraltype and the unique keys data = returnDuplicates(ReferralTypeID, uniquekeysreturned); var jsonString = data; // if no results were found, then submit form to create a new request if ($.trim(jsonString) == "") { var form = $("#referral-form"); // submit form to proper view // form.attr("action", "@Url.Action("CreateNewRequest","ScreenTest")"); // form.submit(); var form = $("#referral-form"); // get URL for form var controllerName = $("#ReferralRoute").val() + "RequestProcess"; var actionName = "CreateRequest"; form.attr("action", getURL(controllerName, actionName, "")); formatform(); form.submit(); } else { var myData = JSON.parse(jsonString); // alert(data); // since we know there will be output, show the bottom section $('#dupesection').show(); // hide the Search button $('.modal-footer').hide(); // set the text for the label to the output area, with the Unique Key Value $('#outputarealabel').text("Matching Referrals"); // (" + UniqueKeyValue + ")"); var status = ""; var output = "<table id='widetable' class='table table-striped' width='100%'><thead><tr style='background-color:#00468b;color:#fff'><th width='5%'>ID</th><th width='20%'>Submitted</th><th width='20%'>Submitted By</th><th width='35%'>Referral Information</th><th width='10%'>Status</th><th width='10%'>Action</th></tr></thead><tbody>"; // create update link // create view link var controllerName = $("#ReferralRoute").val() + "RequestProcess"; var actionName = ""; var routeVals = ""; $.each(myData, function (idx, obj) { routeVals = obj.ID; status = "" switch (obj.ReferralStatusID) { // Produces link for Updating Request case 1: //New Request actionName = "UpdateRequest"; status = "<a class='btn btn-success UpdateRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >Update Referral</a>"; output = output + "<tr class='danger'>"; break; case 3: //Needs Info actionName = "UpdateRequest"; status = "<a class='btn btn-success UpdateRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >Update Referral</a>"; output = output + "<tr class='danger'>"; break; case 5: //Received actionName = "UpdateRequest"; status = "<a class='btn btn-success UpdateRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >Update Referral</a>"; output = output + "<tr class='column-unassigned'>"; break; case 2: //Needs Approval actionName = "UpdateRequest"; status = "<a class='btn btn-success UpdateRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >Update Referral</a>"; output = output + "<tr class='warning'>"; break; case 4: //Approved actionName = "UpdateRequest"; status = "<a class='btn btn-success UpdateRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >Update Referral</a>"; output = output + "<tr class='warning'>"; break; case 10: //Waiting for Reply actionName = "UpdateRequest"; status = "<a class='btn btn-success UpdateRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >Update Referral</a>"; output = output + "<tr class='warning'>"; break; case 6: //Assigned actionName = "UpdateRequest"; status = "<a class='btn btn-success UpdateRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >Update Referral</a>"; output = output + "<tr class='success'>"; break; // Below are View only statuses case 8: //Completed actionName = "UpdateRequest"; status = "<a class='btn btn-primary ViewRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >View Referral</a>"; output = output + "<tr class='info'>"; break; case 12: //On Hold actionName = "UpdateRequest"; status = "<a class='btn btn-primary ViewRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >View Referral</a>"; output = output + "<tr class='info'>"; break; case 9: //Declined actionName = "UpdateRequest"; status = "<a class='btn btn-primary ViewRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >View Referral</a>"; output = output + "<tr class='declined'>"; break; case 11: //Closed actionName = "UpdateRequest"; status = "<a class='btn btn-primary ViewRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >View Referral</a>"; output = output + "<tr class='declined'>"; break; case 7: //In Progress actionName = "UpdateRequest"; status = "<a class='btn btn-primary ViewRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >View Referral</a>"; output = output + "<tr class='declined'>"; break; case 13: //Withdrawn actionName = "UpdateRequest"; status = "<a class='btn btn-primary ViewRequest' href='" + getURL(controllerName, actionName, routeVals) + "' >View Referral</a>"; output = output + "<tr class='declined'>"; break; } output += "<td>" + obj.ID + "</td><td>" + obj.DateSubmitted + "</td><td>" + obj.SubmittedBy + "</td><td>" + obj.Referralinformation + "</td>"; // output += "<td>"; // Sample --->>> <a tabindex="0" class="popup" role="button" data-toggle="popover" data-trigger="focus" data-placement="top" data-content="INformation goes here"><span class="glyphicon glyphicon-question-sign" ></span></a> // output+="<a href='#' title='View More Referral Information' target='_blank' ><span class='glyphicon glyphicon-question-sign'></span> </a>" // output+="</td>"; output += "<td>" + obj.ReferralStatus + "</td><td>" + status + "</td></tr>"; }); output = output + "</tbody></table>"; output = output + '<button type="button" class="btn btn-success CreateNewRequest">Create New Referral</button>'; var $outputarea = $('#outputarea'); $(output).appendTo($outputarea); $("#widetable").DataTable({ "order": [0, 'desc'], "stripeClasses": ['odd', 'even'], "bSort": false }); } $(".CreateNewRequest").click(function (e) { $("#modal-wrapper").hide(); $("#loading").show(); var form = $("#referral-form"); // get URL for form var controllerName = $("#ReferralRoute").val() + "RequestProcess"; var actionName = "CreateRequest"; form.attr("action", getURL(controllerName, actionName, "")); formatform(); form.submit(); }); } //has errors else { $("#modal-wrapper").show(); $("#loading").hide(); } } //numkeys }); function getURL(controllerName, actionName, routeVals) { var URL; var result = 0; $.ajax({ data: { actionName: actionName, controllerName: controllerName, routeVals: routeVals }, async: false, type: 'GET', url: '@Url.Action("getURL","RequestProcess")', success: function (data) { //callback //alert("data =" + data); result = data; } }); //alert("result = " + result); return result; } function returnDuplicates(ReferralTypeID,uniquekeysreturned) { var URL; var result = ""; $.ajax({ data: { referraltypeid: ReferralTypeID, keyValues: encodeURI(uniquekeysreturned) }, async: false, type: 'GET', dataType: "json", url: '@Url.Action("findduplicates","RequestProcess")', error: function (jqXHR, exception) { if (jqXHR.status === 0) { alert('Not connect.n Verify Network.'); } else if (jqXHR.status == 404) { alert('Requested page not found. [404]'); } else if (jqXHR.status == 500) { alert('Internal Server Error [500].'); } else if (exception === 'parsererror' && data != "") { alert('Requested JSON parse failed.'); } else if (exception === 'timeout') { alert('Time out error.'); } else if (exception === 'abort') { alert('Ajax request aborted.'); } else { alert('Uncaught Error.n' + jqXHR.responseText); } }, success: function (data) { //callback //alert("data =" + data); result = data; } }); return result; } function generateUniqueKeystring(ReferralTypeID,uniquekeyfields) { var URL; var result = ""; $.ajax({ data: {referraltypeid: ReferralTypeID, keyValues: uniquekeyfields }, async: false, type: 'GET', url: '@Url.Action("generateUniqueKeystring","RequestProcess")', success: function (data) { //callback //alert("data =" + data); result = data[0]; } }); //alert("result = " + result); //return the first item in the collection return result; }
When I use IE's debugger and watch the Network traffic I see the call being made.
Network results:
===== Success ========URL Method Result Type Received Taken Initiator Wait Start Request Response Cache read Gap/Apps/Referrals/RequestProcess/findduplicates?referraltypeid=21&keyValues=DRC%2520Policy%2C2011212 GET 304 application/json 463 B < 1 ms JS Library XMLHttpRequest 6740 0 0 0 0 9079===== Failed =========URL Method Result Type Received Taken Initiator Wait Start Request Response Cache read Gap/Apps/Referrals/RequestProcess/findduplicates?referraltypeid=21&keyValues=DRC%2520Policy%2C2011214 GET 304 application/json 446 B < 1 ms JS Library XMLHttpRequest 15819 0 0 0 0 0
return Json("ReferralTypeID is 0 or keyValues are not defined", JsonRequestBehavior.AllowGet); ;
and:
return Json("No records found", JsonRequestBehavior.AllowGet);
to see if the problem is on the server side. When checking the response.body when no data is returned I do not get the messages.
Any help in trying to figure out what is going is greatly appreciated. My project is being held up until the issue is resolved.
The 304 appears in the Successful call also. The call under Success returned data. The Call under Failed did not. They both have 304 for the Cache Read. Do you still think it could be a Caching problem on the server?
dyarosh
ASKER
We discovered the problem and it had to do with the Ajax call. Your suggestion about the Cache ended up leading us to the solution even though it doesn't involve the cache on the server. We set the contentType in the AJax call to "application/json; charset=utf-8" and this solved the problem. I gave you a B only because your suggestion ended up leading us to the solution even though it wasn't involved in the solution. Thank you so much for your help!!!
ambience
Glad to hear that, though 304 is not for "cache read" its more than likely the HTTP Result Code - 304 is "Not Modified."
URL Method Result
Server returns 304 telling the client that the version of resource it has is "Not Modified," therefore no need to download it again and use the previous the client has. In your logs, it looks like the server is returning DATA as well - 446 bytes (AFAIR, something against the semantics of 304). IT could be that IE interprets 304 more strictly than other browsers and discards the returned response and uses its previously cached response, whereas other browsers use the response content.
I certainly don't see how setting the content type on the server could fix, when you have already mentioned that IE works fine with some responses.