From what I've heard it should be pretty smooth to produce asynchronous server/client code with .net 4.5, so let's try it out! Defining async methods on the service contract is now a lot cleaner :
[ServiceContract]
public interface IPeopleService
{
[OperationContract]
Task<IList<Person>> GetPeople();
}
instead of the wcf 4.0 way which would look something like this :
[ServiceContract]
public interface IPeopleService
{
[OperationContract(AsyncPattern=true)]
IAsyncResult BeginGetPeople(AsyncCallback cb, object state);
[OperationContract]
IList<Person> GetPeople();
[OperationContract]
IList<Person> EndGetPeople(IAsyncResult ar);
}
the server side implementation of the operation when returning a task is straightforward :
public async Task<IList<Person>> GetPeople()
{
Task t1 = Task.Delay(500);
Task t2 = Task.Delay(500);
await Task.WhenAll(t1, t2);
return await Task.Factory.StartNew(() => people);
}
If you don't want to await something in the method you can skip the async keyword and still return a Task as shown below, async on a method simply tells the compiler that "I'm going to await something in this method".
public Task<IList<Person>> GetPeople()
{
return Task.FromResult(people);
}
Anyways it's really nice to skip the non-implemented begin/end methods on the server which was simply boiler plating in .net 4.0. For the sake of simplicity the service will be hosted in a console application and for consuming the service I've implemented a simple proxy that inherits ClientBase<TChannel> and implements the contract. See the code if this confuses you (which probably means that you're a noob ;-)). The client code when working with tasks is clean and straightforward as well :
var serviceProxy = new PeopleServiceProxy("PeopleServiceEndpoint");
Task<IList<Person>> people = serviceProxy.GetPeople();
people.ContinueWith(
x =>
{
foreach (Person person in x.Result)
{
Console.WriteLine(
"{0} {1} born {2}",
person.FirstName,
person.LastName,
person.BirthDate.ToShortDateString());
}
});
We can control on which thread we will continue by passing in a TaskScheduler. So far so good, so what about testing? I'm using Nunit which integrates really well with VS when using resharper. I want to write an integration test (not unit) to make sure everything works well including the WCF part since unit testing my simple service is too easy ;-) I'll host the service in the Setup method and take it down in the teardown. A simple test then looks like :
[Test]
public void ShallBeAbleToGetDateTimeFromService()
{
IPeopleService serviceProxy = new PeopleServiceProxy("PeopleServiceEndpoint");
Task<IList<Person>> getPeopleTask = serviceProxy.GetPeople();
getPeopleTask.Wait();
IList<Person> result = getPeopleTask.Result;
Assert.IsNotNull(result);
Assert.AreEqual(2, result.Count);
(serviceProxy as IDisposable).Dispose();
}
Obviously we'd use facades to call on services in a real application but the principle is the same. It doesn't get much cleaner than this imo.
/A
Get the code here! (67KB)