intermittent ajax failure with jquery 1.5.1, asp.net, and firefox - c#

I am lazy loading snippets of html on our page in order to improve performance. jQuery's load method does not provide access to the full ajax api (things like error callbacks) so I created a more robust version of it.
I am calling this method 3-5 times per page on just about every page load and am logging when there is some sort of error with ajax call. What I am finding is that about 0.3% of the time the ajax calls are failing the majority of the failures are in firefox 3.6. I am using jQuery 1.5.1 with ASP.NET server side. The 'errorThrown' parameter of the error callback reads:
[Exception... "Component returned failure code: 0x80040111 (NS_ERROR_NOT_AVAILABLE) [nsIXMLHttpRequest.getAllResponseHeaders]" nsresult: "0x80040111 (NS_ERROR_NOT_AVAILABLE)"
and the jqXHR reads:
{"readyState":4,"status":0,"statusText":"error"}
I have confirmed with users that they are experienceing this problem and it's not just bots or some logging of an unexperienced error.
here is the code for my "load" widget
(function ($) {
$.fn.elfLoad = function (url, options) {
return this.each(function () {
var $elem = $(this);
options = $.extend({}, {
type: "GET",
dataType: "html",
data: "",
error: function (jqXHR, status, errorThrown) {
$elem.html('<div class="elf-missing-content centerText">Doh! Something did not go so well when trying to load this content. Please try again later.');
elf.ajax.logInfo("data: " + options.data + " errorThrown: " + errorThrown + " webmethod: " + options.url + "jqXHR: " + JSON.stringify(jqXHR),"elfLoad");
}
}, options);
options.success = function (data, status, jqXHR, responseText) {
responseText = jqXHR.responseText;
if (jqXHR.isResolved()) {
jqXHR.done(function (r) {
responseText = r;
});
$elem.html(responseText);
}
if (options.callback) {
var callbackArgs = {
responseText: responseText,
$elem: $elem,
status: status,
jqXHR: jqXHR
};
$elem.each(options.callback, [callbackArgs]);
}
}
options.url = url;
if (options.data) {
options.data = $.param(options.data, $.ajaxSettings.traditional);
options.type = "POST";
} else {
options.data = "";
}
$.ajax(options);
});
}
})(jQuery);
A call to it would look like this $('#container').elfLoad('url.aspx',{foo:'bar'});
Has anyone else had this problem? Any ideas? jQuery claims to have recently closed a ticket that looks like this in 1.5.1 but I see someone else is having a similar issue. http://bugs.jquery.com/ticket/8400
Thanks!

I ended up solving this issue by using a setTimeout for 2 seconds and retrying the request. So far this is working 100% of the time.

Related

JavaScript not firing in C# MVC4

I have the following code in my view :
<script type="text/javascript">
function OnCancelClick(e)
{
var jobId = e;
var flag = confirm('You are about to cancel job : ' + jobId + '. Are you sure you want to cancel this job?');
if (flag) {
$.ajax({
url: '/job/CancelJob',
type: 'POST',
data: { jobId: jobId },
dataType: 'html',
success: function (result) { alert('Job ' + jobId + ' was cancelled.'); document.location = "#Url.Action("Index", "Job")"; },
error: function () { alert('Something went wrong. Check the log for more information.'); }
});
}
return false;
}
</script>
In my view I also have :
<input type="submit" id="cancelButton" value="Cancel" onclick="javascript: return OnCancelClick(#Model.Id);" />
In my controller I have :
[HttpPost]
public ActionResult CancelJob(int jobId)
{
try
{
logger.LogInfo(string.Format("<start> Cancel-button clicked for job : {0}", jobId), jobId);
JobCommandService.ChangeStatus(jobId, 6);
logger.LogInfo(string.Format("<end> Cancel-button clicked for job : {0}", jobId), jobId);
return RedirectToAction("Index", "Job");
}
catch (Exception ex)
{
logger.LogError(ex.Message, ex, jobId);
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return Json(new { Success = false, Message = ex.Message });
}
}
When I run this in my VS2012 it works just fine.
When I deploy it to the server, I'm getting the message that something went wrong.
In my logging there is no trace of the button being clicked.
As per your comment, when deployed your app is installed in accindigoapps.blabla.lok/jobmonitor.
However your script has the url hardcoded as url: '/job/CancelJob'. That will mean:
when you are debugging from VS your script will work because the request is being sent to a url like http://localhost:XXX/job/CancelJob
however in production, the request will be sent to http://accindigoapps.blabla.lok/job/CancelJob, missing the jobmonitor part.
You need a way to inform your JS code about the base url of your application:
You could generate the Url in a Razor view using Url.Action("CancelJob","job") and pass that Url into your javascript code.
Another option would be to use Url.Content("~/") in some javascript of your base layout. That helper Url.Content("~/") will return only your application folder, / in your dev environment and /jobmonitor/ when deployed. That way you will have your app root-relative url available to any script, so you can use it to build root-relative urls as you were doing in your script:
<script>
var myApp = {};
myApp.BaseUrl = '#Url.Content("~/")';
</script>
//Some other script like yours would be able to keep using root-relative urls as:
$.ajax({
url: myApp.BaseUrl + 'job/CancelJob',
...
If you prefer to generate full urls, you could follow a similar approach. Have a look at this question
Hope it helps!

jQuery PageMethods 401 Authentication failed with FriendlyUrls

I have FriendlyUrls nuget package added to WebForm application.
In RegisterRoutes I have:
var settings = new FriendlyUrlSettings();
//settings.AutoRedirectMode = RedirectMode.Off;
settings.AutoRedirectMode = RedirectMode.Permanent;
routes.EnableFriendlyUrls(settings);
I created 2 pages WebForm1.aspx and WebForm2.aspx
On WebForm1.aspx I referenced jQuery v1.9.1 in the head simply added the following inside the default div tag in the body:
<div id="dvResult"></div>
<script type="text/javascript">
$(function() {
$.fpm("GetCategories", '', function (res) {
$("div#dvResult").html(res.d);
}, function (xhr, ajaxOptions, thrownError) {
$("div#dvResult").html("<b>" + thrownError + "</b><br/>Status: " + xhr.status + "<br/>" + xhr.responseText);
});
});
$.fpm = function fpm(methodName, arguments, onSuccess, onError) {
var proto = (("https:" == document.location.protocol) ? "https://" : "http://");
var hostname = window.location.hostname;
if (window.location.port != 80)
hostname = window.location.hostname + ":" + window.location.port;
var loc = proto + "" + hostname + "/WebForm2.aspx";
$.ajax({
type: "POST",
url: loc + "/" + methodName,
data: "{" + arguments + "}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: onSuccess,
error: onError
});
};
</script>
WebForm2.aspx is kept stock standard after adding the file to the project, except for 1 method added to the code behind:
[System.Web.Services.WebMethod(EnableSession = false)]
public static string GetCategories()
{
return "hi";
}
When I run the page WebForm1.aspx I get the following result:
{"Message":"Authentication failed.","StackTrace":null,"ExceptionType":"System.InvalidOperationException"}
When view the request in fiddler I can see the friendly url did not strip the .aspx extension (which is a good thing):
http://localhost:14918/WebForm2.aspx/GetCategories
However as shown above, the FriendlyUrlSettings has the AutoRedirectMode set to RedirectMode.Permanent and when you uncomment the line for RedirectMode.Off and comment the Permanent out, then you actually get the result "Hi" printed on the screen.
Anyone has any ideas what the cause could be or how to add an exclusion to the routes?
I have tried to following but it does not seem to affect in any way the 401 result I keep getting:
//routes.Add(new Route("*Remote.aspx*", new StopRoutingHandler()));
//routes.Ignore("{remote}", new { remote = #".*\Remote.aspx(/.)?" });
You just saved my day.Below is the c# version of the code.In case of the master pages just paste PageMethods.set_path("default.aspx") before closing Content tag
public static void RegisterRoutes(RouteCollection routes)
{
var settings = new FriendlyUrlSettings();
settings.AutoRedirectMode = RedirectMode.Permanent;
routes.EnableFriendlyUrls(settings, new CustomFriendlyUrlResolver());
}
public class CustomFriendlyUrlResolver : WebFormsFriendlyUrlResolver
{
public override string ConvertToFriendlyUrl(string path)
{
if (HttpContext.Current.Request.PathInfo != "")
{
return path;
}
else
{
return base.ConvertToFriendlyUrl(path);
}
}
}
This is late but in case someone has same issue. Simple fix, set RedirectMode.Off instead of RedirectMode.Permanent. For the Ajax part do the following for the url key:
$.ajax({
type: "POST",
url:'<%=ResolveUrl("sample.aspx/methodname")%>'
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (msg) {
alert("Worked");
},
failure: function (msg) {
alert("Failed");
}
});
I had similar issue, the above solution worked for me. This is a quick fix but I wouldn't recommend it for production. This error occurs partly because of the FriendlyUrl vs non FriendlyUrl redirect method settings hence the server is receiving requests from an unauthenticated user. For production, make sure to put in place necessary security details and accept request from authenticated users otherwise the exposed methods from code behind can cause a huge security risk.
Faced with stripping vast amounts of PageMethods from a large established application, I found the following alternative solution to switching over to WebApi (turning AutoRedirectMode off still allows my file extensions to be displayed when requested directly and I really don't want that).
Instead use a custom FriendlyUrls.Resolver in your App_Start/RouteConfig file. The only change to existing pages was to add the following markup to each page using PageMethods:
<script>PageMethods.set_path("/Pages/Subjects.aspx")</script>
Here is the sample code in VB:
Imports Microsoft.AspNet.FriendlyUrls
Imports Microsoft.AspNet.FriendlyUrls.Resolvers
Public Module RouteConfig
Sub RegisterRoutes(ByVal routes As RouteCollection)
routes.EnableFriendlyUrls(New FriendlyUrlSettings() With {.AutoRedirectMode = RedirectMode.Permanent}, New IFriendlyUrlResolver() {New CustomFriendlyUrlResolver()})
End Sub
End Module
Public Class CustomFriendlyUrlResolver
Inherits WebFormsFriendlyUrlResolver
Public Overrides Function ConvertToFriendlyUrl(path As String) As String
If HttpContext.Current.Request.PathInfo <> "" Then Return path Else Return MyBase.ConvertToFriendlyUrl(path)
End Function
End Class
Hope that helps someone!
Ended up creating WebApi project and after a few new problems arriving (CORS related), got it working and actually feel that it's probably a better solution than pagemethods.

Unexpected jQuery ajax json response

I am having some strange issues with jQuery (1.7.2) ajax and asp.net.
When using the code below locally this all appears to work fine. The ajax fires fine, the modal pops up as expected, the div slides down, and I'm very happy with the result.
However, on our development server, we run into some strange issues. We start hitting the error function. In the error function, the return text isn't our JSON'd time stamp, but rather the HTML from a different page in our page flow. We've tried playing with the params to .ajax, we've tried fiddling with the modal, we've tried just returning the timestamp in our code behind method, we tried changing our dataType to text. That allowed it to fire the modal, however, Inf.innerHTML just ended up displaying the rendering of that other page in our page flow.
We've spent a bunch of time trying to debug this, but we're still stuck. Any ideas would be much appreciated.
jQuery:
$("#<%= Btn.ClientID %>").click(function() {
$.ajax({
async: true,
type: "POST",
url: "Page.aspx/Method",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
$("#Modal").modal({
closeClass: "Modal-Close",
escClose: false,
opacity: 35,
overlayCss: { backgroundColor: "#000" }
}); //end Modal
//timeStamp = data.d; //Timestamp elsewhere in the js
}, //end success
error: function(xhr, status, error) { alert("xhr: " + xhr.responseText + "\n\nstatus: " + status + "\n\nerror: " + error); }
}); //end ajax
return false;
}); //end Btn.click
$(".Modal-Close").click(function() {
ModalClose();
});
var timeStamp;
function ModalClose() {
var img = document.getElementById("imgP");
var Inf = document.getElementById("Info");
var Name = document.getElementById("<%=divName.ClientID %>").value;
img.src = "difImg.png";
Inf.innerHTML = "Sometext" + Name + ", MoreText.<br />" + timeStamp;
var divO = document.getElementById("<%=divOut.ClientID %>");
$(divO).slideDown();
}
C# Page Code-behind
[WebMethod(EnableSession = true)]
public static string Method()
{
// Various magic
return "{\"d\":\"" + DateTime.Now.ToString("MMMM dd, yyyy h:mm tt") + "\"}";
}

JQuery AJAX, Error Status code: 200, Status Text: parserorro | OK

Here is a funny situation that I'm in.
I'm developing an ASP.Net web site using VS 2008 and .Net Framework 3.5, and I want to use jquery ajax in a test page, the code looks like this:
C# Method
[WebMethod]
public static string test()
{
return "Server Response" ;
}
$(document).ready(function() {
$("#myDiv").click(function() {
$.ajax({
type: "POST",
url: "AjaxTest.aspx/test",
data: "",
contentType: "application/json;charset=utf-8",
dataType: "json",
success: function(msg) {
// Replace the div's content with the page
// method's return.
alert(msg.d);
},
error: function(result){
alert("error occured. Status:" + result.status
+ ' --Status Text:' + result.statusText
+ " --Error Result:" + result);
}
});
});
});
So When I use Jquery 1.4.4 like this :
I get : Status 200; Status Text: OK
When I use Jquery 1.5 I get: Status 200; Status Text: Parsererror
So I created a new WebSite in Visual Studio, copy and pased the code there, and it works fine !!!! I can't figure out what causes the problem.
Also I have used methods with parameter, and setting data:"{}", and removing data completely, but nothing seems to work.
I don't know if has to do anything with the DevExpress components that I'm using or not.
I also found a good answer which was working with complete method like this :
complete: function(xhr, status) {
if (status === 'error' || !xhr.responseText) {
alert("Error");
}
else {
var data = xhr.responseText;
alert(data);
//...
}
}
But I don't know if it will work fine or there might be some other problem with this method too. I also don't know how to access response data from here.
But my main concern is finding out what is causing the problem in my website.
UPDATE: Well today in Google Chrome console I noticed some syntax problems with JQuery 1.5
they are as below:
Uncaught SyntaxError: Unexpected token <
jQuery.jQuery.extend.globalEvaljquery.js:593
jQuery.ajaxSetup.converters.text scriptjquery.js:7175
ajaxConvertjquery.js:7074
donejquery.js:6622
jQuery.ajaxTransport.send.callbackjquery.js:7441
The issue isn't so easily solved with fiddler, although it's a great tool.
The issue I think is described here, and for now use the complete event.
there are some issues that will be resolved in jQuery 1.5.1
See:
jQuery returning "parsererror" for ajax request
as it was posted there,
complete: function (xhr, status) {
if (status == 'error' || !xhr.responseText) {
handleError();
}
else {
var data = xhr.responseText;
//...
}
}
Although the interesting thing is - this works for me with jsonp data when I query amazon's service (code amazon was based on some other posting on the net I don't have the ref too) ala:
//resp is simple a placeholder for autocomplete's response which I will need to call on a global scope.
var resp;
var filter;
$(document).ready(function () {
//http://completion.amazon.com/search/complete?method=completion&q=halo&search-alias=videogames&mkt=1&x=updateISSCompletion&noCacheIE=1295031912518
filter = $("#productFilter").autocomplete({
source: function (request, response) {
resp = response;
$.ajax({
url: "http://completion.amazon.com/search/complete",
type: "GET",
cache: false,
dataType: "jsonp",
success: function (data) {
//data[1] contains an array of the elements returned from the service.
//use .map to enumerate through them.
response($.map(data[1], function (item) {
//debugger;
return { label: item, value: item, id: item}
}))
},
data: {
q: request.term,
"search-alias": "videogames",
mkt: "1",
callback: '?'
}
});
},
minLength: 2,
select: function (event, ui) {
//$('#browseNode option:first').attr('selected', 'selected');
alert('selected');
},
open: function () {
$(this).removeClass("ui-corner-all").addClass("ui-corner-top");
},
close: function () {
$(this).removeClass("ui-corner-top").addClass("ui-corner-all");
}
});
});
//this is the method that will be called by the jsonp request
function updateISSCompletion() {
alert('updateiss');
resp(completion[1]);
}
You should use Fiddler - the great web debugging proxy. With its help you can watch for all communication between server and client
Not sure if this will help, but the ajax() API specifies that they have changed the return object for the success() callback function. This is from the jQuery API
As of jQuery 1.5, the success callback function receives a "jqXHR" object (in jQuery 1.4, it received the XMLHttpRequest object). However, since JSONP and cross-domain GET requests do not use XHR, in those cases the jqXHR and textStatus parameters passed to the success callback are undefined.
You can find it here if it helps at all...
jQuery $ajax API
I am running into a similar problem, and am unable to pull the JSON object from any callback functions.
I had this problem too but in PHP When i put in 'remote.php':
`echo $msg`'
problem occurs. When I use json_encode():
echo json_encode($msg);
then everything works.
This is strange, because I get response from server with status 'OK', so then function 'success' should work not 'error'. In 'success' i have only
success: function(res){ console.log(res);}
In my case (when using "jquery 1.9.1"), adding dataType: "json" solved the "parsererror" problem (I didn't specify dataType before and that problem occurred).
I had a similar problem.
I called in AJAX a REST service with POST method and got back :
arguments[0] = status 200 (OK) | arguments[1] = "parseerror" | arguments[2] = "Invalid JSON :"
My server method returned a "void" value. To resolve the problem, I replaced it by a Boolean value for example.

JavaScript, JQuery, or AJAX version of Recaptcha Validate

am trying to validate the recaptcha using some js code but am getting some permission Errors "Access is Denied"
Is it possible to achieve the validation using the javascript validation code alongside ajax across multiple browsers.
<script type="text/javascript">
$(document).ready(function() {
Recaptcha.create("var_public_key", recaptchadiv, {
theme: "clean",
callback: Recaptcha.focus_response_field
});
});
function submitFormData() {
var urlString = "http://www.google.com/recaptcha/api/verify";
var params = encodeURI("remoteip=" + $("#userIp").val() +"&privatekey=" + var_private_key + "&challenge=" + Recaptcha.get_challenge() + "&response=" +
Recaptcha.get_response());
params = encodeURI(params);
var status = document.getElementById("status");
status.className = "";
status.innerHTML = "<b>Submitting your data. Please wait...</b>";
var html = $.ajax({
type: "POST",
url: urlString + "?" + params,
async: false
}).responseText;
alert("ResponseText: " + html + ", Recaptcha.responseText: " + Recaptcha.responseText);
var result = html.split("\n")[0];
if (result == "true") {
status.innerHTML = " ";
return true;
}
else {
status.className = "GlobalErrorText";
status.innerHTML = "Your captcha is incorrect. Please try again";
Recaptcha.reload();
return false;
}
}
</script>
#Boug is right, this is called cross site ajax request, you can see this question to see if you can a find a solution Cross-site AJAX requests but....
I think putting your private key for recaptcha in javascript is a vulnerability, recaptcha should be validated on Server Side code, this question contain useful links about how to implement recaptcha in Asp.Net MVC How to implement reCaptcha for ASP.NET MVC? I used this approach and it works perfectly http://www.dotnetcurry.com/ShowArticle.aspx?ID=611&AspxAutoDetectCookieSupport=1
You are getting permission error because your ajax code is trying to access a script on a different site (google) as your script. From what I know, I dont think you can do cross site Ajax calls for security reasons
The question has already been answered. But, here's some added code that will work in ASP.NET WebForms, which enables you to make a local AJAX request to the page w/ the reCaptcha control, then do server-side captcha validation. The page's web method will return true/false.
I got this code from mindfire solutions, but added the execution of JS functions in the Ajax success callback b/c Ajax is making async callbacks.
Javascript:
<script type="text/javascript">
$(function(e) {
$("#submit").click(function() { // my button is type=button, not type=submit
// I'm using jQuery validation and want to make sure page is valid before making Ajax request
if ( $("#aspnetForm").valid() ) {
validateCaptcha(); // or validateCaptchaJson() if you want to use Json
} // end If ($("#aspnetForm").valid())
}); // end $("#submit").click()
}); // end $(function(e)
function validateCaptcha() {
// Individual string variables storing captcha values
var challengeField = $("input#recaptcha_challenge_field").val();
var responseField = $("input#recaptcha_response_field").val();
// Ajax post to page web method that will do server-side captcha validation
$.ajax({
type: "POST",
url: "page.aspx/ValidateCaptcha",
data: "recaptcha_challenge_field=" + challengeField + "&recaptcha_response_field=" + responseField,
async: false
success: function(msg) {
if(msg.d) { // Either true or false, true indicates CAPTCHA is validated successfully.
// this could hide your captcha widget
$("#recaptcha_widget_div").html(" ");
// execute some JS function upon successful captcha validation
goodCaptcha();
} else {
// execute some JS function upon failed captcha validation (like throwing up a modal indicating failed attempt)
badCaptcha();
// don't forget to reload/reset the captcha to try again
Recaptcha.reload();
}
return false;
}
});
}
function validateCaptchaJson() {
// JavaScript object storing captcha values
var captchaInfo = {
challengeValue: Recaptcha.get_challenge(),
responseValue: Recaptcha.get_response()
};
// Ajax post to page web method that will do server-side captcha validation
$.ajax({
type: "POST",
url: "page.aspx/ValidateCaptcha",
data: JSON.stringify(captchaInfo), // requires ref to JSON (http://www.JSON.org/json2.js)
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function(msg) {
if(msg.d) { // Either true or false, true indicates CAPTCHA is validated successfully.
// this could hide your captcha widget
$("#recaptcha_widget_div").html(" ");
// execute some JS function upon successful captcha validation
goodCaptcha();
} else {
// execute some JS function upon failed captcha validation (like throwing up a modal indicating failed attempt)
badCaptcha();
// don't forget to reload/reset the captcha to try again
Recaptcha.reload();
}
return false;
}
});
}
</script>
Page's Web Method (VB.NET):
<WebMethod()> _
Public Shared Function ValidateCaptcha(ByVal challengeValue As String, ByVal responseValue As String) As Boolean
' IDEA: Get Private key of the CAPTCHA from Web.config file.
Dim captchaValidtor As New Recaptcha.RecaptchaValidator() With { _
.PrivateKey = "your_private_key_goes_here", _
.RemoteIP = HttpContext.Current.Request.UserHostAddress, _
.Challenge = challengeValue, _
.Response = responseValue _
}
' Send data about captcha validation to reCAPTCHA site.
Dim recaptchaResponse As Recaptcha.RecaptchaResponse = captchaValidtor.Validate()
' Get boolean value about Captcha success / failure.
Return recaptchaResponse.IsValid
End Function

Categories

Resources