none
Using TAP, but not exposing Task<X> RRS feed

  • Question

  • Hi -

    I would like to use the task-based async pattern to implement my WCF service, but I don't want to expose return types of the form Task<X> in the service contract (the clients for this service are not .NET and won't be able to handle it). So, I would like:

    [ServiceContract]
    public interface IMyService
    {
         [OperationContract]
         string DoSomething(string s);
    }

    And on the implementation side I would like:

    public class MyServiceImpl : IMyService
    {
        public Task<string> DoSomething(string s)
        {
             return await SomeHelpfulCodeAsync(s);
         }
    }

    Basically I want the WCF core to grab the Awaiter for the return value from the implementation, and register a completion callback on it. When the call completes, I want to the core to marshall the result back to the client. The reason for this is to optimize thread usage (i.e. not block the threads that are servicing incoming WCF requests).

    What is the easiest way possible to achieve this?

    Thanks!
         Terry.


    They're all dead Dave.

    Monday, August 19, 2013 5:43 AM

Answers

  • Hi Terry,

    I think the server-side Contract types used in WCF service (such as the Task<xxx> or IAsyncResult of traditional async mode ) doesn't means the exact types be exposed in the WSDL metadata of the service. For example, we can define a WCF async service as below:

    [ServiceContract]
    public interface IAsyncService
    {
        [OperationContract]
        Task<string> GetDataAsync(string input);
    }
    
    public class AsyncService : IAsyncService
    {
        public async Task<string> GetDataAsync(string input)
        {
            var data = "Got data: ";
    
            await Task.Run(
                () =>
                {
                    data += input;
                }
            );
    
            return data;
        }
    }
    

    and in the generated WSDL, we can find that there is no much different with a normal syncrhonous synatx service. Therefore, no matter .NET or non-.NET client (Java or other ...), they can consume the service by using the standard WSDL document. Actually, when you try adding service reference against the Async service, you can choose to not generate async operations (which let you invoke the service just like a normal WCF service at client-side). So the Task<xxx> based pattern just affect the service execution model at server-side.


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    • Marked as answer by Terry Coatta Tuesday, August 20, 2013 3:33 PM
    Tuesday, August 20, 2013 6:31 AM
    Moderator

All replies

  • Hi Terry,

    I think the server-side Contract types used in WCF service (such as the Task<xxx> or IAsyncResult of traditional async mode ) doesn't means the exact types be exposed in the WSDL metadata of the service. For example, we can define a WCF async service as below:

    [ServiceContract]
    public interface IAsyncService
    {
        [OperationContract]
        Task<string> GetDataAsync(string input);
    }
    
    public class AsyncService : IAsyncService
    {
        public async Task<string> GetDataAsync(string input)
        {
            var data = "Got data: ";
    
            await Task.Run(
                () =>
                {
                    data += input;
                }
            );
    
            return data;
        }
    }
    

    and in the generated WSDL, we can find that there is no much different with a normal syncrhonous synatx service. Therefore, no matter .NET or non-.NET client (Java or other ...), they can consume the service by using the standard WSDL document. Actually, when you try adding service reference against the Async service, you can choose to not generate async operations (which let you invoke the service just like a normal WCF service at client-side). So the Task<xxx> based pattern just affect the service execution model at server-side.


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    • Marked as answer by Terry Coatta Tuesday, August 20, 2013 3:33 PM
    Tuesday, August 20, 2013 6:31 AM
    Moderator
  • Hi Steven -

    Thanks!

    I didn't think to generate the WSDL and actually have a look at it -- just assumed that it would directly reflect the declared return type.

    For clients of this service that I am developing locally, I reference the ServiceContract directly (I use the service contract interface with ChennelFactory). Does the resulting proxy perform the same "mapping" as with the WSDL -- that is, to continue with you example, does the proxy bear a method with the signature:

        string GetDataAsync()

    even though the interface declares the return type to be Task<string>?

    The way that I normally code these locally developed clients is something like (again using your example):  

            BasicHttpBinding myBinding = new BasicHttpBinding();
            EndpointAddress myEndpoint = new EndpointAddress("http://localhost/Services/Service1");
            ChannelFactory<IAsyncService> cf= new ChannelFactory<IAsynService>(myBinding, myEndpoint);
            IAsyncService proxy = cf.CreateChannel();
            string result = proxy.GetDataAsync();

    But, it seems like there is no way for this to work as I might like, because IAsyncService declares the return type of GetDataAsync() to be Task<string> and that is going to produce a type error on the last line above. I don't want to have to re-code my locally developed clients just because I have decided to make use of an asynchronous implementation on the server side.

    Is there any way around this problem?

    As a side node, it seems "wrong" to for an implementation concern (using async to improve thread utilization on the server) to be exposed via the service contract, which is really on supposed to reflect the abstraction of the service, not its implementation details.

    Thanks!
        Terry.


    They're all dead Dave.

    Tuesday, August 20, 2013 3:33 PM
  • Thanks for reply Terry,

    As you also mentioned the client-side proxy (service reference) generation. I think it necessary to take a look at the overall asynchronous programming support of WCF. WCF service's async programming consist of two parts:

    Server-side asynchronous programming
    Client-side asynchronous programming

    When you define your service contract with "Task<xxx>", you are actually doing server-side asynchronous programming (just like the old "Beginxxx", "EndXXX" based pattern for WCF async programing).

    When you generate WCF proxy (service reference) with async method generated, the async methods generated are for client-side async programming.

    The server-side and client-side async programming are totally separated and have no relation to each other. Here is a MSDN blog entry which has explained this well:

    #Scale WCF Application Better with Asynchronous Programming
    http://blogs.msdn.com/b/wenlong/archive/2009/02/09/scale-wcf-application-better-with-asynchronous-programming.aspx

    Hope this helps clarify more.


    <THE CONTENT IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, WHETHER EXPRESS OR IMPLIED>
    Thanks
    MSDN Community Support

    Please remember to "Mark as Answer" the responses that resolved your issue. It is a common way to recognize those who have helped you, and makes it easier for other visitors to find the resolution later.

    Tuesday, August 20, 2013 4:55 PM
    Moderator
  • Thanks for reply Terry,

    When you generate WCF proxy (service reference) with async method generated, the async methods generated are for client-side async programming.

    Hi Steven -

    I understand the server/client separation when one is importing a service reference. But, in the example I outlined in my previous post, you'll see that I am *not* importing a service reference -- rather I am directly using the service contract type with ChannelFactory. So there is no proxy generation, and the ChannelFactory creates channels using the service contract interface directly. Unless there is some further compiler magic occurring, I can't see how the return types of the channels created via ChannelFactory can be correct.

    Is there an example somewhere of using ChannelFactory with Service Contracts designed for TAP?

    Thanks!
        Terry.


    They're all dead Dave.

    Tuesday, August 20, 2013 5:03 PM