Export (0) Print
Expand All

Use Threading with Asynchronous Web Services in .NET Compact Framework to Improve User Experience

.NET Compact Framework 1.0
 

Christian Forsberg
businessanyplace.net

February 2004

Applies to:
   Microsoft® .NET Compact Framework 1.0
   Microsoft Visual Studio® .NET 2003

Summary: The .NET Compact Framework does not directly support calling Web services asynchronously. Synchronous calls do not create a good user experience because the application is hung waiting for the Web service call to return. This article shows you how asynchronous Web services are supported by the Visual Studio .NET development environment. A sample is used to show how to use asynchronous Web services and threading in a sample application. (7 printed pages)


Download Windows Mobile Sample - Threading with Asynchronous Web Services.msi from the Microsoft Download Center.

Contents

Asynchronous Web Services and Threading
Spell Check Web Services
Spelling Anyplace Sample
Code Walk Through
Other Options
Conclusion

Asynchronous Web Services and Threading

Using Web services to add remote functionality is a very powerful way of extending your application. There are already many public Web services, but it is likely that there will be an explosion in the number of Web services. When Web service calls are made from a mobile device (for example, a Microsoft Windows® Mobile-based Pocket PC and Smartphone), it is often done over very limited bandwidth. While this is happening the user has to wait which can be a problem in many scenarios. Therefore, the ability to call Web services asynchronously is a powerful way to allow user interaction to continue while Web service method calls are made. The .NET Compact Framework has several constructs for handling asynchronous Web services calls, and all of them use threading to allow background processing. We will look in detail at the most powerful technique – using callback delegates – but some of the other options are also briefly covered.

Spell Check Web Services

On the Xmethods site, I found a Web service for spelling corrections. The Web services includes a method for checking the spelling of a word (WSpellCheck), and if the spelling is incorrect it returns a number of suggestions. A typical response from the Web services looks like this:

<?xml version="1.0" encoding="utf-8" ?> 
<corrections>
  <correction>
    <word>checck</word> 
    <suggestion>check</suggestion> 
    <suggestion>checks</suggestion> 
    <suggestion>checked</suggestion> 
    <suggestion>checker</suggestion> 
    <suggestion>checkup</suggestion> 
    <suggestion>chock</suggestion> 
    <suggestion>cheek</suggestion> 
    <suggestion>cheek</suggestion> 
    <suggestion>checkbox</suggestion> 
    <suggestion>checkers</suggestion> 
    <suggestion>checking</suggestion> 
    <suggestion>checkout</suggestion> 
    <suggestion>checksum</suggestion> 
    <suggestion>checkups</suggestion> 
    <suggestion>chocks</suggestion> 
  </correction>
</corrections>

If the spelling is correct, the response is an empty corrections tag (<corrections/>).

Spelling Anyplace Sample

The Spelling Anyplace sample was created with Microsoft Visual Studio .NET 2003 in C#, and targeting the .NET Compact Framework. It shows how to create an efficient user experience by allowing user activity while using a Web service asynchronously and updating the user interface from a background thread. The sample consists of a single form, as shown in Figure 1.

Figure 1. Spelling Anyplace sample

In the top text box, the user can enter plain text. The real-word usage could be any text entry activity in a business scenario (customer feedback, service comments, etc). While entering text, the user can select a word and tap the "Check" button to initiate a spell check for that word. A call is then made to the spell check Web service as indicated by the button being disabled (grayed). While the Web service call is processed, the user can continue to enter text. When the Web service call returns, the combo box is filled with spelling suggestions if the word is misspelled as shown in Figure 2.

Figure 2. Web services returns with spelling suggestions

The first entry in the list is the original word, and when suggestion is selected in the list, the incorrect word is replaced in the text.

If the word is correct the combo box is left empty. As soon as the user wants to check the spelling of another word, the same procedure can be repeated while continuing to enter text. Let's see how this was implemented.

Code Walk Through

After adding a Web Reference to the spellcheck Web service (Project, Add Web Reference..., and then type the Web service address: http://www.worldwidedesktop.com/spellcheck/spellcheckservice.asmx), the declarations needed for the Web service and the Web service method response are added on the form level of the main form:

private worldwidedesktop.SpellCheckService wsSpellCheck;
private XmlNode response;

The Web service proxy is created in the constructor of the main form:

wsSpellCheck = new worldwidedesktop.SpellCheckService();

The event handler for the button looks like this:

private void btnCheck_Click(object sender, System.EventArgs e)
{
  btnCheck.Enabled = false;
  cboCorrect.Items.Clear();
  AsyncCallback cb = new AsyncCallback(OnSpellCheckComplete);
  wsSpellCheck.BeginWSpellCheck("", txtText.SelectedText, cb, null);
}

The button is disabled to indicate that a call is being made to the Web services. This gives the user a visual feedback that a call is in progress, and also prevents concurrent calls being invoked. After the combo box items are removed, a callback delegate is created (to the OnSpellCheckComplete method, see below). A delegate is basically a reference to a method, and this delegate is passed to the asynchronous Web service method (BeginWSpellCheck) that uses it to call the method when the Web service call returns. BeginWSpellCheck uses a thread to wait for the asynchronous Web service call to return. This method was generated when the Web Reference was created (see above), and in addition to the parameters of the synchronous (WSpellCheck) method, it also takes the callback delegate as a parameter. In this sample, the last parameter of the asynchronous method is not used, but can be used for passing any object (like the Web service proxy itself) to the callback method. This object is retrieved using the AsyncState of the IAsyncResult parameter (ar) of the callback method (see below).

The callback that is called by the framework when the Web service call returns looks like this:

public void OnSpellCheckComplete(IAsyncResult ar)
{
  response = wsSpellCheck.EndWSpellCheck(ar);
  cboCorrect.Invoke(new EventHandler(HandleResponse));
}

The return value is saved in the local variable (response) and a call is made to a method (HandleResponse) that updates the user interface. As the OnSpellCheckComplete method is called from the framework, it does not run on the same thread as the user interface controls. The call to the Invoke method on a user interface control guarantees that the manipulation of the control is made on the same thread as the user interface. This is necessary to avoid data corruption or other errors.

Here is the method that updates the user interface:

public void HandleResponse(object sender, EventArgs e)
{
  if (response.ChildNodes.Count > 0)
  {
    foreach (XmlNode node in response.ChildNodes[0].ChildNodes)
      cboCorrect.Items.Add(node.InnerText);
    cboCorrect.SelectedIndex = 0;
  }
  btnCheck.Enabled = true;
}

Note that this method must be an event handler delegate, and therefore it is not possible to pass any parameters to this method. That is the reason for the response variable being declared at the form level.

The return value is an XML node (XmlNode) and if the returned node (corrections) contains any child nodes, the child nodes of the first child node (correction) is added to the combo box. The first item (the original word, see sample response above) is selected in the combo box.

Finally, the button is enabled again to indicate that the Web services call is complete.

Other Options

The use of use of a callback delegate as shown above is one of several ways to determine that an asynchronous Web services method call has completed. If you just want to perform some work after the call is made and when that work is done you want to wait for the call to complete, you can do this:

private void btnCheck_Click(object sender, System.EventArgs e)
{
  IAsyncResult ar = wsSpellCheck.BeginWSpellCheck("", txtText.SelectedText, null, null);
  // do work that does not require Web service response
  ar.AsyncWaitHandle.WaitOne();
  response = wsSpellCheck.EndWSpellCheck(ar);
  // update user inteface
}

Yet another way is to poll the thread to see if the method call completed, and this can be done with something similar to:

private void btnCheck_Click(object sender, System.EventArgs e)
{
  IAsyncResult ar = wsSpellCheck.BeginWSpellCheck("", txtText.SelectedText, null, null);
  while (!ar.IsCompleted)
  {
    // do work while waiting
  }
  response = wsSpellCheck.EndWSpellCheck(ar);
  // update user inteface
}

It is important to note that if you are not performing very much work in the while loop, much of the processor power will be used only for polling. This is especially unfortunate on a Pocket PC as it will drain the battery.

Conclusion

The use of asynchronous Web services method calls and background processing using threads can be very powerful when creating a responsive user interface. There are a few things to keep in mind, but when you master the techniques it really brings value to your applications.

Show:
© 2014 Microsoft