One issue with the previous versions of WCF was that its service contracts did not contain definitions of its asynchronous members, resulting in unnecessary complexity in the WCF code when using asynchronous calls. Furthermore, the code was prone to timeouts and error-handling issues.
There are some scenarios that require these kinds of asynchronous calls:
WCF 4.5 simplifies this behavior and also makes the web services easily testable.
Next, we will explore how to implement an asynchronous web service and consume it.
In this recipe, we will explore the new asynchronous features of WCF.
WebAppWcfAsyncHost
and click on OK.AsyncService.svc
and click on the Add button.IAsyncService.cs
file and replace the code with the following:[ServiceContract] public interface IAsyncService { [OperationContract] Task<int> DoWorkAsync(); }
System.Threading.Tasks
.AsyncService
class and replace the code with the following:public class AsyncService : IAsyncService { Public async Task<int> DoWorkAsync() { return new System.Random().Next(1, 10); } }
ConsoleWcfServiceAsyncConsumer
and click on the OK button.AsyncServiceReference
, as shown in the following screenshot, and click on the OK button.Program.cs
file in the designer and enter the following code:class Program { Static AsyncServiceClient svcCli = new AsyncServiceClient(); static void Main(string[] args) { Console.WriteLine("Requesting values"); var result = GetResultsFromWebService(); Console.WriteLine("The result is: " + result.Result.ToString()); Console.ReadLine(); } Static async Task<int> GetResultsFromWebService() { var t1 = svcCli.DoWorkAsync(); var t2 = svcCli.DoWorkAsync(); var t3 = svcCli.DoWorkAsync(); var t4 = svcCli.DoWorkAsync(); Console.WriteLine("Waiting for all the values to be returned.."); await Task.WhenAll(t1, t2, t3, t4); Console.WriteLine("All the values received, processing.."); return t1.Result + t2.Result + t3.Result + t4.Result; } }
Essentially, the only different thing we did was to add the Task<int>
command to the WebService
method declaration; the rest simply works out of the box.
On the client side, we called our random asynchronous value provider four times and assigned the results to the tasks. We then used the Task.WhenAll()
method to wait for the tasks, so the code will not continue running this method until all the tasks have finished; this means that all the web service calls have returned.
Although this example might seem simple, imagine that you changed the random integer services with other possible services, such as GetOrderTotal
, GetOrderTaxes
, or GetOrderShippingCosts
, and you will begin to see the possibilities. This new coding style simplifies our code noticeably, and makes it easier to maintain and understand.
The
Task-Based Asynchronous Pattern that we have just seen is clearly superior to and simpler than the previous event-based patterns and IASyncResult
asynchronous patterns.
We should use this pattern as the preferred way to implement any WCF asynchronous operation.
It is also important to keep in mind that the use of this pattern is beneficial for scalability since it assures that thread-related resources are only consumed when the code is being executed. An asynchronous solution will allow the thread resources to be used by other means while waiting for I/O, database operations, or other services to complete. When the operation is complete, it will yield the necessary data for the operation to continue.
Look into the Understanding async and await in .NET 4.5 recipe of Chapter 2, Exploring the Top New Features of the CLR, dedicated to CLR and the usage of async
and await
.