Search code examples
.netwcfasynchronousasync-awaitchannelfactory

How to add async support to a .NET 4.5 WCF service so it doesn't disrupt existing clients?


I have an existing WCF service with a SOAP endpoint, using .NET 4.5. Most of the existing client code is using the ChannelFactory<T> proxy approach.

I'd like to change the service to support the async / await model for various server-side I/O and database operations.

The problem I'm having is that adding the async keyword to the WCF method calls requires changing their interface signatures to Task<T>. That, in turn, seems to be requiring changes to the client code.

While keeping the service code async "all the way down," is there a straightforward way to keep the exposed API unchanged?


Solution

  • As long as you rename your server side method to include the word XxxxxAsync it will not change the clientside signature.

    WCF automaticly makes two endpoints for every method, a synchronous version and a async version. You can see this this with the WCF test client.

    For example, the following service contract

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        string GetData(int value);
    }
    
    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }
    }
    

    When you fire up the WCF test client you will see 2 methods available

    enter image description here

    If I change the code to the following

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        Task<string> GetDataAsync(int value);
    }
    
    public class Service1 : IService1
    {
        public async Task<string> GetDataAsync(int value)
        {
            await Task.Delay(value);
            return string.Format("You entered and awaited: {0}", value);
        }
    }
    

    I can still call the synchronous string GetData(int) method from my client

    enter image description here

    Note, you will not be able to use the same interface clientside and serverside anymore to represent the API (and you really shouldn't, the client side interface should have both versions in it. That way the client can decide if it wants to make a blocking call or not). You will still be able to use shared models between them however.