My ajax request times out (or is really slow) - asp.net

My first forray into ajax webpages is causing me some problems.
My basic structure is that I have a table on a page, which I want to reload without refreshing the entire page.
So on clicking a button on the page it fires of this:
function RefreshMissionsAjax() {
//fade out the old table.
$(clientID('MissionsDisplay')).fadeOut(500);
//request the new value from the page (calls the GetIncompleteMissions() method in the MissionViewer.aspx.cs page)
$.ajax({
type: "POST",
url: "MissionViewer.aspx/GetIncompleteMissions",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
$(clientID('MissionsDisplay')).html(msg.d);
$(clientID('MissionsDisplay')).fadeIn(500);
},
error: function (xhr, ajaxOptions, thrownError) {
$(clientID('MissionsDisplay')).html('An error occured while trying to refresh the page data.');
$(clientID('MissionsDisplay')).fadeIn(500);
}
});
}
And I have in the code bedind of an aspx page:
[WebMethod]
public static string GetIncompleteMissions()
{
return GetHTMLTable();
}
This method just grabs some data, and creates a html table - nothing too fancy.
When the returned table is small (a dozen rows or less) then it works like a charm.
But when it gets larger, it takes a long long time.
At 100 rows it can take 5 minutes to render the table.
At 1000 rows I have left it for 30 minutes and nothing will happen after the fadeout.
(NB - it loads fairly quickly on the pageload, before the ajax refresh is used, so it is not the actual server side creation of the table thats the problem).
This is my first real attempt at doing something like this, so I dont know if this is the best way to do it - it was just something i pieced together that worked great when i was testing with small datasets.
Now, not so much.
Any ideas how I can make it usable?

If possible, use WCF instead, it should be lot faster.
Anyway, don't pass the raw HTML back, have the service return minimized data in JSON format then use this data in the onsuccess event to create the table on the fly with jQuery.
For example have the service return JSON array with 1000 items then iterate this array and add one row for each item.

Related

How can i upload files along with other model values in asp.net mvc using ajax?

All the articles i've found talks about either uploading both files and text values using non-ajax form post, or uploading only files with ajax post requests. Is there a way to upload both files and text values using ajax post to mvc action where i can get model binding as well as Request.Files?
After making some experiments, turns out the code doing this is also not that complicated:
var formData = new FormData($("form")[0]);
$.post({
url: "/Home/Upload",
contentType: false,
processData: false,
data: formData,
success: function () {
alert("done");
}
});
The tricky part is the construction of FormData object. There's actually no need to manually add files and other text values, as long as all the inputs are inside a form tag.

Logic related to sessions

I have an requirement to show users a pop up when there is one minute left to session expires time. Suppose session expiration time is 5 minutes and I need to show a pop up that "Your session will expire in next one minute" please click here if you want to continue otherwise click cancel. So, if user clicks ok, time should again refreshed automatically and if cancelled then no need to do any thing .
For this I have done something like this in my Shared folder in Layout
var myVar = setInterval(function () { myTimer() }, 240000);
function myTimer() {
var r = confirm("Session will expire in a minute. will you like to continue working?");
if (r == true) {
var _Id = $("#Id").val();
$.ajax({
type: "POST",
contentType: "application/json; charset=utf-8",
url: "../Home/ResetUser",
data: "{'User_ID':'" + _Id + "'}",
dataType: "json",
success: function (data) {
if (data.Data == 'Done') {
}
},
error: function (xhr) {
}
});
}
else {
window.clearInterval(myVar);
}
But I have one problem and that is I do not have the same layout derived in all the pages. Some modules have different layout and some pages do not need any layout.So, I need to keep that script running differently for different layouts or the pages which do not use the layouts.
Will it work fine if I keep the script differently for different layouts?
Also Suppose I have logged in and I set a session variable. Now time is set to 5 minutes
and user come to home page which is not using the layout where I kept the above script.
I have the script added differently in this page and script function time starts..
but then user went to another page then session time will refreshed?
and I have to load my above script function on that page?
Am I doing the right things.
Hi You can write your script in _viewstart.cshtml file.
This will be executed for each request irrespective of the Layout page you are using
but then user went to another page then session time will refreshed? and I have to load my above script function on that page?
Yes when you user refresh the page or request the server again the session time will be reset.
This is the one way to achieve your requirement.

Returning several arrays as a Json result, how can I serialize the response on the server?

When the Action method below attempts to return the Json result no data object comes back to the $.ajax function. Hence I presume I am not serializing the arrays prior to sending them off as a Json result. I need to retain the array names i.e: ProgTypes, Ages etc. So I know which array is which when the data returns from the server.
$.ajax({
url: '/Education/FilterLists',
dataType: 'json',
data: { svalues: svalues, firsttype: $firsttype },
traditional: true,
success: function (data) {
//do something with data
alert('done');
}
});
..
public JsonResult FilterLists(int[] svalues, string firsttype)
{
//Some logic takes place and below arrays are produced
int[] ProgTypes = programs.Select(x => x.FilterValToCatMaps.FirstOrDefault(c => c.FilterValue.FilterID == 5).FilterValueID).Distinct().ToArray();
int[] Ages = programs.Select(x => x.FilterValToCatMaps.FirstOrDefault(c => c.FilterValue.FilterID == 4).FilterValueID).Distinct().ToArray();
int[] Countries = programs.Select(x => x.ParentCategory.ParentCategory.ParentCategory.CatID).Distinct().ToArray();
return Json(new { progtypes = ProgTypes, ages = Ages, countries = Countries});
}
You are attempting to retrieve JSON data via a GET request (jQuery AJAX implicitly does a GET unless you specify the "type: 'POST'" option"). ASP.NET blocks JSON returning GETs for security reasons with an exception of this message:
"This request has been blocked because sensitive information could be disclosed to third party web sites when this is used in a GET request. To allow GET requests, set JsonRequestBehavior to AllowGet."
Your success function is never getting executed because the request isn't a success. I would recommend getting FireBug for FireFox and using the 'Net' tab or use chromes built in debugger and use the 'Network' tab if you are going to be doing any web development (especially AJAX). Network errors pop right up in there and it can save you a lot of time.
You have two options at this point, change your .NET code or change your JavaScript, pick one below:
$.ajax({
url: '/Education/FilterLists',
dataType: 'json',
type: 'POST', //ADD POST HERE
data: { svalues: svalues, firsttype: $firsttype },
traditional: true,
success: function (data) {
//do something with data
alert('done');
}
});
OR
return Json(new { progtypes = ProgTypes, ages = Ages, countries = Countries}, JsonRequestBehavior.AllowGet);

Databinding ASP.Net repeater from Ajax

I've got some Ajax code with calls a WebMethod from within my back-end code and now want to be able to databind the information it receives to a repeater.
Here's my Ajax
$.ajax({
type: "POST",
url: "default.aspx/Call_Car",
data: '{ Ref: "MD12355"}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(msg) {
var cars = msg.d;
$.each(cars, function(index, car) {
$('.test').text(car.PICKUP);
$('.test2').text(car.SUPPLIER);
});
}
});
At the moment it is writing the fields PICKUP and SUPPLIER to my labels but ideally i want it to be able to databind my repeater with all the data.
Here's the response I get back from this call
{"d":[{"SUPPLIER":"Magos Car Hire","PICKUP":"Funchal Airport"}]}
Is it possible to do this?
Thanks
You cannot, a repeater binds on the server side, and you are returning client side data.
You can use one of the jQuery grids or a variety of other grids (kendoui im particularly fond of from telerik)
Or you could request the page from the server that contains the data and grid and load that via ajax.
This is addressed in a bit more detail here:
Bind Data to Repeater using Ajax

Get callback info back to original calling function

Let's say you have a Javascript function that calls a web service method. So that webservice completes and calls a callback function, which has the result.
How do I get that result back into the original function that called the web service method? Essentially, I'm trying to "synchronize" an asynchronous call.
Update:
This is what I'm trying to do. I'm validating based on the return value of a web service.
$.validator.addMethod("zzz",
function(value, element) {
// Call web service function using ASP.NET Ajax.
// Get callback value to determine validity.
return this.optional(element) || ***return t/f based on validity***;
},
function(value, element) { return msg; }
);
so I guess I could do this instead:
$.validator.addMethod("zzz",
function(value, element) {
$.ajax({
async: false
url: **** web service url ****
success: set t/f to validity var
});
return this.optional(element) || ***return t/f based on validity var***;
},
function(value, element) { return msg; }
);
Since you're using jQuery, you can use async:false in your ajax command, like this:
$.ajax({
//options..
async: false
});
//this code will run after the request returns
Note though, this blocks the UI (locks up the browser), it's better to continue the work that depends on the result in the success callback, like this:
$.ajax({
//options..
success: function(data) {
doSomethingWithResult(data);
}
});
Essentially, you can't, but you can break up that function into "before" and "after" parts, like so:
function foo(a) {
var b, c;
// == The "before" part:
b = /* ... */;
// == Call the service:
callWebService(a, b, callback);
// == The "after" part is contained within the callback:
function callback(d) {
// Do something with a, b, c, and d
}
}
But it's important to note that foo will return before callback is called. There's no way to prevent that with an asynchronous call, so if you're looking to have the function return something, you'll have to refactor (or use a synchronous call, but that's a very bad idea). The refactoring would involve whatever's calling foo to provide a callback and expect the result to be provided that way rather than as a return value.
Well what you're trying to accomplish is simulating a sleep command, so your script "waits" for your ajax request? But that doesn't really makes sense. That's why you have to callback in the first place, to continue with the flow once the request has returned a reply, since you cannot predict its response time.
Not to be trite, but you can't create synchronousness from asynchronousness, only the other way around. You need to design your code to allow for this, which generally means callbacks all the way through your call chain.
There is one idiosyncratic exception, which is that you can specify 'false' on the raw XMLHttpRequest's 'open' method's async parameter, which will cause the send method to block until it's done. But this is likely not compatible with some frameworks and is pretty inflexible. Most JS stuff is async.
You should not do that. Just carry on with your processing from the point of the callback.
You risk hanging the browser completely if the call does not return.
If you control the server side then you could write some code on the js side to aggregate calls and then write something on the server side to unpack and do multiple calls from each nested call in the aggregate. When the responses come back then aggregate those and send them back. This will save on performance since large calls are cheaper than many small calls.
We did that on a project I worked on and it worked very nicely. It also consolidates logic on the js side to not be spread all over due to all the async callbacks.
The only way I can think of is like
function b(){
var a = null;
$.get("abc.json", {
success: function(data){
a = data;
}
});
while(a == null){}
alert(a);
}
b();
But generally this isn't good and may cause the browser to complain a script is taking too long to finish.

Resources