Running Multiple WebRequests at the same time with $.ajax - c#

I have 2 MVC apps that need to connect to a 3rd application. The code that is causing problems is identical in both MVC apps.
public bool UpdateServerData()
{
//string BASE_URL = "http://";
string BASE_URL = "http://localhost:55094";
string url = BASE_URL + "/Home/PullLiveData";
WebRequest wr = WebRequest.Create(url);
wr.Credentials = CredentialCache.DefaultNetworkCredentials; // uses current windows user
var response = (HttpWebResponse)wr.GetResponse();
return true;
}
public ActionResult GetServerUpdateProgress()
{
//string BASE_URL = "http://";
string BASE_URL = "http://localhost:55094";
string url = BASE_URL + "/Home/UpdateProgress";
WebRequest wr = WebRequest.Create(url);
wr.Credentials = CredentialCache.DefaultNetworkCredentials; // uses current windows user
var myobj = new UpdateAJAXProgress();
var response = (HttpWebResponse)wr.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
JavaScriptSerializer js = new JavaScriptSerializer();
var objText = reader.ReadToEnd();
myobj = (UpdateAJAXProgress)js.Deserialize(objText, typeof(UpdateAJAXProgress));
return Json(myobj);
}
UpdateServerData tells localhost:55094 to refresh the data in the db.
GetServerUpdateProgress returns a progress count / total so that I can display a progress bar for the db refresh.
The $.ajax that runs UpdateServerData is set to work async: true
Then using setTimeouts, I run GetServerUpdateProgress every few seconds which returns how far along UpdateServerData is from completing.
Working App Functionality:
Not Working:
So what appears to be happening in the non-working version is that it is not running GetServerUpdateProgress even though ajax is calling up the function, it doesn't actually begin to process anything inside it until UpdateServerData is complete. You can see the ajax is sync is set correctly because the loading animation is displayed for both in the non working screen shot. I put a breakpoint at the start of GetServerUpdateProgress and it doesn't even trigger until after UpdateServerData is finished processing.
My main concern is that some setting, perhaps in the webconfig or global.asax, is different and that is what is causing both these apps to run a little differently. Any ideas?
Here's some of the associated javascript:
function UpdateData()
{
$("#ChartUpdateProgressWhole").show();
$.ajax({
type: "POST",
async: true,
url: '#(Url.Action("UpdateServerData", "Charts"))',
contentType: "application/json; charset=utf-8",
success: function (data) {
Alert2({
iconfilename: "tick.png",
text: "Database Updated!",
autohide: true,
});
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
},
complete:function (jqXHR, textStatus) {
$("#ChartUpdateProgressWhole").hide();
timerStop = true;
LoadChart();
},
});
if (!timerStop) {
CheckProgress();
}
}
function CheckProgress()
{
if(timerStop) {
CheckProgressAjax();
return;
}
window.setTimeout(CheckProgress, 2000);
CheckProgressAjax();
}
function CheckProgressAjax()
{
$.ajax({
type: "POST",
async: false,
url: '#(Url.Action("GetServerUpdateProgress", "Charts"))',
contentType: "application/json; charset=utf-8",
success: function (data) {
var width = (data.Completed * 100)/data.Total;
$("#ChartUpdateProgressPercent").css("width", width);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.responseText);
}
});
}

Taking a bit of a stab in the dark here, but ASP.NET will actually queue async requests and process them in order if session state is enabled (to avoid having to deal with synchronisation issues no doubt).
My suggestion would be to disable session state all together if feasible, if this is not possible you can disable it per controller using the following attribute:
[SessionState(SessionStateBehavior.Disabled)]
public class SomeController

Related

Why is my JSON string null on the server side when sent using www-form-urlencoded?

I have an ASP.NET / MVC4 application that uses jquery / ajax.
I'm trying to send a very large string from the client to the server using $.ajax( ... )
Primarily, we use the contentType "application/json" for this which works perfectly. In this one particular case however, the server throws an exception because the data being transmitted is too long. I've tried absolutely everything to increase the maxJsonLength for the deserializer in the web.config file but it doesn't work and no one can figure out why.
Someone suggested, as a work around, to send the contentType as "application/x-www-form-urlencoded; charset=UTF-8" and then have my controller manually deserialize the object rather than letting the MVC framework do it.
Javascript:
function AjaxRequest(data, dataType, type, url, contentType, success, error, args)
{
if (url.indexOf("MyController/SomeMethodInMyController") > 0)
contentType = "application/x-www-form-urlencoded; charset=UTF-8";
data = JSON.stringify(data);
$.ajax({async: args.async, cache: args.cache, data: data, dataType: dataType, type: type, url: url, contentType: contentType, traditional: true, headers : { ... }, beforeSend: { ... }, success: { ... }, error: { ... }, complete: { ...});
}
function SomeFunction()
{
var object = {};
object.Name = $("#someControl").val();
object.RtfData = $("someOtherControl").val();
AjaxRequest(object, 'html', 'post', 'MyController/SomeMethodInMyController', 'application/json;', function (response) { ... }, function (error) { ... });
}
In this case, my application no longer crashes "interally" where the MVC framework attempts to deserialize the object on its own. Now it bypasses all that and directly calls the method in my controller. Kind of hacky, but 3 days later I'll take what I can get.
C#:
public void SomeMethodInMyController(string formData)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
jss.MaxJsonLenght = int.MaxValue;
MyType objMyType = jss.Deserialize<MyType>(formData);
//do stuff with objMyType
}
Problem is that when I set a breakpoint in this method, formData is null.
In my browser's console, before $.ajax(); is actually executed I typed typeof(data)into the console which returns "string". If I mouse over the symbol I can see all the data I expect it to contain is there. So why is that in my C# code the value is null?
I think you need to send a FormData object and not just a string. Try changing your AjaxRequest function like this:
function AjaxRequest(data, dataType, type, url, contentType, success, error, args)
{
if (url.indexOf("MyController/SomeMethodInMyController") > 0)
contentType = "application/x-www-form-urlencoded; charset=UTF-8";
var form = new FormData();
form.append("MyData", JSON.stringify(data));
$.ajax({processData: false, async: args.async, cache: args.cache, data: form, dataType: dataType, type: type, url: url, contentType: contentType, traditional: true, headers : { ... }, beforeSend: { ... }, success: { ... }, error: { ... }, complete: { ...});
}

Passing variable to server-side then back to client side without postback or reload

Is there a way to pass values from client side to server-side, server side process this value, then return it to client side without reload or postback?
I am using ajax to pass the value to server side. Here is my client side code:
var baseUrl = '<%= ResolveUrl("~/") %>';
$.ajax({
type: "POST",
url: baseUrl + "Pages/TeamTimeTest/teamtime.aspx/setjson",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({
strpath: $("#hdnfld").val()
}),
success: function (data) {
alert(data);
},
error: function (response) {
console.log(response);
}
});
Here is my code behind code:
[WebMethod(EnableSession = true)]
public static string setjson(string strpath)
{
HttpContext.Current.Session["strDwnPath"] = strpath;
var val = HttpContext.Current.Session["strDwnPath"].ToString();
return val;
}
It returns undefined for me. But when I reload it gives me the correct value. Is there a chance that I could have that value even without reloading?
HttpContext.Current.Session["strDwnPath"] = strpath;
var val = HttpContext.Current.Session["strDwnPath"].ToString();
return val;
I should have done this instead.
var val = strpath;
return val;
All i need here is to get the returned value and it did without reload.

How can browsers display JSON returned from C# Web Service

I have a Web Service (C#, non-WCF) that should return JSON to mobile app clients, it has an API function like this:
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public Animal AnimalInformation(int animalID) {
Animal animal = new Animal();
animal.name = AnimalNameForID(animalID);
animal.color = AnimalColorForID(animalID);
return animal;
}
Although its response format is set to JSON, the response it displays in the browser is still XML, like this:
<Animal>
<Name>Vicky</Name>
<Color>Grey</Color>
</Animal>
I've been looking around for an answer and found out that this is related to the client's reception format, according to this thread, and the thread suggests to use this piece of javascript code to view the JSON return:
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8;",
url: "http://MyWebServiceURL",
data: JSON.stringify({ ParameterName: "DataToSend" }),
dataType: "json",
success: function (data, textStatus, jqXHR) {
//do something
},
error: function (jqXHR, textStatus, errorThrown) {
//fail nicely
}
});
I wasn't able to get this piece of js code to work, it always fails.
My questions:
1, Is there any settings can be set in my browser so that it asks for JSON instead of XML from the Web Service?
2, If not, are there any (simple) alternative solutions? I'm building this Web Service for my app, but I haven't started working on the app yet, so please don't suggest using app as the test client for WS
Check this out: stackoverflow.com/a/19564022/487940
Essentially, you want to flush the contents down the Response and set the ContentType of the response:
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(UseHttpGet=true ,ResponseFormat = ResponseFormat.Json)]
public void HelloWorld()
{
JavaScriptSerializer js = new JavaScriptSerializer();
Context.Response.Clear();
Context.Response.ContentType = "application/json";
HelloWorldData data = new HelloWorldData();
data.Message = "HelloWorld";
Context.Response.Write(js.Serialize(data));
}
}
public class HelloWorldData
{
public String Message;
}

AJAX call to a WebMethod

I have the following Webmethod in my C#/.NET web-application, file lite_host.aspx.cs:
[WebMethod]
public static bool UpdatePage(string accessCode, string newURL)
{
bool result = true;
try {
HttpContext.Current.Cache[accessCode] = newURL;
}
catch {
result = false;
}
return result;
}
It should get the values of "accessCode" and "newURL" from a JavaScript function via a jQuery AJAX call with and make the appropriate changes in Cache:
function sendUpdate() {
var code = jsGetQueryString("code");
var url = $("#url_field").val();
var options = { error: function(msg) { alert(msg.d); },
type: "POST", url: "lite_host.aspx/UpdatePage",
data: {'accessCode': code, 'newURL': url},
contentType: "application/json; charset=utf-8",
dataType: "json",
async: false,
success: function(response) { var results = response.d; } };
$.ajax(options);
}
However when I call the sendUpdate() function, I my script ends on $.ajax error and I'm getting an alert text "undefined".
Undefined means that msg.d doesn't exist. Try doing a console.log(msg) and use Chrome's debugger to see what is outputted (yeah, I know) to the console.

$.ajax and .each in JQuery, with MVC, isn't asynchronous

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.

Categories