On the course of last few months, I’ve been working with Craig Neuwirt, on what I consider one of the coolest additions to Castle WCF Integration Facility.
Problem
As you probably know by default all WCF calls are synchronous – you make a request, under the cover WCF blocks your thread using a WaitHandle waiting for response, then it unblocks your threads making it look like a local call. This makes things simple for a programmer, who does not have to deal with synchronization, but it’s an overkill from scalability and performance perspective.
There are also one way calls, often mistakenly called ‘fire and forget’ which are still synchronous, but return control to your thread as soon as they get confirmation from the other end that message was received.
There are also actual asynchronous calls, but to take advantage of this you have to either use svcutil to generate your code, or build asynchronous versions of your contracts manually, which is tedious, forces you to remember quite a lot details about how asynchronous contracts should look like, and there’s no way compiler will tell you your sync and async contracts are out of sync (no pun intended).
Solution
Using trunk version of WCF Facility you can take advantage of a new mechanism that lets you perform asynchronous WCF calls having just the synchronous contract. Let me show you an example.
Contract project holds the service contract that both client and service share:
[ServiceContract]
public interface IMyService
{
[OperationContract]
string MyOperation(string message);
}
Notice there’s no asynchronous version of the operation.
Service project contains only simple implementation of the contract plus console host.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService
{
public string MyOperation(string message)
{
Console.WriteLine("Called non one way operation... with " + message);
Thread.Sleep(1000);
Console.WriteLine("Done calculating");
return message.ToUpperInvariant();
}
}
It uses Thread.Sleep to simulate some lengthy operation, so that we can actually see that client does not wait for the end of the operation.
The service host uses WCF Facility to configure the service:
class Program
{
static void Main(string[] args)
{
using (StartService())
{
Console.WriteLine("Running");
Console.ReadKey(true);
}
}
private static IWindsorContainer StartService()
{
return new WindsorContainer()
.AddFacility<WcfFacility>()
.Register(Component.For<MyService>().ActAs(
new DefaultServiceModel().AddEndpoints(
WcfEndpoint.ForContract<IMyService>()
.BoundTo(new NetTcpBinding())
.At("net.tcp://localhost/Service"))));
}
}
Client project is even simpler:
class Program
{
static void Main()
{
var container = ConfigureContainer();
var client = container.Resolve<IMyService>("operations");
for(int i=0;i<10;i++)
{
Console.WriteLine("Asking: " + i);
client.BeginWcfCall(
s => s.MyOperation("Operation for " + i.ToString()),
asyncCall => Console.WriteLine(asyncCall.End()),
null);
}
Console.ReadKey(true);
}
private static WindsorContainer ConfigureContainer()
{
var container = new WindsorContainer();
container.AddFacility<WcfFacility>().Register(
Component.For<IMyService>()
.Named("operations")
.ActAs(new DefaultClientModel
{
Endpoint = WcfEndpoint.
BoundTo(new NetTcpBinding()).
At("net.tcp://localhost/Service")
}));
return container;
}
}
It configures Windsor container and WCF Facility, then it obtains client proxy for the service (again, synchronous contract) and uses some WCF Facility magic to perform calls asynchronously. Let’s run it and see:
As you can see, on the client we first issued all 10 requests, then we gradually received responses from the server.
So how do I use it?
Discussion
As you can see in the code above, instead of calling MyOperation directly on proxy I used BeginWcfCall extension method from WCF Facility and passed there a delegate with invocation of the method, plus two more arguments. The second and third arguments can be either AsyncCallback, and object, like in standard .NET async pattern, or (as in my example) IWcfAsyncCall<T> (or it’s non-generic version for methods that don’t return any value).
IWcfAsyncCall itself inherits from IAsyncResult and adds convenience methods to end async invocation. The overload with out arguments are there to handle methods that have ref or out arguments. Yes – this means you can use that also for methods with out and ref arguments. One more noteworthy feature is usage of SynchronisationContext, which means it’s safe to update WinForms/WPF GUI from the end operation thread.
The code is available now, take it, use it, tell us what you think.