Showing posts with label Web Services. Show all posts
Showing posts with label Web Services. Show all posts

Friday, August 14, 2009

WCF - Event-based asynchronous pattern

WCF Guidance for WPF Developers

Asynchronous proxies generated with svcutil support two modes of asynchronous operations: delegate-based opertations and event-based operations. Delegate-based asynchronous operations follow the traditional asynchronous delegate pattern whereby each call is broken into two: a begin operation, and an end operation.

Eg:

[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IProjectService/GetProjects", ReplyAction="http://tempuri.org/IProjectService/GetProjectsResponse")]

System.Collections.ObjectModel.ObservableCollectionProject> GetProjects();

[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IProjectService/GetProjects", ReplyAction="http://tempuri.org/IProjectService/GetProjectsResponse")]

System.IAsyncResult BeginGetProjects(System.AsyncCallback callback, object asyncState);

System.Collections.ObjectModel.ObservableCollectionProject> EndGetProjects(System.IAsyncResult result);

The drawback of the delegate-based asynchronous pattern is that every callback must synchronize access to UI components, and to other instance members belonging to the main Window. This requires developers to write synchronization logic which quickly adds to code clutter, and can become hard to follow. The event-based pattern solves this problem by exposing an event that is executed on the UI thread that can be used to notify the client about the completion of the operation. This logic is encapsulated in the proxy. You can use the svcutil tool with the /async /targetClientVersion:Version35 option to generate proxies with Async event support.

This option adds a EventArgs type that inherits from the AsyncCompletedEventArgs type for each asynchronous operations on the service. Later in the code you can use the event based asynchronous pattern to as given in the example below to query the service methods.

__AsyncProxy = new WCFSampleProjects.Proxies.Async.ProjectServiceClient("ProjectServiceAsync");

__AsyncProxy.InnerChannel.Faulted += new EventHandler(AsyncProxyFaulted);

__AsyncProxy.GetProjectsAsync();

__AsyncProxy.GetProjectsCompleted += new EventHandlerGetProjectsCompletedEventArgs>((y, z) =>

{

var __Projects = z.Result;

__Projects.ToList<Project>().ForEach(item => Console.WriteLine(item.Title));

});

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.