Wahlin on .NET

Returning Complex Types from AJAX-Enabled Web Services

Dan Wahlin walks you through exactly how to return any object that contains sub-objects exposed through properties.

Over the past few weeks I've been writing about different ways that Web Services can be used by ASP.NET AJAX applications.  In this article I'll discuss how complex types written in C# or VB.NET can be returned to an AJAX client and used in a page. 

By complex type, I mean any object that contains sub-objects exposed through properties. The code below shows an example of a complex type named CustomerDetails that inherits from Customer and exposes an Address property of type Address. The Address type contains street, city, ZIP code and state information.

public class CustomerDetails : Customer
{
    public CustomerDetails()
    {
    }

    Address _Address;
    Gender _Gender = Gender.Unknown;

    public Address Address
    {
        get { return _Address; }
        set { _Address = value; }
    }

    public Gender Gender
    {
        get { return _Gender; }
        set { _Gender = value; }
    }
}

public enum Gender
{
    Unknown,
    Male,
    Female
}

public class Address
{
    public Address() { }

    string _Street;
    string _City;
    string _State;
    string _Zip;

    public string Street
    {
        get { return _Street; }
        set { _Street = value; }
    }        

    public string City
    {
        get { return _City; }
        set { _City = value; }
    }   
     
    public string State
    {
        get { return _State; }
        set { _State = value; }
    }

    public string Zip
    {
        get { return _Zip; }
        set { _Zip = value; }
    }
}

public class Customer
{
    private string _CustomerID;
    private string _ContactName;
    private string _CompanyName;
    private string _Country;

    public Customer() { }

    public string Country
    {
        get { return _Country; }
        set { _Country = value; }
    }

    public string CompanyName
    {
        get { return _CompanyName; }
        set { _CompanyName = value; }
    }

    public string CustomerID
    {
        get { return _CustomerID; }
        set { _CustomerID = value; }
    }

    public string ContactName
    {
        get { return _ContactName; }
        set { _ContactName = value; }
    }
}

The Web service proxy object generated by the ASP.NET AJAX ScriptManager automatically allows access to properties defined within the CustomerDetails class shown above.  However, if you want to use the Address class as a standalone object, there are additional steps you must take.  Fortunately, ASP.NET AJAX includes an attribute named GenerateScriptType that will do all of the heavy lifting for you.

Listing 1 shows an example of a Web method named GetCustomerDetails() that exposes the CustomerDetails object shown above. 

After referencing the service using the ScriptManager (see my previous article on consuming Web services with ASP.NET AJAX here), you can call the GetCustomerDetails() Web method and access the returned object's properties directly using JavaScript as shown in Listing 2.

If you want to use the Address type as a standalone object, you'll quickly find that you can't by default. AJAX-enabled Web services expose types returned from a Web method and allow access to nested members. However, the types that are nested are not directly available as standalone types. This means that you can't create a new instance of the Address type on the client side and pass it back to the Web service when updates are needed.

To make the Address type available on the client side as a standalone type, the GenerateScriptType attribute can be applied to the Web service class as shown here:

[ScriptService]
[GenerateScriptType(
  typeof(Address))]
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class CustomerService :
  WebService

{

}

By adding the GenerateScriptType attribute and specifying that the Address type should be exposed, the client-side proxy generated by the ScriptManager control will make the Address type available as a standalone type that can be accessed directly without having to go through CustomerDetails.  This can be useful when you want to update a specific sub-object of CustomerDetails such as Address. Listing 3 shows an example of accessing the Address type directly on the client and using it to fill a CustomerDetails object with data.

By using the GenerateScriptType attribute, you can easily expose sub-types to the client side, allowing more flexibility in how the types are used.  Other types (such as enums) can be exposed as well using GenerateScriptType.   

About the Author

Dan Wahlin (Microsoft MVP for ASP.NET and XML Web Services) is the founder of The Wahlin Group which specializes in .NET and SharePoint onsite, online and video training and consulting solutions. Dan also founded the XML for ASP.NET Developers Web site, which focuses on using ASP.NET, XML, AJAX, Silverlight and Web Services in Microsoft's .NET platform. He's also on the INETA Speaker's Bureau and speaks at conferences and user groups around the world. Dan has written several books on .NET including "Professional Silverlight 2 for ASP.NET Developers," "Professional ASP.NET 3.5 AJAX, ASP.NET 2.0 MVP Hacks and Tips," and "XML for ASP.NET Developers." Read Dan's blog here.

comments powered by Disqus
Upcoming Events

.NET Insight

Sign up for our newsletter.

I agree to this site's Privacy Policy.