Asynchronously consume synchronous WCF service

后端 未结 3 578
北荒
北荒 2020-12-08 02:58

I’m currently in the process of migrating a client application over to .NET 4.5 to make use of async/await. The application is a client for a WCF service which currently off

3条回答
  •  醉酒成梦
    2020-12-08 04:00

    If your server-side API can be naturally async (like your Task.Delay example, rather than the Task.Run wrapper), declare it as Task-based in the contract interface. Otherwise, just leave it synchronous (but don't use Task.Run). Do not create multiple endpoints for the sync and async versions of the same method.

    The generated WSDL remains the same for async and sync contract APIs, I just found out that myself: Different forms of the WCF service contract interface. Your clients will keep running unchanged. By making your server-side WCF method asynchronous, all you do is improve the service scalability. Which is a great thing to do, of course, but wrapping a synchronous method with Task.Run would rather hurt the scalability than improve it.

    Now, the client of your WCF service doesn't know if the method is implemented as synchronous or asynchronous on the server, and it doesn't need to know that. The client can call your method synchronously (and block the client's thread) or it can call it asynchronously (without blocking the client's thread). In either case, it won't change the fact that the SOAP response message will be sent to the client only when the method has fully completed on the server.

    In your test project, you're trying to exposes different versions of the same API under different contract names:

    [ServiceContract]
    public interface IExampleService
    {
        [OperationContract(Name = "GetTest")]
        string GetTest();
    
        [OperationContract(Name = "GetTestAsync")]
        Task GetTestAsync();
    
        [OperationContract(Name = "GetTestRealAsync")]
        Task GetTestRealAsync();
    }
    

    This doesn't really make sense, unless you want to give your client an option to control if the method runs synchronously or asynchronously on the server. I cannot see why you would want this, but even if you have your reason, you'd be better off controlling this via a method argument and a single version of the API:

    [ServiceContract]
    public interface IExampleService
    {
        [OperationContract]
        Task GetTestAsync(bool runSynchronously);
    }
    

    Then, in the implementation your could do:

    Task GetTestAsync(bool runSynchronously)
    {
        if (runSynchronously)
            return GetTest(); // or return GetTestAsyncImpl().Result;
        else
            return await GetTestAsyncImpl();
    }
    

    @usr explains this in great details here. To sum up, it is not like the WCF service calls back your client to notify about the completion of the async operation. Rather, it simply sends back the full SOAP response using the underlying network protocol when it's done. If you need more than that, you could use WCF callbacks for any server-to-client notifications, but that would span the boundaries of a single SOAP message.

提交回复
热议问题