WCF + Tasks
In WCF we can use the APM pattern to create an asynchronous client. For example, consider the following service contract:
public interface IHello
{
[OperationContract]
string Greet(string name);
}
An APM-enabled version of this interface would look like this:
public interface IHelloApm
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGreet(string name, AsyncCallback asyncCallback, object asyncState);
string EndGreet(IAsyncResult asyncResult);
}
WCF’s client can automatically generate a proxy that implements this interface (e.g. by inheriting from ClientBase<IHelloApm>).
However, in .NET 4.0, we now use Tasks, which provide a far more convenient API than APM. Fortunately, there’s an easy way to convert one to the other, by using the FromAsync methods in TaskFactory. This would require you to:
- Create the above APM interface.
- Create a client class.
- Wrap each method pair (Begin & End) in a method that calls FromAsync and returns a Task.
I decided this was way too much of a hassle, and apparently the good folks at Microsoft thought along the same lines. One of the samples in the Async CTP contains an IWsdlImportExtension (called TaskWsdlImportExtension) that causes SvcUtil (the same mechanism used by “Add Service Reference” in VS) to generate methods that return Tasks. If you’re using SvcUtil to generate your proxies, you’re good to go. You can use the sample generator even without relying on the CTP itself.
But what if you write your own interfaces? Wouldn’t it be nice if you could simply create the following interface and have the runtime figure it out for you?
public interface IHelloAsync
{
[OperationContract]
Task<string> Greet(string name);
}
Side (but important) note: You may ponder – why not just use Task.Factory.StartNew() method and pass a delegate that calls the original (synchronous) method? Because then you’d be wasting a thread that will be kept waiting for I/O! .NET utilizes I/O Completion Ports when you use the APM methods, which provides an efficient way of waiting for I/O to complete.
Introducing TaskClient<T>
TaskClient is very much like ClientBase (in fact, it implements the same interface, ICommunicationObject), only it uses code generation (Reflection Emit) to generate both the async interface and a class that implements the above (IHelloAsync) interface, by invoking FromAsync for each method. Sample usage:
taskClient.Channel.Greet(“Seattle”).ContinueWith(t => Console.WriteLine(t.Result));
Channel is IHelloAsync, and Greet returns a Task. We use a continuation to write the result to the console. When combined with Async CTP’s await keyword, this makes calling services that much easier.
The generated class looks something like this:
{
private readonly Func<IHelloApm> _channel;
public HelloAsyncClient(Func<IHelloApm> channel)
{
_channel = channel;
}
public Task<string> Greet(string name)
{
IHelloApm channel = _channel();
return
Task.Factory.FromAsync(
new Func<string, AsyncCallback, object, IAsyncResult>(channel.BeginGreet),
new Func<IAsyncResult, string>(channel.EndGreet), name, null, TaskCreationOptions);
}
public TaskCreationOptions TaskCreationOptions { get; set; }
}
Note that the channel is lazily evaluated on each call. This allows for more sophisticated channel management options.
Known limitations:
- TaskClient currently won’t handle overloaded methods in the interface.
- Ref/Out parameters are not supported (nor will they be; they do not make sense in async interfaces).
- The interface must be public.
A word of caution: While the code attached to this post works, it wasn’t thoroughly tested. So, if you would like to use this in a production environment, we are planning on making it available in a future release WCF Contrib. This is a well established library of WCF extensions. I suggest checking it out, and waiting for more news.
Attachment: ServiceModelTasks.zip
Tags
.NET 4 Animation AppFabric Async Axum Blog C# ClearType Cloud CLR CodeValue Contests Deep Zoom Experiments Generics Google Ink Lectures Modeling Performance Personal Pivot Prism Programming Languages Prolog Reflector RTL Sela Silverlight The Arbel Network Themes Threading Tips Visual Studio WCF Windows 7 Windows 2003 Windows Azure Windows Forms Windows Phone Windows Vista Windows XP WPF XAML ZuneArchives
- May 2013
- February 2013
- June 2012
- May 2012
- June 2011
- November 2010
- August 2010
- July 2010
- June 2010
- March 2010
- December 2009
- November 2009
- February 2009
- January 2009
- December 2008
- November 2008
- October 2008
- September 2008
- August 2008
- November 2007
- September 2007
- June 2007
- May 2007
- February 2007
- November 2006
- October 2006
- February 2006
- August 2005
- February 2005
- August 2004
- July 2004
- June 2004
- May 2004





