In this section, I’ll walks through the various options provided by the Microsoft .NET Framework for making Web service calls and discuss the best way to consume Web services from Windows Forms clients.
Most materials in this section are adapted materials from  and . See , , , , and  in more details.
In this article, I’ll use a Web method created in Matt’s articles that purposefully could take a long time to return. The Web method is called DelayedResponse and takes an integer as its only parameter and returns a string.
When you choose the Add Web Reference option in Microsoft Visual Studio® .NET, Visual Studio .NET generates a proxy class. Web services are called through the proxy class. This technique allows the application developer to call a local method on the proxy class that takes care of the details of generating, transmitting and parsing the XML required to actually calling the remote Web service. The generated proxy class provides three methods for each Web service operation. One method named the same as the Web service operation that calls the Web service synchronously and a pair of methods prefixed with Begin and End to call the Web service asynchronously.
Calling the Web service synchronously is now a matter of creating an instance of the proxy and calling the method named the same as the Web service operation:
A typical communication scenario that a Windows Forms client consumes a Web service is shown below.
A Windows Forms client calls a Web service and the Web service retrieves data from a database. Three components might sit on different machines and the calls made might be lengthy network calls.
Web services are slow due to the latency involved when making calls across a network, especially over a relatively low-speed wireless connection. Communicating large amounts of data may also cause the slowness.
If you make a lengthy Web service call synchronously, the user interface of your application might freeze. In Windows Forms applications, the user experience we focus on is to allow the applications to do other things while making the Web service calls. As you can see later, the best way to make Web service calls from Windows Forms clients is to make asynchronous Web service calls or combine asynchronous Web service calls with an asynchronous delegate.
Before introducing asynchronous Web service calls, I want to show you how to make a synchronous Web service call with an asynchronous delegate.
When a managed application is executed, the runtime offers a pool of threads that will be created the first time the code accesses it. The thread pool allows jobs to be run in the background without the overhead of frequently creating and destroying separate threads for each task.
There are several ways to use the thread pool. For example, you can use the thread pool method QueueUserWorkItem. The way I’m going to use is to use asynchronous delegates. For more information on using delegates, see .
Here is how it works. We first define a delegate named AsyncDelegate. In the button click event handler, we create an instance of that delegate that refers to the method (named Callback) that will do the work. Then, call BeginInvoke to run the Callback method on a thread from the thread pool. We also pass an AsyncCallback object and the AsyncDelegate object in the BeginInvoke call. Passing the AsyncCallback object will cause the CleanUpDelegate method invoked after the Callback method completes and the AsyncDelegate object will be used to make the EndInvoke call in the CleanUpDelegate method. In the Callback method, we make a synchronous Web service call. Then, make a Control.Invoke call to deliver the response message from a thread pool thread to the UI thread and update the UI in the UpdateUI method. After the Callback method completes, the CleanUpDelegate method is invoked and we make the EndInvoke call to clean up memory.
The Control.Invoke call here is necessary because only the UI thread is allowed to access properties of a control. Unfortunately the Control.Invoke call here does not work in the .NET Compact Framework. The .NET CF supports just one of the overloaded Control.Invoke methods from the full .NET Framework. Control.Invoke takes a single parameter; a delegate specifying which method to execute on the UI thread. The delegate must be of type EventHandler. To pass data, you have to use shared data.
Always call EndInvoke after your asynchronous call completes. This will pretend you from the memory leak.
Asynchronous delegates are a commonly used approach to send a task from the calling thread to a thread pool thread. While doing the task, the thread pool thread might need to communicate with the UI thread. The best way to do that is to use the message-passing model introduced by Chris Sells and Ian Griffiths (see , , , , and ).