开发者

WCF - Are Asynchronous Services interoperable?

Basically as the question states开发者_JAVA技巧, if I make my services asynchronous does that mean they aren't interoperable anymore?


As far as the client is concerned, a sync or an async version of the service are identical (see example below). So the sync/async decision does not affect interoperability.

public class StackOverflow_6231864_751090
{
    [ServiceContract(Name = "ITest")]
    public interface ITest
    {
        [OperationContract]
        string Echo(string text);
        [OperationContract]
        int Add(int x, int y);
    }
    [ServiceContract(Name = "ITest")]
    public interface ITestAsync
    {
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginEcho(string text, AsyncCallback callback, object state);
        string EndEcho(IAsyncResult ar);
        [OperationContract(AsyncPattern = true)]
        IAsyncResult BeginAdd(int x, int y, AsyncCallback callback, object state);
        int EndAdd(IAsyncResult ar);
    }
    public class Service : ITest
    {
        public string Echo(string text) { return text; }
        public int Add(int x, int y) { return x + y; }
    }
    public class ServiceAsync : ITestAsync
    {
        string Echo(string text) { return text; }
        int Add(int x, int y) { return x + y; }
        public IAsyncResult BeginEcho(string text, AsyncCallback callback, object state)
        {
            Func<string, string> func = Echo;
            return func.BeginInvoke(text, callback, state);
        }

        public string EndEcho(IAsyncResult ar)
        {
            Func<string, string> func = (Func<string, string>)((System.Runtime.Remoting.Messaging.AsyncResult)ar).AsyncDelegate;
            return func.EndInvoke(ar);
        }

        public IAsyncResult BeginAdd(int x, int y, AsyncCallback callback, object state)
        {
            Func<int, int, int> func = Add;
            return func.BeginInvoke(x, y, callback, state);
        }

        public int EndAdd(IAsyncResult ar)
        {
            Func<int, int, int> func = (Func<int, int, int>)((System.Runtime.Remoting.Messaging.AsyncResult)ar).AsyncDelegate;
            return func.EndInvoke(ar);
        }
    }
    public static void Test()
    {
        foreach (bool useAsync in new bool[] { false, true })
        {
            Type contractType = useAsync ? typeof(ITestAsync) : typeof(ITest);
            Type serviceType = useAsync ? typeof(ServiceAsync) : typeof(Service);
            Console.WriteLine("Using {0} service implementation", useAsync ? "Asynchronous" : "Synchronous");
            string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
            ServiceHost host = new ServiceHost(serviceType, new Uri(baseAddress));
            host.AddServiceEndpoint(contractType, new BasicHttpBinding(), "");
            host.Open();
            Console.WriteLine("Host opened");

            Console.WriteLine("Using the same client for both services...");
            ChannelFactory<ITest> factory = new ChannelFactory<ITest>(new BasicHttpBinding(), new EndpointAddress(baseAddress));
            ITest proxy = factory.CreateChannel();
            Console.WriteLine(proxy.Echo("Hello"));
            Console.WriteLine(proxy.Add(3, 4));

            ((IClientChannel)proxy).Close();
            factory.Close();

            host.Close();

            Console.WriteLine("Done");
            Console.WriteLine();
        }
    }
}


If by "making the service asynchronous", you mean using AsyncPattern, then my understanding is that this has no effect on the client at all, only on how the WCF runtime invokes your operations on the server. The client (a WCF client, that is), as ever, makes its own choice over whether to use asynchronous calls.

From this MSDN page:

To define a contract operation X that is executed asynchronously regardless of how it is called in the client application...

and:

In this case, the asynchronous operation is exposed in metadata in the same form as a synchronous operation: It is exposed as a single operation with a request message and a correlated response message. Client programming models then have a choice. They can represent this pattern as a synchronous operation or as an asynchronous one, so long as when the service is invoked a request-response message exchange takes place.


You're services don't have to do anything "special" ... they still behave the same way. You're clients on the other hand have to consume the services using an Asynchronous Pattern. The easiest way to do this is if you use "Add Service Reference...". Simply check a little box that says "Generate Asynchronous Operations" and voila, you can make asynchronous calls to your service...

Here's a good resource: How to: Call WCF Service Operations Asynchronously

Despite the negative comments, the example at the end is well put. Simply subscribe to the <service-name>Completed event and then make an Async call. The call is made, your UI thread is freed up and as soon as the call completes the event is raised! Be careful with your new found powers!

public class Foo
{
    private BarServiceClient client;

    public Foo()
    {
        client = new BarServiceClient();
        client.DoWorkCompleted += Client_DoWorkCompleted;
    }

    private void Client_DoWorkCompleted(object sender, DoWorkCompletedEventArgs e)
    {
        //e.Result contains your result.
    }

    public void DoBar()
    {
        client.DoWorkAsync(); //Called asynchronously, UI thread is free! :)
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜