Executing Asynchronous Web Services

This article has been excerpted from book "A Programmer's Guide to ADO.NET in C#".

There are two ways to access web services from a client application synchronously and asynchronously. A synchronous Web service is like the one we just executed in our client application. When a client is accessing a web service synchronously, a client has to wait until it gets a response from the web service. As we saw in our client application in the previous section, we're accessing OrderRetrievalService synchronously. What if a web method takes a long time in response? For instance, what if our InsertOrderFromNode method takes 10 minute in response and client has many other things to process? In the present case, the client has to wait for 10 minute and can't execute any thing else until getting a response from web service. In other words, a client's main thread is busy with the Web service if the client is accessing a Web service synchronously. Executing a web service asynchronously allows client application to execute more than one thread simultaneously. In other words, by calling accessing web services asynchronously, a client can continue to use the calling thread while waiting for the XML web service to respond. To access Web services asynchronously doesn't require any special configuration.

When adding a Web reference to a client application, VS.NET generates a proxy class capable of calling an XML Web service both synchronously and asynchronously. You can see the proxy reference of OrderRetrievalService by expanding the mcb node in the Solution Explorer; the reference filename is Reference.cs 

To view the contents of the proxy file, right-click and select View Code. This file stores information related to the web service and its methods. It also contains the URL of the web service. You can find the following code in Reference.cs as OrderRetrievalService.

        /// <remarks/>
        public Service1() 
                this.Url = "http://mcb/ OrderRetrievalService/Service1.asmx";

Other information this file stores is asynchronous method for every web method published by a web service. For each web method, there are two contains a corresponding Begin and End method. Therefore, for web method InsertOrderFromNode, asynchronous calls are BeginInsertOrderFromNode and EndInsertOrderFromNode. You can find the following methods in Reference.cs file:

        public System.IAsyncResult BeginInsertOrderFromNode
        (System.Xml.XmlNode aNode,
        System.AsyncCallback callback, object asyncState)
            return this.BeginInvoke("InsertOrderFromNode", new object[] { aNode}, callback, asyncState);

        /// <remarks/>
        public int EndInsertOrderFromNode(System.IAsyncResult asyncResult)
            object[] results = this.EndInvoke(asyncResult);
            return ((int)(results[0]));

Asynchronous web service execution requires a two-step process. First, you tell the Web service to begin execution by calling the Begin method. The second step, calling the End method, completes the web service call and returns the response.

To call a web service asynchronously, a client thread can use a WaitHandle. When you get to a place in your client code when you are required to wait for the service to end, you call a WaitHandle there. Listing 8-9 is an example of how to use the WaitHandle. You can also assign a WaitHandle a timeout period in case the web service takes to long.

In Listing 8-9, the code is adding two customer orders, so it needs to call the web service twice. The code starts by calling BeginInsertOrderFromNode on the first order, which returns an AsyncronousResult object. You can also use the same method, BeginInsertOrderFromNode, to begin the service for inserting a second order. You can use the WaitHandles returned from these calls to create the WaitHandle instance. When you require the client to wait for the service to finish, you execute the Waithandle's WaitAll method. The WaitAll method waits for all the asynchronous threads to complete before continuing execution of the code in the client. In this method you also pass a timeout period of 15 minutes, so you don't have to wait forever. When the wait has completed, you call the EndInsertOrderFromNode for both asynchronous threads. In the case where you were waiting for a return value, the End<method> call would also return the data. 

Note: You need to add a reference of the System,Threading namespace to the application because the WaitHandle class is defined in the System.Threading namespace.

Listing 8-9. Using WaitHandle to make synchronous calls

        private void Button3_Click(object sender, System.EventArgs e)
            // create the order information in XML from the Client TextBoxes
            XmlDocument OrderInfo = new XmlDocument();
            "<Order>" + "<OrderDate>" + TextBox1.Text + "</OrderDate>" + "<ShipName >" + TextBox2.Text + "</ShipName>" +
            "<ShipAddress>" + TextBox3.Text + "</ShipAddress>" + "<ShipCity>" + TextBox4.Text + "</ShipCity>" +
            "<ShipCountry>" + TextBox5.Text + "</ShipCountry>" +
            "<ShipPostalCode>" + TextBox6.Text + "</ShipPostalCode >" +

            // Construct the Web Service for entering an Order
            mcb.Service1 OrderEntry = new mcb.Service1();

            // Call the Asynchronous InsertOrderFromNode
            IAsyncResult ws1 = OrderEntry.BeginInsertOrderFromNode(
            OrderInfo, null, null);

            // Change the order information slightly
            OrderInfo["Order"]["ShipName"].InnerText = "Fred Estaire";

            // Call another Asynchronous InsertOrderFromNode Call
            IAsyncResult ws2 = OrderEntry.BeginInsertOrderFromNode(OrderInfo,
            null, null);

            // Construct an array of wait Handle and call WaitHandle for a
            // Maximum of 15 minutes
            WaitHandle[] TheWaitHandle = {ws1.AsyncWaitHandle, ws2.AsyncWaitHandle};
            WaitHandle.WaitAll(TheWaitHandles, new TimeSpan(0, 15, 0), true);

            // All the web services have returned (or timed out)
            // call end order on both web service Threads
            int orderid1 = OrderEntry.EndInsertOrder(ws1);
            int orderid2 = OrderEntry.EndInsertOrder(ws2);

WaitHandles has a few modes. In the previous mode, WaitAll, the command will wait until all services are completed (wait until ws1 and ws2 are completed). You can also call WaitAny. In the case of WaitAny, the method will wait until any of the services complete (wait until ws1 or ws2 is complete).


Hope this article would have helped you in understanding Executing Asynchronous Web Services See other articles on the website also for further reference.

This essential guide to Microsoft's ADO.NET overviews C#, then leads you toward deeper understanding of ADO.NET.