Update: On June 20th 2009, Codeplex notified me that the patch I did for the ACT has been applied. I haven't tested it yet, though. Get the latest source (not latest stable version) and you should be fine.

The Ajax Control Toolkit has a PopupExtender module that is used throughout the library in whichever controls need to show above other controls. I wanted to use the Calendar Extender in my web site, but the calendar appeared underneath other controls. I checked it out and it had a zIndex of 1000, which should have been enough. I took me an hour to realise that in the toolkit code zIndex was a property of the div element, not of the div style!

A download of the latest version from Feb 29 shows the problem is still there. The fix? go to the PopupExtender folder in the source code, open the PopupBehaviour.js file, search for a line that looks like this:
element.zIndex = 1000;
and replace it with
element.style.zIndex = 1000;
. Now it works!

The issue is already in the AjaxControlToolKit issue tracker, but it was not addressed yet.

A while ago I wrote a quick post to remind me of how to use the AutoCompleteExtender, but recently I realised that it was terribly incomplete (pun not intended). I've updated it, but I also felt that I need to restructure the whole post, so here it is, with more details and more code fun.

First of all, a short disclaimer: I am not familiar with the ASP.Net Ajax javascript paradigm. If some of the things that I am doing seem really stupid, it's because I did it by trial and error, not by understanding why the code is as it is. Here it goes.

There are two ways in which to use the AutoCompleteExtender: using PageMethods or using web service methods. The details are in the previous post, I will only list the gotchas in this one.
  • PageMethods requirements:
    1. ScriptManager must have EnablePageMethods="true"
    2. The page method must have the form public static string[] MethodName(string prefixText, int count) AND THE SAME PARAMETER NAMES. If you change prefixText with text it will not work!
    3. The page method has to be public and STATIC
    4. No, it is not possible to declare the method in a web user control, it must be in the page
  • Web service requirements:
    1. The method must have the form public string[] MethodName(string prefixText, int count) AND THE SAME PARAMETER NAMES. If you change prefixText with text it will not work!
    2. The method has to be public and NOT STATIC
    3. The method must be marked as ScriptMethod
.

Now, the method can return an array different from a string array, but the only useful types there would be numerical or maybe dates. Any object that you send will ultimately be transformed into "[object Object]". There is a way to send a pair of value,text encoded in the strings, and for that you use:
AutoCompleteExtender.CreateAutoCompleteItem(text, value);

It doesn't help much outside the fact that in the client javascript events of the AutoCompleteExtender the first parameter will be the AutoCompleteExtender javascript object and the second an object with a _text and a _value properties.

One of the questions I noticed frequently on the web is: How do I show the user that there are no auto complete matches?. The easy solution is always to return at least one string in the string array that your method is returning. If there are no matches, make sure there is a "No Match" string in the list. But then the complicated part comes along: how do you stop the user from selecting "No Match" from the list? And I do have a solution. It seems that the text in the textbox is set based on the existence of a javascript object called control that has a set_text function. If the object or the function do not exist, then a simple textbox.value=text is performed. So I used this code:

string script = @"var tb=document.getElementById('" + tbAutoComplete.ClientID + @"');if (tb) tb.control={set_text:setText,element:tb};";
ScriptManager.RegisterStartupScript(Page,Page.GetType(),UniqueID+"_init",script,true);
to set the object for my textbox. And also the javascript code that looks liks this:
function setText(input) {
if (input=='No Match') return;
this.element.value=input;
}


These being said, I think that one can use the AutoCompleteExtender and know what the hell is making it not work.

Update: The 30 September 2009 release of the AjaxControlToolkit doesn't have the error that I fix here. My patch was applied in July and from September on the bug is gone in the official release as well. Good riddance! :)

==== Obsolete post follows

I've just downloaded the 29 feb 2008 release of the AjaxControlToolKit and I noticed that the TabContainer bug that I fixed in one of the previous posts did not work anymore. So the post is now updated with the latest fix.

Fixing TabContainer to work with dynamic TabPanels

Apparently, the guys that make the Ajax Control Toolkit are not considering this a bug, since I posted it a long time ago as well as a bunch of other folks and there are also some discussions about it on some forums.

This blog post is about ASP.Net Ajax calls (Update panel and such), if you are interested in aborting jQuery.ajax calls, just call abort() on the ajax return object.

Kamal Balwani asked for my help on the blog chat today and asked for the solution for a really annoying issue. He was opening a window when pressing a button on an ASP.Net page and that window used web services to request data from the server repeatedly. The problem was when the window was closed and FireFox (the error did not appear on Internet Explorer) showed a 'Sys is not defined' error on this javascript line: _this._webRequest.completed(Sys.EventArgs.Empty);.

It was a silly error, really. There was this javascript object Sys.Net.XMLHttpExecutor and it had a function defined called _onReadyStateChange where a completed function received Sys.EventArgs.Empty as an argument. At that time, though, the page was unloaded as well as any objects defined in it. I consider this a FireFox bug, as any javascript function should not try to access an object that was unloaded already.

Anyway, going through the Microsoft Ajax library is a nightmare. I am sure they had clear patterns in mind when they designed it this way but for me it was a long waste of time trying to get my head around it. Finally I've decided that the only solution here was to abort the last Ajax request and so I've reached these two posts:

Cancel a Web Service Call in Asp.net Ajax
How to cancel the call to web service.

Bottom line, you need to use the abort function on a WebRequestExecutor object which one can get from using the get_executor function on a WebRequest object which should be returned by a scriptmethod call.

But you see, when you execute TestService.MyMethod you get no return value. What you need to do is use TestService._staticInstance.MyMethod which returns the WebRequest object required! Good luck figuring that out without Googling for it.

From then on the ride was smooth: add an array of web requests and at the window.onbeforeunloading event, just abort them all.

Here is the code for the popup window:

<body onload = "runMethod();" onbeforeunload = "KillRequests();">

function runMethod() {
   if (!window._webRequests) window._webRequests = Array();
   _webRequests[_webRequests.length]
      = TestService._staticInstance
        .MyMethod(OnSuccess, OnTimeout);
   }


function OnSuccess(result) {
   //do something with the result
   setTimeout(runMethod, 500);
   }


function OnTimeout(result) {
   setTimeout(runMethod, 500);
   }


function KillRequests() {
   if (!window._webRequests) return;
   for (var c = 0; c < window._webRequests.length; c++) {
      if (window._webRequests[c]) {
         var executor = window._webRequests[c].get_executor();
         if (executor.get_started()) executor.abort();
         }
      }
   }

A chat user asked me the other day of how does one put the tabs in the AjaxToolKit TabContainer vertically and I had no idea. I've decided to do it today and write this blog post, maybe he'll come back and he'd get the answer.

So, the request is simple: take a web site with a TabContainer in it and make it show the tabs vertically. I can only assume that the vertical tabs would go on the left and the content in the right. So I took the Internet Developer Toolbar and analysed the html output of a page with four static tabs. I added a <style> tag with CSS classes and started making changes until it worked. Unfortunately, the same setup would not work on Firefox, so I had to repeat the process using Firebug to analyse the page output. In the end this is the result:
<style>
.ajax__tab_header {
float:left;
}
.ajax__tab_body {
/*float:left;*/
margin-left:220px;
}
.ajax__tab_outer {
display:block !important;
}
.ajax__tab_tab{
/*min-width:200px;*/
width:200px;
height:auto !important;
}
</style>
.

Add this on top of your page or include it in your CSS and the tabs will appear vertically.

Now for a bit of explaining.
  • First of all this does not overwrite the CSS that the TabContainer loads because it is organized under a general ajax__tab_xp class like: .ajax__tab_xp .ajax__tab_header .
  • Then the width of 200px is arbitrary. I used it to keep the vertical tabs at the same width. I tried using min-width first, but it won't display right in Firefox.
  • Another point is about the ajax__tab_body class that I tried to set up first as float left, which would place the body div next to the tabs div, however this breaks if the body tab is wider and the content would appear underneath the tabs div. Thanks to my colleague Romeo I used the margin-left trick. 220px is enough to work in both IE and Firefox. It can be made smaller (closer to 200px)if the default IE body margin would be 0.
  • The !important keyword is placed to overwrite some settings that are already set up in the original TabContainer CSS.
  • Last issue: now the right panel will be truncated if it gets too large. You should control the overflow of that div, although, as far as I am concerned, my job is done


As a kind of disclaimer, I am not a CSS expert. If you know of a better way of doing this, please let me know.

I named this post so because I started researching something that a chat user asked me: how do you add UpdatePanels programatically to a page. You see, the actual problem was that he couldn't add controls to the UpdatePanel after adding it to the page and that was because the UpdatePanel is a templated control, in other words it contains one or more objects that inherit from ITemplate and all the control's children are part of these templates.

So, the required application is like this: A page that has a button that does nothing but a regular postback and another button that adds an UpdatePanel. Each update panel must contain a textbox and a button. When the button is pressed, the textbox must fill with the current time only in that particular UpdatePanel. If the regular postback button is pressed, the UpdatePanels must remain on the page.

What are the possible issues?
First of all, the UpdatePanels must survive postbacks. That means that you have to actually create them every time the page loads, therefore inside Page_Load. Note: we could add them in Page_Init and in fact that's where they are added when getting the controls from the aspx file of a page, but during Init, the ViewState is not accessable!
Then, there is the adding of the UpdatePanels. It is done in a Click event from a button, one that is done AFTER the Page_Load, therefore adding of an UpdatePanel must also be done there. Note: we could put the CreatePanels method in Page_LoadComplete, but then the controls in the update panel will not respond to any events, since the Load phase is already complete.
There is the matter of how we add the TextBox and the Button in each UpdatePanel. The most elegant solution is to use a Web User Control. This way one can visually control the content and layout of each UpdatePanel and also (most important for our application) add code to it!
Now there is the matter of the ITemplate object that each UpdatePanel must have as a ContentTemplate. This is done via the Page.LoadTemplate method! We you give it the virtual path to the ascx file and it returns an ITemplate. It's that easy!

Update:if you by any chance want to add controls programatically to the UpdatePanel, use the ContentTemplateContainer property of the UpdatePanel like this:
updatePanel.ContentTemplateContainer.Controls.Add(new TextBox());


Enough chit-chat. Here is the complete code for the application, the DynamicUpdatePanels page and the ucUpdatePanelTemplate web user control:
DynamicUpdatePanels.aspx.cs
using System;
using System.Web.UI;

public partial class DynamicUpdatePanels : Page
{
private int? _nrPanels;

public int NrPanels
{
get
{
if (_nrPanels == null)
{
if (ViewState["NrPanels"] == null)
NrPanels = 0;
else
NrPanels = (int) ViewState["NrPanels"];
}
return _nrPanels.Value;
}
set
{
_nrPanels = value;
ViewState["NrPanels"] = value;
}
}

protected void Page_Load(object sender, EventArgs e)
{
CreatePanels();
}

private void CreatePanels()
{
for (int i = 0; i < NrPanels; i++)
{
AddPanel();
}
}

private void AddPanel()
{
UpdatePanel up = new UpdatePanel();
up.UpdateMode = UpdatePanelUpdateMode.Conditional;
up.ContentTemplate = Page.LoadTemplate("~/ucUpdatePanelTemplate.ascx");
pnlTest.Controls.Add(up);
}

protected void btnAdd_Click(object sender, EventArgs e)
{
NrPanels++;
AddPanel();
}
}


DynamicUpdatePanels.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="DynamicUpdatePanels.aspx.cs"
Inherits="DynamicUpdatePanels" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>
Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:Panel ID="pnlTest" runat="server">
</asp:Panel>
<asp:Button ID="btnAdd" runat="server" Text="Add Panel" OnClick="btnAdd_Click" />
<asp:Button ID="btnPostBack" runat="server" Text="Postback" />
</form>
</body>
</html>


ucUpdatePanelTemplate.ascx.cs
using System;
using System.Web.UI;

public partial class ucUpdatePanelTemplate : UserControl
{
protected void btnAjax_Click(object sender, EventArgs e)
{
tbSomething.Text = DateTime.Now.ToString();
}
}


ucUpdatePanelTemplate.ascx
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="ucUpdatePanelTemplate.ascx.cs"
Inherits="ucUpdatePanelTemplate" %>

<asp:TextBox ID="tbSomething" runat="server"></asp:TextBox>
<asp:Button ID="btnAjax" runat="server" OnClick="btnAjax_Click" />


That's it, folks!

When one wants to indicate clearly that a control is to perform an asynchronous or a synchronous postback, one should use the Triggers collection of the UpdatePanel. Of course, I am assuming you have an ASP.Net Ajax application and you are stuck on how to indicate the same thing on controls that are insides templated controls like DataGrid, DataList, GridView, etc.

The solution is to get a reference to the page ScriptManager then use the method RegisterPostBackControl on your postback control. You get a reference to the page ScriptManager with the static ScriptManager.GetCurrent(Page); method. You get the control you need inside the templated control Item/RowCreated event with a e.Item/Row.FindControl("postbackControlID");

So, the end result is:

ScriptManager sm=ScriptManager.GetCurrent(Page);
Control ctl=e.Item/Row.FindControl("MyControl");
sm.RegisterPostBackControl(ctl);


Of course, if you want it the other way around (set the controls as Ajax async postback triggers) use the RegisterAsyncPostBackControl method instead.

Special thanks to Sim Singh from India for asking me to research this.

Update: this problem appeared for older versions of AjaxControlToolKit. Here is a link that says they fixed this issue since 21st of September 2007.

You are building this cool page using a TabContainer or some other AjaxControlToolKit control and everything looks smashing and you decide to add the UpdatePanels so that everything would run super-duper-fast. And suddenly the beautiful page looks like crap! Everything works, but your controls don't seem to load the cascading style sheet.
What is happening is that you make a control visible using update panels and so the CSS doesn't get loaded. I don't know exactly why, you would have to look into the AjaxControlToolKit source code and find out for yourself.

I found two fixes for this. The first is the nobrainer: add another TabContainer or AjaxControlToolKit control in the page, outside any updatepanels, make it visible, but set its style.display to 'none' or put it in a div or span with style="display:none". The second is the AjaxControlToolKit way. In the Page_Load event of the page or user control that contains the TabContainer or AjaxControlToolKit control add this line:
ScriptObjectBuilder.RegisterCssReferences(AjaxControlToolKit control);

This is part of the ExtenderControlBase class in AjaxControlToolKit, which is inherited by most if not all of their controls.

Now it should all work wonderfully.

I was building my nice little web app, you know: grids, buttons, ajax, stuff like that. And of course I had to create CSS classes for my controls, for example a button has the class of butt and the Send button has a class of buttsend. I agree it was not one of the most inspired CSS class name, but look what ajax made out of it:

Maybe it works for other IIS versions as well, but I certainly was looking for a way of turning it on on our Windows 2000 development/test computer. So this is the long story:
HOW TO: Enable ASPX Compression in IIS

and this is the short one:
Step 1: backup your site metabase
Go to the Internet Information Services (IIS) tab and right click on it, go to All Tasks, choose Backup/Restore Configuration and save it.

Step 2: make the change to the metabase
Create a .bat file that has the following content:
net stop iisadmin
cd C:\InetPub\adminscripts
CSCRIPT.EXE ADSUTIL.VBS SET W3Svc/Filters/Compression/GZIP/HcScriptFileExtensions "asp" "dll" "exe" "aspx"
CSCRIPT.EXE ADSUTIL.VBS SET W3Svc/Filters/Compression/DEFLATE/HcScriptFileExtensions "asp" "dll" "exe" "aspx"
net start w3svc


Make sure to restart the SMTP service or any others that were stopped by the bat. I don't know how to start it from the command line and I pretty much don't care. The batch file will notify you of possible services it will shut down, but will restart in the end only the Web service.

The performance is immediately visible and it also works with Ajax.

Update:
This article was originally talking about Windows XP. Thanks to McHilarant (see comment below) I realized that, even if the changes in the metabase are possible on any IIS5 (Windows XP and Windows 2000), the actual compression will not be possible on XP. I remembered then that the actual modification that I did that time was not on my dev machine, but on our office server, therefore I updated the post accordingly.

Another Update:
Here is a link about a script to enable IIS 6 gzip compression: Script to Enable HTTP Compression (Gzip/Deflate) in IIS 6.

Before Asp.Net Ajax was released I used to work with a library called AjaxPro (formerly Ajax.Net). It also wrapped specially decorated methods and sent them to the Page as javascript functions with a callback javascript function as the last parameter. In this library, by not using a callback you were saying that you want to execute the function synchronously, that you want to wait for a result. After all, that's a functionality included in the XmlHttpRequest object.

I was amazed to see that Asp.Net Ajax does not offer such an option. You NEED a callback function. So... how do you use a WebMethod as a javascript validation function, since the validators only accept a synchronous function?

The first idea I had was the easy way, to cycle inside the function until I had a result. Bad idea: Javascript itself is not really multitask, so it just took the CPU to 100% and that was the end of it: kill task. The second idea was the hard way: redo all code in the XmlHttpRequest wrapper and use the included synchronous functionality. Too complicated, although I found an article about how to do that. So here is the way I did it:
1. Get the validator object
2. Set a property on it to tell if the validator is inside an async call or not
3. Set a property to hold the last value that was validated
4. Set a property to hold the last result returned
5. Set a method of the validator as the call back function
6. If is in async return false
7. If the last value is the same with the current validating value, return last result
8. Execute the async validation function with the validator callback method as a parameter and return false (or "in async")

Now, the callback method just sets the result and clears the async flag and also updates the visual of the validator. By doing this I essentially don't allow postbacks during validation calls, which makes sense. I also had an idea of creating a special "in async" validator that would not allow postback and would display something nice, but the solution I am explaining keeps it local, with ValidationGroups and everything working just fine.

I will show the code in a few seconds, but first be warned that I am using a validator made by myself which expects null or true as valid and a string or false as invalid. If the result is a string, it displays it as the ErrorMessage. So, on with the code:
The function to get a reference to the validator (which in some cases, especially Ajax, is not the same as the span with the same id)
function getValidator(id)
{
if (typeof(Page_Validators)=='object')
for (c=0; c<Page_Validators.length; c++)
if (Page_Validators[c].id==id) return Page_Validators[c];
return false;
}


The preparing function, which can be reused for more validators. I couldn't find a better way to encapsulate this behaviour yet, please feel free to enlighten me with ideas
// parameters are the value to be validated 
// and the validator object
function prepareAsync(value,validator) {
if (!validator) {
validator.doReturn=true;
return 'Error in prepareAsync: validator not found!';
}
// it's validating
if (validator.inAsync) {
validator.doReturn=true;
return 'In async validation';
}
// it has validated this value before
if (validator.prevValue==value) {
validator.doReturn=true;
return validator.result;
}
// create the callBack function as a method
// of the validator object
if (!validator.callBack)
validator.callBack=function(res) {
validator.inAsync=false;
validator.result=res;
if (res==null) {
validator.isvalid=true;
} else
if (typeof(res)=='boolean') {
validator.isvalid=res;
} else {
// setting the validation message is
// as simple as changing the innerHTML
// of the validator span
validator.innerHTML=res;
validator.isvalid=false;
}
// that's an ASP.Net validator function
// since .NET 1.0 upwards
ValidatorUpdateDisplay(validator);
}
validator.inAsync=true;
validator.prevValue=value;
validator.doReturn=false;
}


and now a sample validation function:
// parameters are the value to be validated
// and the id of the validator
function ValidateProdotto(value,id) {
// get the validator object
var validator=getValidator(id);
// reuse this function to all validators in the page
var res=prepareAsync(value,validator);
// doReturn says if it has a result for us
if (validator.doReturn) return res;
// perform the actual validation
PageMethods.ValidateProdotto(value,validator.callBack);
// and return false, since we are in async now
return false;
}


Hope this helps somebody. This applies to short validations, but feel free to enhance my design with cancellations of running async operations in case the value is changed or with an array caching all the values tried and validated.

You have one beautiful page with Ajax.Net, UpdatePanels and the sorts. Then you go test it with FireFox and it doesn't work. Or you have some other reason for not wanting Ajax in certain situations, like for example people with no Javascript. So what do you do? How can you tell the page NOT to do Ajax postbacks?

The solution is to set ScriptManager's EnablePartialRendering to false. I used to do it with a Panel that was outside the UpdatePanel and in the page Init cycle I would move all controls from the update panel to this normal panel. And it worked, too.

I had to rewrite the entire post. It started from a nice article by a guy called Dan Wahlin and it ended with three (at least? :) ) separate links to his articles and his blog entered in my Technorati favourites.

Here are links to what appears to be a series about Asp.Net Ajax, really informative and concise:

Update Panel properties explained: Implement UpdatePanel Properties

Implement visual cues during updates:Inform Users With Customized Visual Feedback

Minimize the load on the server on many subsequent clicks or refresh requests:Coping With Click-Happy Users

Here is a complete list of the links in the same series:
ASP.NET AJAX Articles

It all started with my own library, a dll in which I wanted to include Javascript, CSS and ultimately images or flash files. I did it the only way I could in 1.1, mainly adding the resources to the project, setting them as Embedded Resource, then reading them and either put them in the page or write them in the application directory and link them in the page. As you can imagine, there were a lot of issues related to writing writes and so on.

But then .NET 2.0 and the AjaxControlToolkit arrived. This toolkit had this funny looking Tab thing, and it used images. So where did it get the images? I was surprised to see that the namespace of the TabContainer control was decorated with stuff like this:

[assembly: WebResource("AjaxControlToolkit.Tabs.tab.gif", "image/gif")]

then in the CSS files, stuff like

background-image:url(<%=WebResource("AjaxControlToolkit.Tabs.tab.gif")%>)

Could it be so easy? yes! And for the js files, they had this class called a ScriptControlBase and the only thing you needed to do to insert a javascript file was decorate the implementing class like this:

[ClientScriptResource("AjaxControlToolkit.TabPanel", "AjaxControlToolkit.Tabs.Tabs.js")]

But what was the underlying mechanism? Googling for WebResource.axd you get these informative links:
Using WebResource.axd for embedded resources
Accessing Embedded Resources through a URL using WebResource.axd

Working with Web Resources in ASP.NET 2.0

These three articles pretty much explain the basics, so I won't do anything but emphasize the more important points:
  • When you use the name of the resource, either when decorating the namespace or when getting the reference to it, use the project namespace and the folder in which the file is in, otherwise it will not work. So if you have the namespace MyControls.Web and you have the folder Images in which you embedded an Image.gif file, the name should be MyControls.Web.Images.Image.gif.
  • To programatically get the url for an embedded resource use Page.ClientScript.GetWebResourceUrl(Type type,string resourceName)
  • In order to get the contents of an embedded resource use code like this:
    Assembly assembly = GetType().Assembly;
    arr = assembly.GetManifestResourceNames();
    foreach (string name in arr)
    if (name==resourceName) {
    Stream s = assembly.GetManifestResourceStream(name);
    // do something with the stream
    break;
    }


But what is this WebResource.axd? It's an IHttpHandler, one that you can also implement quite easily. They are used to handle Ajax, file uploads, get access to all kinds of resources. Look it up. Somewhere in the near future I might write an article about these, too.

You are trying to use a WebMethod or a web service ScriptMethod in Javascript and you get an InvalidOperationException saying something about a circular reference. It happened to me when trying to read a DataTable in Javascript.

Why. The Javascript serialization of DataSets, DataTables and DataRows was available once in the ASP.Net Ajax web extensions. That's why you probably found a lot of Google results with people that could either only serialize DataSets, but not DataTables, or people that made it work by magic by adding some lines in the converters section of web.config, things that can't possibly work with your setup. Then, the option was removed in the final version of ASP.Net Ajax, only to be readded in the ASP.Net Futures, which is a test playground for future features of the platform.

What. There are several options, one being to reference an older version of ASP.Net Ajax and uses the converters there. But why bother? It's unlikely you use the DataTable or some other object in Javascript with all the options of the C# object. You probably just want to itterate through rows and read properties. So build your own converter.

How. Create a new library project. Add a class named DataTableConverter that inherits from JavaScriptConverter, and implement: IEnumerable<Type> SupportedTypes, IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer) and object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer).

You probably won't need to Deserialize anything, you can leave that unimplemented. The list of convertible types is easy enough, all you are left with is the Serialize code, which is actually very easy, too. Then all you need to do is add this in the web.config file:
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization >
<converters>
<add name="DataTableAjaxFix" type="AjaxTypeConverters.DataTableConverter"/>
</converters>
</jsonSerialization>


And here is the complete C# code of my DataTableConverter, but you can easily adapt it to anything:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Web.Script.Serialization;

namespace AjaxTypeConverters
{
public class DataTableConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new Type[] {typeof (DataTable)}; }
}

public override object Deserialize(IDictionary<string, object> dictionary, Type type,JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}

public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
DataTable listType = obj as DataTable;

if (listType != null)
{
// Create the representation.
Dictionary<string, object> result = new Dictionary<string, object>();
ArrayList itemsList = new ArrayList();
foreach (DataRow row in listType.Rows)
{
//Add each entry to the dictionary.
Dictionary<string, object> listDict = new Dictionary<string, object>();
foreach (DataColumn dc in listType.Columns)
{
listDict.Add(dc.ColumnName, row[dc]);
}
itemsList.Add(listDict);
}
result["Rows"] = itemsList;

return result;
}
return new Dictionary<string, object>();
}
}
}