I was using Ajax exclusively until I got tired of the sheer innefficiency of the update panels. They work, but it is so darn slow when you are trying to do anything real on a website. I had pages with a few update panels and they would simply take seconds to refresh.
So I moved to jQuery using webservices for the data access. It was a great move. Now the pages load faster. There is a little bit of a loss of convinience since I am trying to completly get rid of the scriptmanager, but the following bit of javascript made calling the services a lot easier. Coupled with some restful wcf services, it works like a charm. I've converted entire page to a windows like editing system using only javascript and restful service.
Anyway, here is some code to help calling services in jQuery
// *** Service Calling Proxy Class
function serviceProxy(serviceUrl) {
var _I = this;
this.serviceUrl = serviceUrl;
// *** Call a wrapped object
this.invoke = function(method, data, callback, error, bare) {
// *** Convert input data into JSON - REQUIRES Json2.js
var json = JSON2.stringify(data);
// *** The service endpoint URL
var url = _I.serviceUrl + method;
$.ajax({
url: url,
data: json,
type: "POST",
processData: false,
contentType: "application/json",
timeout: 10000,
dataType: "text", // not "json" we'll parse
success:
function(res) {
if (!callback) return;
// *** Use json library so we can fix up MS AJAX dates
var result = JSON2.parse(res);
// *** Bare message IS result
if (bare)
{ callback(result); return; }
// *** Wrapped message contains top level object node
// *** strip it off
for (var property in result) {
callback(result[property]);
break;
}
},
error: function(xhr) {
if (!error) return;
if (xhr.responseText) {
var err = null;
try{ var err = JSON2.parse(xhr.responseText); }
catch(e) { err = xhr.responseText;}
if (err)
error(err);
else
error({ Message: "Unknown server error." })
}
return;
}
});
}
}
if (!this.JSON2) {
JSON2 = function() {
function f(n) { return n < 10 ? '0' + n : n; }
var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g, gap, indent, meta = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"': '\\"', '\\': '\\\\' }, rep; function quote(string) {
return escapeable.test(string) ? '"' + string.replace(escapeable, function(a) {
var c = meta[a]; if (typeof c === 'string') { return c; }
c = a.charCodeAt(); return '\\u00' + Math.floor(c / 16).toString(16) +
(c % 16).toString(16);
}) + '"' : '"' + string + '"';
}
function str(key, holder) {
var i, k, v, length, mind = gap, partial, value = holder[key]; if (value && typeof value === 'object' && typeof value.toJSON === 'function') { value = value.toJSON(key); }
if (typeof rep === 'function') { value = rep.call(holder, key, value); }
switch (typeof value) {
case 'string': return quote(value); case 'number': return isFinite(value) ? String(value) : 'null'; case 'boolean': case 'null': return String(value); case 'object': if (!value) { return 'null'; }
if (value.toUTCString)
{ var xx = '"\\/Date(' + value.getTime() + ')\\/"'; return xx; }
gap += indent; partial = []; if (typeof value.length === 'number' && !(value.propertyIsEnumerable('length'))) {
length = value.length; for (i = 0; i < length; i += 1) { partial[i] = str(i, value) || 'null'; }
v = partial.length === 0 ? '[]' : gap ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']' : '[' + partial.join(',') + ']'; gap = mind; return v;
}
if (typeof rep === 'object') { length = rep.length; for (i = 0; i < length; i += 1) { k = rep[i]; if (typeof k === 'string') { v = str(k, value, rep); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } } } else { for (k in value) { v = str(k, value, rep); if (v) { partial.push(quote(k) + (gap ? ': ' : ':') + v); } } }
v = partial.length === 0 ? '{}' : gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}' : '{' + partial.join(',') + '}'; gap = mind; return v;
}
}
return { stringify: function(value, replacer, space) {
var i; gap = ''; indent = ''; if (space) { if (typeof space === 'number') { for (i = 0; i < space; i += 1) { indent += ' '; } } else if (typeof space === 'string') { indent = space; } }
if (!replacer) {
rep = function(key, value) {
if (!Object.hasOwnProperty.call(this, key)) { return undefined; }
return value;
};
} else if (typeof replacer === 'function' || (typeof replacer === 'object' && typeof replacer.length === 'number')) { rep = replacer; } else { throw new Error('JSON.stringify'); }
return str('', { '': value });
}, parse: function(text, reviver) {
var j; function walk(holder, key) {
var k, v, value = holder[key]; if (value && typeof value === 'object') { for (k in value) { if (Object.hasOwnProperty.call(value, k)) { v = walk(value, k); if (v !== undefined) { value[k] = v; } else { delete value[k]; } } } }
return reviver.call(holder, key, value);
}
if (/^[\],:{}\s]*$/.test(text.replace(/\\["\\\/bfnrtu]/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { var regEx = /(\"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}.*?\")|(\"\\*\/Date\(.*?\)\\*\/")/g; text = text.replace(regEx, this.regExDate); j = eval('(' + text + ')'); return typeof reviver === 'function' ? walk({ '': j }, '') : j; }
throw new SyntaxError('JSON.parse');
}, regExDate: function(str, p1, p2, offset, s) {
str = str.substring(1).replace('"', ''); var date = str; if (/\/Date(.*)\//.test(str)) { str = str.match(/Date\((.*?)\)/)[1]; date = "new Date(" + parseInt(str) + ")"; }
else { var matches = str.split(/[-,:,T,Z]/); matches[1] = (parseInt(matches[1], 0) - 1).toString(); date = "new Date(Date.UTC(" + matches.join(",") + "))"; }
return date;
}, quote: quote
};
} ();
}
The usage is like this:
var manageProxy = new serviceProxy("/WebServices/ResultStructuresService.svc/");
manageProxy.invoke("SomeFunction",
{ someparam: somevalue },
function(message) {
if (!message) {
return;
}
// the json parameters should be encode to prevent that attack
if (message && message.length > 0) {
// do something with the response
_allowedTypes = message;
}
},
function(error) {
$.jGrowl(error.Detail, { header: "Oops!", life: 8000 });
});