Martin Bliss
Martin Bliss

Reputation: 1051

How can I implement client-side async calls with WCF's ChannelFactory<T>?

Suppose we are writing a client for a Calculator web service using WCF's ChannelFactory. The service contract is shared by way of a third assembly referenced by both the implementation service and the client. Below is the service contract (which cannot be changed!)

public interface ICalculator 
{
    int Add(int x, int y);
}

The ChannelFactory creates a transparent proxy object that "mocks" the ICalculator service contract, passing method calls to a RealProxy object which then sends the message down the WCF channel stack. Is there a way to manipulate WCF (on the client side ONLY!) to auto-expose Task-friendly service operations, similar to VS-auto-generated service proxies?

To be clear, I'm not looking to modify my service to be async-friendly in anyway. I want my client to proceed processing while waiting for ordinarily blocking service calls to complete.

Upvotes: 3

Views: 1252

Answers (2)

Martin Bliss
Martin Bliss

Reputation: 1051

I did some exploring using ILSpy and found that both ChannelFactory and VS' service proxy code both leverage the same code underneath the covers to generate a transparent proxy for ICalculator. The only difference is that the auto-gen code created a custom interface that mirrored the service's contract, plus Task async methods, with OperationContract attributes that pointed back to the "real" service operation URIs.

[ServiceContract]
public interface ICalculatorClient
{
    [ServiceOperation(Action="http://tempuri.org/ICalculator/Add")]
    Task<int> AddAsync(int x, int y);
}

So, instead of using an assembly containing the original service's service contract, I created my own ICalculatorClient service contract in the client code (the name was just to eliminate ambiguity for this test) which featured the desired Task async method calls, only with the requisite ServiceOperation attributes with an Action property pointing to the URI for the "real" service operation on the server contract.

At runtime, the desired behavior was observed: My client code proceeded while waiting on a response from the server, which it eventually received as expected. The service is none the wiser, not having been modified to address client needs. The client is all the smarter, gaining control over the details of its interaction with a web service.

Upvotes: 2

Aron
Aron

Reputation: 15772

public interface ICalculator 
{
    Task<int> Add(int x, int y);
}

Use this as the contract. However you need to make sure you are running .net 4.5 for this to work.

Remember on the server side to use this pattern

public class Calculator : ICalulator
{
    public Task<int> Add(int x, int y)
    {
        int result = x + y;
        return Task.FromResult(result);
    }
}

Upvotes: 2

Related Questions