Friday, October 3, 2008

Web Service/ WCF callouts and async page support in ASP.NET 2.0

With asynchronous page support in ASP.NET, we can register one or more tasks with the RegisterAsyncTask method for the runtime to execute asynchronously. In this article I will explain how to use the async page support in ASP.NET for calling web services/ WCF services to get the data for processing.

WEB SERVICE

We will create a simple Web Service method as:

public class CustomerService : System.Web.Services.WebService

{

[WebMethod]

public Collection<Customer> GetCustomers()

{

return new Collection<Customer>

{

new Customer { CustomerID = 1, CustomerName = "Prajeesh" },

new Customer { CustomerID = 2, CustomerName = "Sachin" },

new Customer { CustomerID = 3, CustomerName = "Rahul" },

new Customer { CustomerID = 4, CustomerName = "Varun" },

new Customer { CustomerID = 5, CustomerName = "Rachel" },

new Customer { CustomerID = 6, CustomerName = "Monica" },

new Customer { CustomerID = 7, CustomerName = "Micheal" },

new Customer { CustomerID = 8, CustomerName = "John" }

};

}

}

[Serializable]

public class Customer

{

public Int32 CustomerID { get; set; }

public String CustomerName { get; set; }

}

And the proxy class generated for this web service has the Asynchronous methods generated for the GetCustomers method.

Now Compared to VS 2005 proxy generation one major difference in VS 2008 is the missing of BeginXXX and EndXXX methods. All we get for asnyc processing is:

<>

public event GetCustomersCompletedEventHandler GetCustomersCompleted;

public void GetCustomersAsync() {

this.GetCustomersAsync(null);

}

public delegate void GetCustomersCompletedEventHandler(object sender, GetCustomersCompletedEventArgs e);

public partial class GetCustomersCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs {

private object[] results;

internal GetCustomersCompletedEventArgs(object[] results, System.Exception exception, bool cancelled, object userState) :

base(exception, cancelled, userState) {

this.results = results;

}

public Customer[] Result {

get {

this.RaiseExceptionIfNecessary();

return ((Customer[])(this.results[0]));

}

}

}

Now in the asp.net code behind file to access this method we need to add few lines like:

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

{

CollectionCustomer> customers;

CustomerServiceHost.CustomerService service;

protected void Page_Load(object sender, EventArgs e)

{

if (!Page.IsPostBack)

{

PreRenderComplete += new EventHandler(

delegate

{

_customerGridView.DataSource = customers;

_customerGridView.DataBind();

_resultLabel.Text = "Sucess";

});

service = new AsyncWebApplication.CustomerServiceHost.CustomerService();

service.GetCustomersCompleted +=

new AsyncWebApplication.CustomerServiceHost.GetCustomersCompletedEventHandler(

delegate(Object s, AsyncWebApplication.CustomerServiceHost.GetCustomersCompletedEventArgs ce)

{

customers = new CollectionCustomer>(ce.Result.ToList());

});

service.GetCustomersAsync();

}

}

public override void Dispose()

{

if (service != null) service.Dispose();

base.Dispose();

}

}

WCF SERVICE

Our WCF Service consists of a ServiceContract and a DataContract like:

[ServiceContract]

public interface ICustomerWCFService

{

[OperationContract]

Collection<WCFCustomer> GetCustomers();

}

[DataContract]

public class WCFCustomer

{

[DataMember]

public Int32 CustomerID { get; set; }

[DataMember]

public String CustomerName { get; set; }

}

And the Service implementation is like

public class CustomerWCFService : ICustomerWCFService

{

public Collection<WCFCustomer> GetCustomers()

{

return new Collection<WCFCustomer>

{

new WCFCustomer { CustomerID = 1, CustomerName = "Prajeesh" },

new WCFCustomer { CustomerID = 2, CustomerName = "Sachin" },

new WCFCustomer { CustomerID = 3, CustomerName = "Rahul" },

new WCFCustomer { CustomerID = 4, CustomerName = "Varun" },

new WCFCustomer { CustomerID = 5, CustomerName = "Rachel" },

new WCFCustomer { CustomerID = 6, CustomerName = "Monica" },

new WCFCustomer { CustomerID = 7, CustomerName = "Micheal" },

new WCFCustomer { CustomerID = 8, CustomerName = "John" }

};

}

}

Now the proxy class generated using the SVCUTIL with Asynchronous options gives you the BeginXXX and EndXXX methods on which we can use the PageAsyncTask method for asp.net asnyc processing.

Code:

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

{

PageAsyncTask customerGetAsyncTask;

ListWCFCustomer> wcfCustomers;

CustomerWCFServiceProxy.ICustomerWCFService wcfService;

protected void Page_Load(object sender, EventArgs e)

{

if (!Page.IsPostBack)

{

PreRenderComplete += new EventHandler(

delegate

{

_customerGridView.DataSource = wcfCustomers;

_customerGridView.DataBind();

_resultLabel.Text = "Sucess";

});

wcfService = new CustomerWCFServiceProxy.CustomerWCFServiceClient();

}

customerGetAsyncTask = new PageAsyncTask(

delegate(Object beginSender, EventArgs beginArgs, AsyncCallback asynCb, Object asyncState)

{

return wcfService.BeginGetCustomers(asynCb, asyncState);

},

delegate(IAsyncResult asynEndResult)

{

wcfCustomers = wcfService.EndGetCustomers(asynEndResult).ToList();

},

delegate(IAsyncResult asynTimeOutResult)

{

_resultLabel.Text = "Timeout!!!";

},

null);

RegisterAsyncTask(customerGetAsyncTask);

}

}

Note: You can also implement parallel processing for asynchronous methods using the PageAsyncTask methods by passing true as parameter in the overloaded method.

No comments: