my Ajax calls don't seem to be asynchronous when wrapped inside a .each loop, instead they seem to wait for each to finish before calling the next one ..
MVC C#:
[HttpPost]
public JsonResult DoActionGetNextStep(JSONSubmission Submission)
{
SomeStruct body = new SomeStruct();
DateTime start = DateTime.Now;
try
{
System.Threading.Thread.Sleep(5000);
body.html= "There, done";
}
catch (Exception e)
{
body.html= "There was an error: "+e.Message;
}
TimeSpan s = DateTime.Now - start;
ast.Html = body.html+ "<p> c# took " +s.Seconds +"s</p>";
return Json(body);
}
JQuery:
function DoActions(targets) {
$(targets).each(function () { DoAction($(this)); });
}
function DoAction(target) {
var parent = $(target).parents('div.actionReplaceable');
var JSONSubmission = { Data : "somedata" };
var Submission = JSON.stringify(JSONSubmission, null, 2);
$.ajax({
type: 'POST',
url: '/Main/DoActionGetNextStep',
data: Submission,
async: true,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (Result) {
var html = Result.html;
$(parent).html(html);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
$(parent).html("JQuery Error: " + textStatus + "\n" + errorThrown);
}
});
}
This ends up taking 25 seconds for 5 elements, each of them reporting that their call took 5 seconds. I thought ajax calls were asynchronous, so this operation should take 5 seconds total? Both server and browser are running on my localhost. Can anyone spot what I'm missing?
There are two reasons why Ajax calls aren't processed in parallel:
Most browsers limit this, either because they only use two connections to each site they contact or because they explicitly limit concurrent Ajax calls.
If you access the session state in an ASP.NET application (MVC or not), you'll also run into an exclusive lock that causes parallel connections to wait. For MVC, there's an attribute to indicate that your controller action only requires read-only access to the session state to work around that.
Your requests should be asynchronous. Check with console.log in the appropriate places to see when things happen.
$(targets).each(DoAction);
function DoAction() {
var $parent = $(this).parents('div.actionReplaceable'),
JSONSubmission = { Data : "somedata" };
console.log("sending request for " + this-id);
$.ajax({
type : 'POST',
url : '/Main/DoActionGetNextStep',
data : JSON.stringify(JSONSubmission, null, 2),
contentType : 'application/json; charset=utf-8',
success : function (Result) {
console.log("received response for " + this-id);
$parent.html(Result.html);
},
error : function (XMLHttpRequest, textStatus, errorThrown) {
console.log("received error for " + this-id);
$parent.html("JQuery Error: " + textStatus + "\n" + errorThrown);
}
});
}
There is no need for a target parameter. jQuery sets this correctly for callback functions.
Once you got rid of the target parameter you just need to pass the function reference to .each().
Unless the return type is JSON (seems to be HTML here), setting dataType: 'json' is wrong.
setting async: true is superfluous unless you configured the global Ajax options to be async: false. Which I hope you did not.
Related
I have a WCF Service and I am using AJAX to call the service methods from my web application. My AJAX call is as below.
$.ajax({
type: 'GET',
url: 'http://localhost:56083/Service1.svc/Web/GetIntegrationById?id=' + value,
dataType: 'json',
processData: true,
contentType: "application/javascript",
success: function (data) {
console.log(data);
},
failure: function (data) {
console.log("Failed " + data);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log("Request: " + XMLHttpRequest.toString() + "\n\nStatus: " + textStatus + "\n\nError: " + errorThrown);
}
})
This call is being used to implement Search functionality. WCF service contains the below method that is being called above.
public Integration GetIntegrationById(string id)
{
IntegrationList integrationList = new IntegrationList();
Integration integration;
integration = integrationList.CreateIntegrations().Where(i => id != null && i.IntegrationId == Convert.ToInt16(id)).FirstOrDefault();
return integration;
}
CreateIntegrations() method given below.(Created for testing purposes)
public Integration[] CreateIntegrations()
{
List<Integration> integrationList = new List<Integration>()
{
new Integration() { IntegrationId=1,... },
new Integration() { IntegrationId=2, ... },
new Integration() { IntegrationId=3, ... },
new Integration() { IntegrationId=4, ... },
new Integration() { IntegrationId=5, ... }
};
Integrations = integrationList;
return integrationList.ToArray();
}
Now when I enter values between 1-5 in the search textbox I get the respective Integration object. However, when I enter something that is not in the list above, for example, id=8, as expected the value of integration is null which gets returned from the web method. This leads to a parser error on the client side as it is expecting a JSON value and receives null which it fails to parse. So I changed the last line to
return integration ?? new Integration();
This was done with the hope of receiving a non-null value on the client-side. However, this fails with the error below.
I might be doing ample of things wrong here but I need to know how to manage/handle null values when returned from the service method. If not how do I handle a scenario where a requested item is not present? Any help appreciated. Thanks.
The problem here is when you are giving correct or expected input ,successful response is returned i.e integration variable holds known value which is understood by js. But for the wrong input deserialization is failing since the return value from the service is null and thus failing.
Assuming $('#id').val() in client side html holds your input id value.
$.ajax({
type: 'Post',
url: 'http://localhost:56083/Service1.svc/Web/GetIntegrationById',
data: JSON.stringify({ id: $('#id').val() }),
dataType: 'json',
processData: true,
contentType: "application/json;charset=utf-8",
success: function (data) {
console.log(data);
},
failure: function (data) {
console.log("Failed " + data);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log("Request: " + XMLHttpRequest.toString() + "\n\nStatus: " + textStatus + "\n\nError: " + errorThrown);
}
})
Since its a mock service,suggest you to create the class object of Integration and tweak appropriately.I am sure,if you call GetIntegrationById method within .net application,it will fail since integration object will be null but since its a JS call,its failing silently in js console.
Integration integration=new Integration();
[I realise this might seem like a stupid question but I am lost.]
Using umbraco 4.9 I have a multi-lingual site where I have made an event handler to replicate content nodes to all languages as they are created in the back office to all languages. I am now trying to attach this to a custom context menu item(umbraco.interfaces.IAction) to give the creator a choice.
In the context menu item it is only possible to call a javascript function as a string. I shouldn't touch the umbraco code itself so how can I pass a value to a web service? Where do I include the reference?
This is what I have at the moment:
public string JsSource
{
get
{
return "function AddItem(){" +
"var multiLang = confirm('Create for all languages?');" +
//"$.ajax({" +
//"type: 'Post'," +
//"url: 'TryAgain.aspx/' + SendMultiVal" +
//"data: multiLang})" +
//"PageMethods.SendMulti(multiLang);}" +
string.Format("{0}.actionNew()", ClientTools.Scripts.GetAppActions)+"};";
}
}
Thanks in advance.
So the first thing that you need to do is to store the boolean value in a variable called boolvalue and then call the callservice function once you have the value.For eg:
CallService("POST", "YourServiceUrl",boolvalue,
function (data) {
alert("Service Call Success");
},
function (result) {
alert('Service call failed: ' + result.status + '' + result.statusText);
});
This will make a service call and get data from service if it returns some data.
CallService = function (method, serviceUrl, value, successHandler, errorHandler) {
$.ajax({
type: method,
url: serviceUrl,
contentType: "application/text; charset=utf-8",
dataType: "json",
data:JSON.stringify(value),
success: successHandler,
error: errorHandler
});
};
Modify the dataType and dataType fields depending upon the type of data that you send and receive from the service.
Look into this if you need more information:
http://api.jquery.com/jQuery.ajax/
Let me know if this works out for you.
I have the following request:
var response = $.ajax({
type: "POST",
contentType: "application/x-www-form-urlencoded",
url: this.AgentServiceUrl + "/" + methodName,
data: data,
async: this.Async,
success: function (xml, textStatus) { if (successHandler != null) successHandler(state, $.xml2json(xml), textStatus); },
error: function (xmlHttpRequest, textStatus, errorThrown) { if (errorHandler != null) errorHandler(state, xmlHttpRequest, textStatus, errorThrown); }
});
I want to add to a variable to this request header and consume it on C#,
I try many ways but I can't consume it on C#:
beforeSend: function (req)
{
req.setRequestHeader("AgentGUID", this.AgentGUID);
},
Pass parameters:
Can you help me? I don't want to change the function at the C# part I just want to use something like:
(System.Web.HttpContext.Current.Request.Headers["someHeader"]
Your beforeSend should work as you wish, but the reason you are not getting the value on server side is that this.AgentGUID on this method call is undefined because this in that context is pointing to another object (most probably ajax request object).
By defining a variable outside your ajax call you issue will be fixed.
var me = this;
var response = $.ajax({
...
beforeSend: function (req)
{
req.setRequestHeader("AgentGUID", me.AgentGUID);
},
...
});
I have the following jQuery AJAX request:
function sendUpdate(urlToSend) {
var code = AccessCode;
var url = urlToSend;
var options = { error: function(msg) { alert(msg.d); },
type: "POST", url: "webmethods.aspx/UpdatePage",
data: "{ accessCode: " + code + ", newURL: '" + url + "' }",
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function(response) { var results = response.d; } };
$.ajax(options);
}
And the corresponding ASP.NET WebMethod:
[WebMethod]
public static bool UpdatePage(string accessCode, string newURL)
{
bool result = true;
try
{
HttpContext.Current.Cache[accessCode + "l"] = newURL;
}
catch
{
result = false;
}
return result;
}
That all used to work correctly with "async:false", however I have to get rid of it as it freezes the browser until the response is received. Now the AJAX request above returns "undefined".
Could anybody tell me why it happens and where the problem is?
Thanks.
You should really make sure to properly encode this JSON. JSON.stringify is the most reliable method:
data: JSON.stringify({ accessCode: code, newURL: url })
This ensures that even if the code and url variables contain some dangerous characters that will break your string concatenations in the resulting JSON at the end everything will be properly encoded. The JSON.stringify method is natievly built into modern browsers but if you need to support legacy you could include json2.js.
Also because you code is no longer blocking you should make sure that if you call this sendUpdate from some button click or form submit you cancel the default action by returning false.
My way works correctly:
[System.Web.Services.WebMethod()]
public static string getHello(string str)
{
//do some things with str
return str;
}
In file .js, I define this function to call webmethod in file .cs:
function CallServerFunction(StrPriUrl, ObjPriData, CallBackFunction) {
$.ajax({
type: "post",
url: StrPriUrl,
contentType: "application/json; charset=utf-8",
data: ObjPriData,
dataType: "json",
success: function (result) {
if (CallBackFunction != null && typeof CallBackFunction != 'undefined') {
CallBackFunction(result);
}
},
error: function (result) {
alert('error occured');
alert(result.responseText);
window.location.href = "FrmError.aspx?Exception=" + result.responseText;
},
async: true
});
}
Then, call to use (call in file.js):
var text = $("#textbox_send").val();
var myresult;
CallServerFunction("Default.aspx/getHello", JSON.stringify({ str: text }), function (myresult) {
if (text != "")
$('#' + id).append('<p>' + $("#account_user").text() + ': ' + myresult.d + '</p>');
});
The "undefined" could be the result of a server error.If you use Firebug,Firefox(or any good client debugging tool), you can find the error returned by the server. Paste the error,if any.
Nevertheless, I also noted the the "data" for "accessCode" is not properly enclosed within quotes ‘ ’
The corrected data option would be :
data: "{ accessCode: '" + code + "', newURL: '" + url + "' }",
PS:
Since 'options' have a different meaning in Jquery, I would recommend changing the variable name as 'setting' . Change 'var options ' to 'var settings'. :)
Does anyone know what is it going on here? I have try to pass a value from ajax to .aspx, but somehow the value seem doesn't pass over successfully.
Following is my code:
$.ajax({
type: "POST",
url: "pgtest.aspx",
data: "sState=VIC",
success: function (msg) {
alert("Data Saved: " + msg);
}
});
and this is my code inside my .net c#:
newTest.Value = Request.QueryString["sState"];
Somehow the for Request.QueryString["sState"] is empty in .net c#. Does anyone know what is going wrong here ?
When passing data in POST, the data is not passed in Request.QueryString, it's passed into Request.Form instead. Try
newTest.Value = Request.Form["sState"];
Another thing I'd change is the jQuery call - use a data object instead of just a string, a such:
$.ajax({
type: "POST",
url: "pgtest.aspx",
data: { sState: "VIC" },
success: function (msg) {
alert("Data Saved: " + msg);
}
});
Request.QueryString is for GET requests only. For POST requests, you need Request.Form. See also: Get POST data in C#/ASP.NET
You need to use GET request as it is light in nature but less secured too and it is passed in querystring.:
$.ajax({
type: "GET",
url: "pgtest.aspx?sState=VIC",
success: function (msg) {
alert("Data Saved: " + msg);
}
});
Now you will get below values:
newTest.Value = Request.QueryString["sState"];