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));

});

No comments: