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

1

5

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?

Grajeda answered 11/1, 2015 at 0:0 Comment(2)
You're using a shared model right? You haven't added a service reference?Walcoff
^For the in-solution projects, yes. There are also external, non-.NET clients.Grajeda
D
10

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.

Dehydrogenate answered 11/1, 2015 at 0:27 Comment(4)
Thanks. That's pretty close to what I'm after, although no longer being able to use the same interface for both client and server unfortunately means some client code would have to change. One thing I don't understand is why clients should ever need to know or care whether server-side calls are async or not. Similarly, an async client-side call should have no effect or visibility from the server.Grajeda
@Grajeda You are correct, the client shouldn't know nor care what is happening server side, that is why you normally do not use the same interface on the server to host the WCF service as you do on the client to consume the WCF service. Forcing them to use the same interface creates an artificial restriction. And no client side code needs to change, you can leave the client using the same interface you just need to write a new internal interface the server will use that has the same method signatures except adding the word Async and having it return a task where appropriate.Dehydrogenate
Yay, it worked. The only catch I ran into is that the server's interface name needs to be the same as the one used on the client side. It can be in a different namespace, though.Grajeda
@Grajeda if you set the Name property of the ServiceContract you can have the name it exposes be diffrent than the interface name, that would let you use a diffrent actual interface name but still use the old "legacy" name (I think, only about 80% sure about that and don't have anything to test on right now).Dehydrogenate

© 2022 - 2024 — McMap. All rights reserved.