Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Keeping your solution clean with AJAX and SOAP

3.00/5 (7 votes)
5 Jul 2007CPOL4 min read 1   122  
How to benifit from JavaScript object serialization and Web Services without knowing anything about them.

Introduction

The article assumes that the reader is using and has general knowledge of the ASP.NET AJAX framework.

Get it? Keeping your solution "clean" with "AJAX and SOAP"? Anyway, this article was originally titled "Super Simple JSON with ASP.NET AJAX", but I was being somewhat liberal with my use of the term "JSON" (though no more liberal than the way I have seen others use the term "AJAX"). The real title of the article should be something like "How to take advantage of a Web Service that returns JavaScript objects without having to worry about serialization or Web Services." Or maybe, it should be "Super Simple Serialization" to take advantage of alliteration. Or maybe even, "Calling Web Services from Client Script in ASP.NET AJAX" (though I think that one is already taken). The true reason for the current title will be revealed at the end of the article. In any case, this is the easiest way I have found to take advantage of AJAX without having to think about a Web Service layer and without having to worry about serializing or deserializing the objects that I am already using.

The following example uses JavaScript to call a method on its "host" page which will return a person object and display information about that person in a popup box. The example is contained in one ASPX page for simplicity.

Using the code

First, the code-behind

C#
using System;
using System.Web.UI;
using System.Web.Services;

namespace AJAXExample
{
    public partial class _Default : Page
    {
        public class Person
        {
            // Person

            public Person(string name, DateTime birthDate, Person[] friends)
            {
                this.name = name;
                this.birthDate = birthDate;
                this.friends = friends;
            }

            // Name

            private string name;
            public string Name
            {
                get { return name; }
            }

            // BirthDate

            private DateTime birthDate;
            public DateTime BirthDate
            {
                get { return birthDate; }
            }

            // Age

            public int Age
            {
                get { return DateTime.Now.Year - BirthDate.Year; }
            }

            // Friends

            private Person[] friends;
            public Person[] Friends
            {
                get { return friends; }
            }
        }

        // Page_Load

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

        // GetPerson

        [WebMethod]
        public static Person GetPerson()
        {
            Person friend1 = new Person("friend one", DateTime.Now, null);
            Person friend2 = new Person("friend two", DateTime.Now, null);
            return new Person("person name", DateTime.Parse("7/4/1980"), 
                new Person[] { friend1, friend2 });
        }
    }
}

Explanation of the code-behind

The first thing you will notice is the definition of a Person class. This class, of course, could be anywhere, and best practices would say that it is probably in its own file. Either way, things to notice about it are that all the properties are read only, one of the properties is a collection, and there is even a calculated field. The fields don't need to be read only, but the class has been designed that way to show that any class can be serialized into a JavaScript object.

The only method on the page is the GetPerson() method which returns a new instance of a person when called. You will notice that the method is static, public, and marked with the WebMethod attribute. This is all that is needed to make the method accessible to the JavaScript on the page. Calling this method will return a proxy object that highly resembles the Person class described in the previous paragraph. Because the object is returned to its caller as a JavaScript object, the properties will no longer be read only, calculated fields will no longer have logic behind them, and all methods on the object will no longer be present but all of the data will persist in the same structure (hierarchy), even the properties that are collections.

Now, the ASPX page

ASP.NET
<%@ Page Language="C#" AutoEventWireup="true" 
    CodeBehind="Default.aspx.cs" 
    Inherits="AJAXExample._Default" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>AJAX Example</title>
        <script type="text/javascript">

        // GetPerson

        function GetPerson() 
        {
            PageMethods.GetPerson(OnGetPersonSucceeded);
        }

        // OnGetPersonSucceeded

        function OnGetPersonSucceeded(result, userContext, methodName) 
        {
            alert("name: " + result.Name 
            + "\r\nbirthdate: " + result.BirthDate 
            + "\r\nage: " + result.Age + "\r\nfriends: " 
            + result.Friends.length);
        }
        
        </script>
    </head>
    <body>
        <form id="form" runat="server">
            <asp:ScriptManager 
                ID="scriptManager" 
                runat="server" 
                EnablePageMethods="true">
            </asp:ScriptManager>
            <input type="button" onclick="GetPerson();" value="get person" />
        </form>
    </body>
</html>

Explanation of the ASPX page

The first thing to notice is that there is one, and only one, ScriptManager on the page, and its EnablePageMethods property is set to true. Setting this property to true is what allows the JavaScript on the page to "see" the static method we created in the code-behind. A PageMethods object is then created by the ScriptManager that allows access to the code-behind method. The only element on the page is an HTML button that calls the JavaScript function GetPerson(). The JavaScript function GetPerson() is really just a pass through method that uses the PageMethods object to call the GetPerson() method in the code-behind. PageMethod.GetPerson accepts several parameters including callback functions for both success and failure. This implementation assumes success every time, and thus only passes in the OnGetPersonSucceeded function as the first parameter. The Person class from the GetPerson method in the code-behind (the static Web Service method) is returned to the OnGetPersonSucceeded as a JavaScript object. The first parameter of this method (result) is actually the serialized Person object, and its properties have been populated with the data from the code-behind object.

Screenshot - simpleAJAXExample.jpg

Summary

That is all there is to it. No extensive JSON, serialization, or Web Service experience is necessary, just a ScriptManager with its EnablePageMethods property set to true and a public, static method with a WebMethod attribute. Here is the best part and the true reason for the title of this article, testing is easier now. JavaScript can be hard to code and debug, and even harder to test. The method described above allows for more logic to be moved to the code-behind, which in turn allows for the help of a compiler, and allows much easier access by testing software such as NUnit. I'm a big believer in keeping as much logic out of the UI as possible, and this seems like a great way to reduce some of that hairy JavaScript code and to keep a project "clean".

Resources

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)