Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
Markdown Monster - The Markdown Editor for Windows

'My Ajax.NET' library from Jason Diamond


:P
On this page:

I spent a bit of time playing around with Jason Diamonds My AJAX.NET library in light of my Portland .NET User group session tonight. Although the talk is on Script Callbacks in ASP.NET 2.0 I wanted to also show a number of ways to do the same thing in ASP.NET 1.1.

 

I had looked previously at Michael Schwarz’s Ajax.NET library which is similar. What’s nice about Jason’s library is that it’s much more compact, comes with source code, and is beautiful in its simplicity.

 

Some of the features:

 

  • Attribute Based
    Add an attribute to a method and it becomes client callable.


  • Mapped Client Object
    The client side implements a class that matches methods for all of your attributed server methods. Methods have the same signature as the server equivalent (plus an extra parameter to specify the callback function to receive the result)


  • Result Marshalling
    The result from a server method is marshaled to a real type. Most simple types are supported as are DataSet/DataTable/DataRow, IEnumable (arrays of simple types). Currently there’s no support for complex types.


  • Exception Marshalling
    Exceptions can be marshaled to the client as well. (I had to change the behavior to use innerException data to get meaningful messages)


  • Tied into the Page framework
    The library hooks into the current page framework and participates in regular POSTBACK behavior. This means when you all the Ajax method on the server, you get full page state including control state, so you can read form controls (this.txtName.Text). This is great because you don’t have to pass parameters in many cases as the page is in context. On the downside, every request is a POST which increases the size of data going to the server and there’s no way to disable that.


  • Fully self contained
    The entire library is contained in a small source file. Sweet and simple – you can add a single source file to your project and off you go. There are no external dependencies on HTTP Handlers, and no script resources that load, everything is self contained in a single page.

 

I whipped up a  quick sample using the Northwind database in a couple of hours that does display and updates to the NW Customer table. You can take a look and check out the code that goes with the sample, which is surprisingly little. In fact, I think there’s actually less code in this AJAX implementation than it would have taken using a plain ASP.NET implementation.

 

I ended up modifying a few things in the library to add support for DBNull and passing full exception messages back to the client, but overall the base code works great.

 

What I really like is the fact that you can pass back common .NET types like DataSet/DataTable/DataRow as objects, that are picked up on the client using the same object hierarchy. So you can actually talk to an object on the client like this:

 

<script type="text/javascript">

var CustRow = null;

 

function GetCustomerListCallback(Result)

{

    var Table = Result.value; // DataTable

    var List = document.getElementById('lstCustomers');

   

    if (List == null)

        return;

   

    for (x=List.options.length-1; x > -1; x--)

    {

        List.remove(0);

    }

           

    for (x=0; x < Table.Rows.length; x++ )

    {

        var Row = Table.Rows[x];  // Mozilla needs to assign

       

        var option = document.createElement("option");

            option.text = Row.CompanyName;

            option.value = Row.CustomerId;

 

            if ( window.navigator.appName.toLowerCase().indexOf("microsoft") > -1)

                List.add(option); 

            else

                List.add(option, null);

     }

   

    // *** Show First Item

    if (List.length > 0)

    {

        List.selectedIndex = 0;

        List.onchange();

    }

}

function GetCustomerRowCallback(Result)

{

    CustRow = Result.value;  // DataRpw

   

    AssignValue( "txtContactName",CustRow.ContactName);

    AssignValue( "txtCompany",CustRow.CompanyName);

    AssignValue( "txtAddress",CustRow.Address);

    AssignValue( "txtCity",CustRow.City);

    AssignValue( "txtCountry",CustRow.Country);

    AssignValue( "txtRegion",CustRow.Region);

    AssignValue( "txtPostalCode",CustRow.PostalCode);

   

    var TitleSpan = document.getElementById("DialogTitle");

    if (TitleSpan)

        TitleSpan.innerHTML = CustRow.CompanyName;

   

}

function AssignValue(ControlName,Value)

{

    if (Value == null)

        Value = "";

       

    var Ctl = document.getElementById(ControlName);

    if (Ctl)

        Ctl.value = Value;

}

function SaveCustomerCallback(Result)

{

//    if (Result.error)

//    {

//        alert(Result.error);

//        return;

//    }

    if (Result.value == null)

        return;

        

    if (Result.value)

        alert("Customer Saved!");

    else

       alert("Result.value.error");

}

</script> 

 

To trigger a server requests and get these callbacks called you can use simple functions like this:

 

<script type="text/javascript">

Callback.GetCustomerList(GetCustomerListCallback);

</script> 

 

which is the same method signature as on the server, plus the name of the callback function on the client to call.

 

The DataTable and DataRow ‘serializations’ are not full object copies of the server side counterparts, they are meant to only transfer the data to the client, so you only get Rows and Values, not the whole rest of the object hierarchy.

 

Current objects results are not supported but I’m sure either Jason or somebody in the community will provide an implementation in short order.

 

The server code for the class is minimal too:

 

public partial class CustomerList : System.Web.UI.Page

{

    protected void Page_Load(object sender, EventArgs e)

    {

      

            Ajax.Manager.Register(this, "Callback", Ajax.Debug.Errors);

    }

 

    [Ajax.Method]

    public DataTable GetCustomerList()

    {

        busCustomer Customer = new busCustomer();

        if (Customer.GetCustomerList() < 0)

            return null;

 

        return Customer.DataSet.Tables["TCustomerList"];

    }

 

    [Ajax.Method]

    public DataRow GetCustomerRow(string CustomerId)

    {

        busCustomer Customer = new busCustomer();

        if (!Customer.Load(CustomerId))

            return null;

 

        return Customer.DataRow;

    }

 

    [Ajax.Method]

    public bool SaveCustomer()

    {

        string CustomerId = Request.Form["lstCustomers"];

 

        busCustomer Customer = new busCustomer();

 

        if (CustomerId == null)

            throw new ApplicationException("Invalid CustomerId");

       

        if (CustomerId == "")

        {

            if (!Customer.New())

                throw new ApplicationException("Couldn't create new customer.");

            ;

        }

        else

        {

            if (!Customer.Load(CustomerId))

                throw new ApplicationException("Couldn't load customer");

        }

 

        Customer.Entity.Contactname = this.txtContactName.Text;

        Customer.Entity.Companyname = this.txtCompany.Text;

        Customer.Entity.Address = this.txtAddress.Text;

        Customer.Entity.City = this.txtCity.Text;

 

        if (!Customer.Validate())

            throw new ApplicationException(Customer.ValidationErrors.ToString());

 

        if (!Customer.Save())

            throw new ApplicationException(Customer.ErrorMessage);

 

        return true;

}

}

 

This sample is ASP.NET 2.0 (because the session I’m doing is on script callbacks in ASP.NET 2.0 mainly), but the above code works the same in 1.1. I think this sample is taking no more code than the equivalent ASP.NET server code would have taken. In fact, if I used my custom data controls on the form I could even take advantage of custom databinding and reduced the code even further. Slick.

 

I actually ran into a post from Peter Bromberg over at Egghead Café, which turned me on to Jason’s library. Peter has an interesting take on the whole AJAX terminology which I tend to agree with, but then again, let’s not get wrapped up in terminology. Remote Scripting, Callbacks, AJAX – it’s all good. With tools like Ajax.NET and the Jasons My Ajax.NET library

 

 Jason put the thing out as a sample, it’s not meant as a ‘product’. There’s no license, no copyright – it’s free, use it as you see fit. It’s as is although Jason has been responding to queries and provided a number of fixes.

 


The Voices of Reason


 

Sonu Kapoor
July 27, 2005

# re: 'My Ajax.NET' library from Jason Diamond

Its actually Michael Schwarz not Steve Schwarz :)

Rick Strahl
July 27, 2005

# re: 'My Ajax.NET' library from Jason Diamond

Wrong Schwarz. Steve's the Indigo guy... <g> Fixed. Thanks.

J.Gregory
July 28, 2005

# re: 'My Ajax.NET' library from Jason Diamond

Just thought I'd point out that your quick sample link is broken, the url is doubled.

Rick Strahl's WebLog
July 29, 2005

# Some Ajax for .NET Tool Thoughts

There's a lot of variety in the various 'Ajax' implementation for .NET and a lot of discussion of which is better. The way I see it there are two major approaches that are complimentary to each other: An engine that is part of the ASP.NET page processing engine (Page Context driven - examples Script Callbacks in ASP.NET 2.0, My Ajax.NET) and a URL based approach that allows going to other pages to retrieve content. The latter is not discussed much but I think a very important one to feed data from the server in a more 'data driven' mechanism rather than as a UI engine.

Azeem
October 03, 2005

# re: 'My Ajax.NET' library from Jason Diamond

Hi,

Can anyone list or tell the link where i can find the properties of the objects that are returned from server to client? There are a bit different property names like in case of a DataTable, we use TableName property at server but it doesn't work in JS. Please guide if i'm wrong

Thanks

Azeem Fraz.

Rick Strahl
October 03, 2005

# re: 'My Ajax.NET' library from Jason Diamond

Use an HTTP proxy like Fiddler to look at the data sent back and you can see exactly what properties the objects have. DataTable and DataRow are very simplified and basically just return the data arrays, none of the functional aspects.

steve
October 04, 2005

# re: 'My Ajax.NET' library from Jason Diamond

can any 1 tel me how to use the redirect to another page using AJAX wen i click a button...

pls tel me in both ways serverside and client side..

steve

DB
October 23, 2005

# re: 'My Ajax.NET' library from Jason Diamond

I used The AjaxButton on a usercontrol placed on a page both the page and usercontrol have thr register method but still the callback on the usercontrol never reached , have any Ideas???

TweeZz
May 21, 2006

# ANTHEM

'My Ajax.NET' doesn't exist anymore. It's now called Anthem. Check out the url.
http://forums.anthemdotnet.com/forums/index.php

Rick Strahl's Web Log
February 17, 2007

# Some Ajax for .NET Tool Thoughts - Rick Strahl's Web Log

There's a lot of variety in the various 'Ajax' implementation for .NET and a lot of discussion of which is better. The way I see it there are two major approaches that are complimentary to each other: An engine that is part of the ASP.NET page processing engine (Page Context driven - examples Script Callbacks in ASP.NET 2.0, My Ajax.NET) and a URL based approach that allows going to other pages to retrieve content. The latter is not discussed much but I think a very important one to feed data fr

# DotNetSlackers: 'My Ajax.NET' library from Jason Diamond


West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024