Export (0) Print
Expand All

Consuming Web Services with the Microsoft .NET Compact Framework

.NET Compact Framework 1.0
 

Neil Cowburn
Content Master Ltd

March 2003

Applies to:
    Microsoft® .NET Compact Framework
    Microsoft Windows® CE

Summary: Learn how to call Web services synchronously and asynchronously from your Smart Device application using the .NET Compact Framework. (7 printed pages)

Contents

Introduction
Consuming a Web Service
Making Synchronous Web service Calls
Making Asynchronous Web Service Calls
More Info

Introduction

A primary feature of the Microsoft®.NET Compact Framework is its ability to consume Web services. The .NET Compact Framework supports the use of Web services in two distinct ways: synchronously and asynchronously. Both have their advantages and disadvantages. Synchronous Web service calls are simple to code while asynchronous calls require some slightly more complex coding. Synchronous calls will cause the application to freeze if the Web service is unresponsive for a long period, whereas asynchronous calls allow the user to interact with the application while the call to the Web service is on going.

When consuming Web services from a Smart Device project you will experience an initial delay of a few seconds. If you make asynchronous calls, this delay does not have to freeze your application's user interface. This delay occurs when the .NET Compact Framework runtime is setting up the connection details for the Web service, and caching the details. This can often cause your application to appear unresponsive. Subsequent calls to the Web service will show greatly improved performance.

This article demonstrates how to add a Web Reference to a Web service to your Smart Device projects, and how to call the Web service both synchronously and asynchronously.

This article assumes that you have a working knowledge of creating Smart Device applications with Microsoft Visual Studio® .NET 2003.

Consuming a Web Service

To consume a Web service in a Smart Device project, you need to add a Web Reference to your project. A Web reference enables a project to consume a Web service. When you add a Web Reference to your project, Visual Studio .NET automatically generates a proxy class with methods that serve as proxies for each exposed method of the Web service. The proxy class is hidden from view in the Solution Explorer by default. Your application uses an automatically generated class to access Web services, and not one you would modify with your own code.

To add a Web Reference to a project:

  1. In Solution Explorer, select the project that will consume the Web service.
  2. On the Project menu, select Add Web Reference.
  3. Enter the URL for the Web service you wish to consume and click the Go button.

The Add Web Reference dialog box

  1. In the Web reference name field, enter a name that you will use in your code to access the selected Web service programmatically.
  2. Click the Add Reference button to create a reference to the Web service in your application. The new reference will appear in the Solution Explorer under the Web References node for the selected project.

The proxy class that Visual Studio .NET generates when you add a Web Reference also includes methods for accessing the Web Service synchronously or asynchronously. We will now look at how you do this.

Making Synchronous Web service Calls

When making synchronous calls to Web services, the calling thread is blocked until the Web service returns the result of the method call. Synchronous calls are useful if the method you are calling on the server does not require much processing time and will return quickly. In addition, synchronous Web service calls are simpler to implement than their asynchronous counter-part. However, you will notice a significant delay in calling Web services from a .NET Compact Framework application, which cause your application to lock and your user interface to freeze until the method call has returned.

To make a synchronous call to a Web service, you create an instance of the proxy class and then call the methods within the proxy class as you would with any other class. The code sample below shows you how to make a synchronous call to a Web method of a Web service that returns information about the books in the pubs example database shipped with SQL Server. The code then walks through the DataSet to load the data into a ListView control on a Windows Form.

This example assumes that when you added a Web Reference, (as explained in the first part of this paper) you named the Web reference BookCatalog. The BookCatalog Web service has the GetItems Web method, which returns a DataSet object. The code is taken from the button1_Click() event handler in the download that accompanies this article.

// ---- Call the Web service ----
// Create an instance of Web Service proxy class
BookCatalog.Service1 bookcatalog = new BookCatalog.Service1();
// Create a new instance of a DataSet object and call the Web Service 
// method, GetItems, to retrieve the list of books
DataSet ds = bookcatalog.GetItems();
// ------------------------------

// ----  Process the DataSet ----
// Loop through the DataSet and add each row's Title_ID and Title 
// field to the ListView
foreach(DataRow drBook in ds.Tables[0].Rows) {
    // Create a new ListViewItem to add to the ListView
    ListViewItem book = new ListViewItem();
    // Assign the Title_ID field to the Text property
    book.Text = drBook["Title_ID"].ToString();
    // Assign the Title field to the first SubItem
    book.SubItem[0].Text = drBook["Title"].ToString();
    // Add the book ListViewItem to the ListView
    listView1.Items.Add(book);
}
// ------------------------------

Making Asynchronous Web Service Calls

By making an asynchronous call to a Web service, you can continue to use the calling thread while you wait for the Web service to respond. This means users can continue to interact with your application without it locking up while the Web service access proceeds. This is a better design pattern and a more effective use of threads within the Smart Device application by making use of the multithreading support. When making asynchronous calls, the call is made on a different thread to the one that is running the user interface. The Web services application does not require any special configuration to support asynchronous access nor do they need to know whether you are calling it synchronously or asynchronously. For every synchronous method in the proxy class, there is a corresponding Begin and End method. For example, if the name of the Web service method is GetItems, the asynchronous methods are BeginGetItems and EndGetItems.

Calling Web services asynchronously is a two-step operation. Firstly, call the Begin method to initiate the call to the Web method. Secondly, call the End method to complete the Web service call and retrieve the response from the Web service.

The Begin method returns a System.Web.Services.Protocol.WebClientAsyncResult object, which implements the System.IAsyncResult interface. This object provides status information about the pending asynchronous call. By passing this object to the End method, the proxy class can identify which request you would like to complete, especially when making multiple asynchronous calls simultaneously.

There are several ways to determine when the asynchronous Web service call has completed:

  • Pass a callback delegate to the Begin method. The callback delegate executes when the Web service call completes.
  • Force the application to wait using one of the WaitHandle methods of the IAsyncResult.AsyncWaitHandle object. When using the methods of the WaitHandle class, the client can also specify a timeout after which it will abandon waiting for results from the Web services it called.
  • Poll the value of the IAsyncResult.IsCompleted property in your main thread code for a value of true. When this property is true, call the End method to retrieve the response from the Web service.
  • Call the End method directly without using one of the other techniques for determining if the asynchronous Web service call has completed. This method will block execution of the calling thread until the asynchronous call is complete.

The most efficient method is passing a callback delegate to the Begin method, as callback functions do not block threads while waiting for a response. When the Web service returns its response, the callback delegate executes in a new thread. You then call the End method inside the callback.

The code below shows you how to create an asynchronous Web service call; the code shows a call to BeginGetItems, which has the following syntax:

BeginGetItems(System.AsyncCallback callback, object asyncState);

BeginGetItems takes two parameters, the first of which is an AsyncCallback object, which is created by passing the address of the ServiceCallback method in its constructor. The second parameter is of type object; you can pass any object that will assist you in handling the response from the Web service. You access this same object by getting the AsyncState property of the IAsyncResult parameter to your callback method. In the example below, the object that is passed in this way is the Web service proxy object so that when the callback delegate executes, a call to EndGetItems can be made, as shown in the ServiceCallback method below.

private void button2_Click(object sender, System.EventArgs e)
{
    // Disable the Async button and clear the ListView of any data
    // Create an instance of Web service proxy class
    BookCatalog.Service1 ws = new BookCatalog.Service1();
    // Create a reference to the callback delegate
    AsyncCallback cb = new AsyncCallback(ServiceCallback);
    // Call the Begin method, passing the callback delegate and
    // this proxy class instance as the AsyncState object. 
    ws.BeginGetItems(cb,ws);
}

private void ServiceCallback(IAsyncResult ar)
{
    // Cast the AsyncState object to the proxy object
    BookCatalog.Service1 ws = (BookCatalog.Service1)ar.AsyncState;
    // Call the End method and assign the response to a DataSet
    DataSet ds = ws.EndGetItems(ar);

    // Loop through the DataSet and add each row's Title_ID and Title 
    // field to the ListView
    foreach(DataRow drBook in ds.Tables[0].Rows) {
        // Create a new ListViewItem to add to the ListView
        ListViewItem book = new ListViewItem();
        // Assign the Title_ID field to the Text property
        book.Text = drBook["Title_ID"].ToString();
        // Assign the Title field to the first SubItem
        book.SubItem[0].Text = drBook["Title"].ToString();
        // Add the book ListViewItem to the ListView
        listView1.Items.Add(book);
    }
}

Making asynchronous Web service calls requires a little more code than making synchronous calls, but the end result, a more responsive application, is certainly worth the effort.

Important   Use multithreaded programming techniques when calling Web services asynchronously

If you do not use multithreaded techniques when making asynchronous Web service calls, you will encounter problems when two or more threads try to access the same data at the same time. One such technique, shown in the code below, is to use the lock statement in C# to acquire mutually exclusive access to an object, such that any other threads are denied access.

private void ServiceCallback(IAsyncResult ar)
{
    // Cast the AsyncState object to the proxy object
    BookCatalog.Service1 ws = (BookCatalog.Service1)ar.AsyncState;
    // Call the End method and assign the response to a DataSet
    DataSet ds = ws.EndGetItems(ar);

    // Use the lock statement to prevent other threads from accessing
    // the listview until you have finished updating it
    lock(this.listView1)
    {        
        // Loop through the DataSet and add each row's Title_ID and 
        // Title field to the ListView
        foreach(DataRow drBook in ds.Tables[0].Rows) {
            // Create a new ListViewItem to add to the ListView
            ListViewItem book = new ListViewItem();
            // Assign the Title_ID field to the Text property
            book.Text = drBook["Title_ID"].ToString();
            // Assign the Title field to the first SubItem
            book.SubItem[0].Text = drBook["Title"].ToString();
            // Add the book ListViewItem to the ListView
            listView1.Items.Add(book);
        }
    }
}

You should investigate other techniques, such as using the Monitor class and Control.Invoke to make your applications thread-safe. More information about multithreaded programming can be found in the MSDN® Library.

More Information

For additional information about Smart Device programming and the .NET Compact Framework, see the following resources:

Show:
© 2014 Microsoft