Looking Forward to next AjaxPro Release

Michael Schwarz on Friday, April 13, 2007

Some developers mentioned that it would be nice if Ajax.NET Professional [1] could be more JSON compliant to use with some JavaScript frameworks that are not using the eval statement. And, if you have a look at json.org [2] JSON message always have to be an object or array, not a string or boolean directly. Well, I absolutly see the need of these changes and I have done this already in a beta version which I will provide this evening.

 

How JSON messages will look like, now

To be more JSON compliant I'll return an object with two possible parameters, one with the name value and another one with error (if an Exception has been thrown during the execution of the AjaxMethod). Another change will be to remove the JavaScript code ";/*" at the end of each JSON message which I used to get it working on all web server including some very special configurations with Apache and Mono.

// 3 old JSON messages<span class="str">"Hello World"</span>;/
<span class="kwrd">true</span>;/

=<span class="kwrd">null</span>;r.error={<span class="str">"Message"</span>:<span class="str">"You are not authenticated!"</span>,<span class="str">"Type"</span>:<span class="str">"System.Exception"</span>};/*

<span class="rem">// 3 new JSON messages</span> {<span class="str">"value"</span>:<span class="str">"Hello World"</span>} {<span class="str">"value"</span>:<span class="kwrd">true</span>} {<span class="str">"error"</span>:{<span class="str">"Message"</span>:<span class="str">"You are not authenticated!"</span>,<span class="str">"Type"</span>:<span class="str">"System.Exception"</span>}}</pre>

 

New JSON converters

There will be a couple of new JSON converters which may get default. The thing is that AjaxPro sometimes is returning a function call to return a new instance of a class with some additional properties. With the old DataSet converter I reduced the amoung of data sent back to the client-side JavaScript code by saving each time the colum names. A new converter will return a common array with column names in each row which can be used in more third-party JavaScript frameworks. You can switch between these converters in web.config. Note: the change of the DateTime converter will save some bytes, too, which is already possible in AjaxPro web.config configuration today.

<pre class="csharpcode"><span class="rem">// old DataSet converter</span>
<span class="kwrd">new</span> Ajax.Web.DataSet([<span class="kwrd">new</span> Ajax.Web.DataTable(<br> [[<span class="str">"uid"</span>,<span class="str">"System.Int16"</span>],[<span class="str">"name"</span>,<span class="str">"System.String"</span>],[<span class="str">"type"</span>,<span class="str">"System.String"</span>],<br> [<span class="str">"refdate"</span>,<span class="str">"System.DateTime"</span>]],<br> [<br> [1,<span class="str">"sysobjects"</span>,<span class="str">"S "</span>,<span class="kwrd">new</span> Date(Date.UTC(2002,11,17,13,36,10,43))],<br> [1,<span class="str">"sysindexes"</span>,<span class="str">"S "</span>,<span class="kwrd">new</span> Date(Date.UTC(2002,11,17,13,36,10,43))],<br> [1,<span class="str">"syscolumns"</span>,<span class="str">"S "</span>,<span class="kwrd">new</span> Date(Date.UTC(2002,11,17,13,36,10,43))],<br> [1,<span class="str">"systypes"</span>,<span class="str">"S "</span>,<span class="kwrd">new</span> Date(Date.UTC(2002,11,17,13,36,10,43))],<br> [1,<span class="str">"syscomments"</span>,<span class="str">"S "</span>,<span class="kwrd">new</span> Date(Date.UTC(2002,11,17,13,36,10,43))]<br> ]<br>)]);/*

<span class="rem">// new DataSet converter</span> {<span class="str">"result"</span>:{<span class="str">"Tables"</span>:[ {<span class="str">"Rows"</span>:[ {<span class="str">"uid"</span>:1,<span class="str">"name"</span>:<span class="str">"sysobjects"</span>,<span class="str">"type"</span>:<span class="str">"S "</span>,<span class="str">"refdate"</span>:<span class="str">"2002-11-17T13:36:10"</span>}, {<span class="str">"uid"</span>:1,<span class="str">"name"</span>:<span class="str">"sysindexes"</span>,<span class="str">"type"</span>:<span class="str">"S "</span>,<span class="str">"refdate"</span>:<span class="str">"2002-11-17T13:36:10"</span>}, {<span class="str">"uid"</span>:1,<span class="str">"name"</span>:<span class="str">"syscolumns"</span>,<span class="str">"type"</span>:<span class="str">"S "</span>,<span class="str">"refdate"</span>:<span class="str">"2002-11-17T13:36:10"</span>}, {<span class="str">"uid"</span>:1,<span class="str">"name"</span>:<span class="str">"systypes"</span>,<span class="str">"type"</span>:<span class="str">"S "</span>,<span class="str">"refdate"</span>:<span class="str">"2002-11-17T13:36:10"</span>}, {<span class="str">"uid"</span>:1,<span class="str">"name"</span>:<span class="str">"syscomments"</span>,<span class="str">"type"</span>:<span class="str">"S "</span>,<span class="str">"refdate"</span>:<span class="str">"2002-11-17T13:36:10"</span>}, ]} ]}}</pre>

 

AjaxSecurityProvider and the AjaxToken

Because the old interfaces IAjaxKeyProvider and IAjaxCryptProvider are not easy to understand (for some developers) I changed that and created only on interface (abstract class). With this new provider you could create your own de/-encryption for JSON messages and provide a token for each client. I will write about this in another post when the beta is available to the public.

Below you will see a simple encryption (reverse the JSON messages only, but could be replaced i.e. by a Blowfish implementation [3])) and a way to create a token that will be checked for each Ajax request:

<pre class="csharpcode"><span class="kwrd">public</span> <span class="kwrd">class</span> MySecurityProvider : AjaxSecurityProvider
{
<span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> Encrypt(<span class="kwrd">string</span> json)
{
<span class="kwrd">char</span>[] s = json.ToCharArray();
Array.Reverse(s);
<span class="kwrd">return</span> <span class="kwrd">new</span> String(s);
}

<span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> Decrypt(<span class="kwrd">string</span> jsoncrypt) { <span class="kwrd">char</span>[] s = jsoncrypt.ToCharArray(); Array.Reverse(s); <span class="kwrd">return</span> <span class="kwrd">new</span> String(s); }

<span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> ClientScript { get { <span class="kwrd">return</span> <span class="str">@"

AjaxPro.cryptProvider = {};

AjaxPro.cryptProvider.decrypt = function(s) { var r = []; for(var i=s.length -1; i&gt;=0; i--) { r.push(s.substr(i,1)); } return r.join(''); };

AjaxPro.cryptProvider.encrypt = function(s) { var r = []; for(var i=s.length -1; i&gt;=0; i--) { r.push(s.substr(i,1)); } return r.join(''); };

"</span>; } }

<span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">string</span> GetAjaxToken(<span class="kwrd">string</span> sitePassword) { <span class="kwrd">if</span> (HttpContext.Current == <span class="kwrd">null</span> || HttpContext.Current.Request == <span class="kwrd">null</span>) <span class="kwrd">return</span> <span class="kwrd">null</span>;

<span class="kwrd">string</span> ip = HttpContext.Current.Request.UserHostAddress; <span class="kwrd">string</span> agent = HttpContext.Current.Request.UserAgent; <span class="kwrd">string</span> site = sitePassword; <span class="kwrd">string</span> token = ip + agent + site;

<span class="kwrd">return</span> MD5Helper.GetHash(token); }

<span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> IsValidAjaxToken(<span class="kwrd">string</span> token, <span class="kwrd">string</span> sitePassword) { <span class="kwrd">if</span> (token == GetAjaxToken(sitePassword)) <span class="kwrd">return</span> <span class="kwrd">true</span>;

<span class="kwrd">return</span> <span class="kwrd">false</span>; }

<span class="kwrd">public</span> <span class="kwrd">override</span> <span class="kwrd">bool</span> AjaxTokenEnabled { get { <span class="kwrd">return</span> <span class="kwrd">true</span>; } } } </pre>

The old version had a lot of bugs when using the token feature. I fixed those bugs and added support for tokens if using the IFrame XMLHttpRequest replacement when ActiveX objects are disabled.

New JavaScript proxy files

A lot of developers are already using JavaScript frameworks with XMLHttpRequest support. For those I will add new settings to change the output of the JavaScript wrappers, core.ashx, prototype.ashx will be removed then, and you should not have a problem with any third-party control or JavaScript framework.

Another thing is that the Ajax request queue perhaps may be removed. I see more problems with that when developers are using this to run more than 20 (!!!) at the same time which makes absolutly no sense.