Ajax.NET Professional with Mootools

Edit: Do not use this.  See the updated post here.

Edit: I posted this pretty quickly without trying to pass back serialized types from the client to AjaxPro. Mootools Json.Remote prepends “json=” to the JSON string and AjaxPro’s deserializer doesn’t like that. To work around it, I have created Json.AjaxPro which removes this: 

Json.AjaxPro = XHR.extend({ initialize: function(url, options){ this.url = url; this.addEvent('onSuccess', this.onComplete); this.parent(options); this.setHeader('X-Request', 'JSON'); }, send: function(obj){ return this.parent(this.url, Json.toString(obj)); }, onComplete: function(){ this.fireEvent('onComplete', Json.evaluate(this.response.text, this.options.secure)); } });

See also updated assembly and source code below

I have been meaning to start a blog for a while, if only so I can Google my own thoughts later on… I have been using the Ajax.NET library for JSON-RPC with ASP.NET for the last couple of years on various projects. It has always been the easiest way to get an AJAX app going quickly for me. In order to allow easier use with third party libraries like Mootools, the latest AjaxPro beta release adds the ability to alter JSON output to be strictly JSON-compliant (string date formatting mostly) and allows using a custom TypeJavaScriptProvider which renders the client script proxies for your server calls. It also adds the jQueryTypeJavaScriptProvider which generates jQuery-compatible proxy functions, eliminating the need to include the default AjaxPro “core”, “prototype core” and “converter” files. In addition to saving bandwidth, this eliminates potential conflicts with other libraries. Since Mootools already has XHR and JSON handling in the form of JSON.Remote, I took a look a the AjaxPro source to see if I could implement a Mootools provider. It is still a little rough and not every native feature of AjaxPro’s lib is implemented, but it will work for most cases I think. It supports callback, context and onerror arguments (no changes are required to existing javascript code). Tokens and the global AjaxPro.onError aren’t working yet, but I will take a look at it when I have more time. If anyone wants to improve on it, that would be helpful. To use this, download and reference this assembly. You will need the appropriate ajaxNet/ajaxSettings in your web.config 

<scriptReplacements> <file name="core" path=""/> <file name="prototype" path=""/> <file name="converter" path=""/> </scriptReplacements> <providers> <typeJavaScriptProvider type="Ifw.AjaxNet.MootoolsTypeJavaScriptProvider, Ifw.AjaxNet"/> </providers> <oldStyle> <renderJsonCompliant/> <renderDateTimeAsString/> </oldStyle>

Here is the VS2005 Project and a quick look at the (simple) source:  

using System; using System.Reflection; using System.Text; using AjaxPro; namespace Ifw.AjaxNet { public class MootoolsTypeJavaScriptProvider : TypeJavaScriptProvider { public MootoolsTypeJavaScriptProvider(Type type, string url, StringBuilder sb) : base(type, url, sb) {} public override void RenderClassBegin() { string clientNS = GetClientNamespace(); sb.Append("\r\n").Append(clientNS).Append("_class = new Class({\r\n"); sb.Append("AjaxUrl : '" + m_URL + "',\r\n"); } public override void RenderClassEnd() { string clientNS = GetClientNamespace(); sb.Append(@"AjaxProCB : function(response, onsuccess, context, onfailure) { var o = null; eval(""o = "" + response + "";""); if(o != null) { if(typeof o.value != ""undefined"" && typeof onsuccess == ""function"") { o.context = context; onsuccess(o); return; } else if(typeof o.error != ""undefined"" && typeof onfailure == ""function"") { onfailure(o.error); return; } } if(typeof onfailure == ""function"") { onfailure({""Message"":""Failed.""}); } } }); "); sb.Append(clientNS).Append(" = new ").Append(clientNS).Append("_class();\r\n\r\n"); } public override void RenderMethods(MethodInfo[] methods) { for (int i = 0; i < methods.Length; i++) { MethodInfo method = methods[i]; string methodName = GetClientMethodName(method); ParameterInfo[] pi = method.GetParameters(); sb.Append(methodName); sb.Append(" : function("); for (int p = 0; p < pi.Length; p++) { sb.Append(pi[p].Name); sb.Append(", "); } sb.Append("onsuccess, context, onfailure)\r\n{"); sb.Append(@" return new Json.AjaxPro(this.AjaxUrl, { headers: {""X-AjaxPro-Method"":""" + methodName + @"""}, onSuccess: function(response) { " + GetClientNamespace() + @".AjaxProCB(response, onsuccess, context, onfailure); } }).send({"); for (int p = 0; p < pi.Length; p++) { sb.Append("\""); sb.Append(pi[p].Name); sb.Append("\":"); sb.Append(pi[p].Name); if (p < pi.Length - 1) sb.Append(", "); } sb.Append("});\r\n},\r\n"); //TODO: Implement support for AjaxPro Tokens /* string AjaxToken = @"beforeSend: function(xhr) { if(typeof AjaxPro !== 'undefined' && AjaxPro.token !== null) xhr.setHeader(""X-AjaxPro-Token"", AjaxPro.token);}"; */ } } } }

Here is an example of a Mootools proxy class generated with 2 server-side functions:

if(typeof Ifw == "undefined") Ifw={}; if(typeof Ifw.Cgd == "undefined") Ifw.Cgd={}; if(typeof Ifw.Cgd.Video == "undefined") Ifw.Cgd.Video={}; Ifw.Cgd.Video.ProjectManager_class = new Class({ AjaxUrl : '/ajaxpro/Ifw.Cgd.Video.ProjectManager,App_Code.lonzioom.ashx', LoadProjects : function(onsuccess, context, onfailure) { return new Json.AjaxPro(this.AjaxUrl, { headers: {"X-AjaxPro-Method":"LoadProjects"}, onSuccess: function(response) { Ifw.Cgd.Video.ProjectManager.AjaxProCB(response, onsuccess, context, onfailure); } }).send({}); }, SaveProject : function(dto, onsuccess, context, onfailure) { return new Json.AjaxPro(this.AjaxUrl, { headers: {"X-AjaxPro-Method":"SaveProject"}, onSuccess: function(response) { Ifw.Cgd.Video.ProjectManager.AjaxProCB(response, onsuccess, context, onfailure); } }).send({"dto":dto}); } AjaxProCB : function(response, onsuccess, context, onfailure) { var o = null; eval("o = " + response + ";"); if(o != null) { if(typeof o.value != "undefined" && typeof onsuccess == "function") { o.context = context; onsuccess(o); return; } else if(typeof o.error != "undefined" && typeof onfailure == "function") { onfailure(o.error); return; } } if(typeof onfailure == "function") { onfailure({"Message":"Failed."}); } } }); Ifw.Cgd.Video.ProjectManager = new Ifw.Cgd.Video.ProjectManager_class();

That should do it… Hopefully someone finds this useful.

1 comment so far

  1. […] Professional with Mootools (part 2) Posted June 7, 2007 This is an update to my original post.  That version was a preliminary attempt and should not be used in […]


Leave a comment