ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


Developing Web-Service-Driven, Smart Mobile Applications

by Michael Juntao Yuan
02/23/2004

Creating applications for mobile devices has its own set of unique challenges. Adding to the mix is the problem of maintaining connectivity over slow, expensive, and unreliable networks. Working with web services and other network protocols that were designed with broadband in mind can become a real burden to making applications really mobile. But there is hope; in this article, we will walk through the design and implementation of a complete end-to-end mobile application. It illustrates the common architecture and coding techniques for web-services- driven, smart mobile clients.

.NET Compact Framework and Smart Client

The wide adoption of the .NET Compact Framework on Windows Mobile devices (including PocketPCs and Smartphones) enables us to extend the existing Web Services infrastructure to support end-to-end mobile applications. The .NET Compact Framework has some important advantages over legacy mobility technology platforms.

Compared with micro-browser-based mobile thin clients, .NET-Compact-Framework- based smart clients are more reliable and faster because they are less dependent on the network and can cache aggressively to reduce network round trips. In today's unreliable, expensive, and slow wireless networks, offline operation capability is crucial to the success of a mobile application. In addition, smart clients offer richer user experiences via more interactive UIs that run locally on the device.

Compared with C/C++ native applications, .NET smart clients are easier to develop and less prone to errors, thanks to the advanced programming language/tool support in .NET and the managed execution environment. Since mobile devices have limited memory space and processing power, most smart clients delegate some data- or computation-intensive tasks to back end servers. The .NET Compact Framework offers superb support for XML web services, which allows us to build connected smart clients that easily integrate into the existing service infrastructure.

The .NET Compact Framework is specifically designed to follow the same application models and APIs that are available in the regular .NET framework. Together with familiar tools such as Visual Studio .NET 2003, it is very easy for a desktop or server-side .NET developer to get started with the Compact Framework. However, despite the apparent similarity in development environments, mobile devices and networks are different from PCs and Ethernets in several fundamental ways. Blind skill transfer from PCs to devices is often a source of frustration or even project failure. As developers, we have to understand the special requirements and characteristics of networked mobile applications. Now, let's first have a look at the sample application.

Introducing the MapPoint Smart Client Application

The sample application is a driving directions application powered by the MapPoint web service. On a connected Windows Mobile device, it works as follows: the user taps from and to addresses into the UI form; the device queries a GIS (Geographic Information System) server, and then displays driving directions and turn-by-turn driving maps. It allows the user to look up driving directions any time, from anywhere in the field. Figure 1 shows the workflow.

The workflow of Driving Directions application
Figure 1. The workflow of the Driving Directions application

The complete source code of the application is available from here. To build and test the front-end mobile smart client, you have to have Visual Studio .NET 2003 and the PocketPC 2003 and Smartphone 2003 SDKs installed. Both SDKs are freely available from Microsoft's mobility web site.

MapPoint Web Service

At the back end, the Microsoft MapPoint web service, a hosted GIS solution, drives the application. A GIS server stores and processes geographic information. For example, the GIS server can: convert a street address to a pair of longitude and latitude coordinates, and vice versa; find the best route to connect two addresses; check yellow pages listings against addresses; find out points of interest (e.g., landmarks and shops) and potential hazards (e.g., construction sites and underground pipes) around a certain location or a route. GIS is widely used in military, city planning, construction, transportation, tourism, and many other industries. It helps planners to design the most efficient strategy and prepares field personnel for new environments. MapPoint takes care of the day-to-day GIS server management, as well as the licensing of up-to-date, high-resolution digital maps. Users pay for its services on a per-use or subscription basis. A big advantage of MapPoint is that it is accessible through an open SOAP web service interface. Being a web service ensures that MapPoint is ubiquitously available to a large variety of client and middleware applications.

Although we make use of the MapPoint SOAP API in the sample application, API usage is not the focus of this article. Interested readers can find the C# and VB.NET API reference in the MapPoint SDK from MSDN. In order to run the application, you need a service account with MapPoint. You can sign up for a 45-day free evaluation account, replace the account credentials in the MPfacade.asmx.cs file with your own, and then re-build the application.

Web Services Facade

MapPoint is a utility service. It offers fine-grained access to its GIS services. This allows us to write flexible applications without arbitrary limitations imposed by the API designer. However, the tradeoff is that we have to make many small-step method calls to complete a task. For example, in order to get driving directions between two addresses, we must complete the following steps:

  1. Convert the addresses to latitude and longitude coordinates.
  2. Calculate the route according to options.
  3. Render the overview map with the route and start/end locations highlighted.
  4. Retrieve turn-by-turn instructions for each route segment.
  5. Render highlighted turn-by-turn maps for each route segment.

The last two steps need to be repeated many times for a long route with many segments. All of those calls are remote SOAP RPCs performed over the network. For clients that only need to perform simple, pre-scripted GIS tasks (e.g., our driving directions client), those RPC round trips are excessive and cause drastic performance degrade over wireless networks. Therefore, it is not advisable to access the MapPoint web service directly from mobile clients. To minimize the round trips over wireless networks, we place a remote facade in front of the MapPoint web service.

A remote facade is a design pattern to provide a coarse-grained access interface to a set of complex remote subsystems. It is designed to shield the client from the complexity of subsystems. As a result, network round trips are greatly reduced. The facade pattern is probably the most widely used architectural pattern in end-to-end mobile applications. In our application, the facade takes in two human-readable addresses in a single RPC call from the wireless client, queries MapPoint via a sequence of remote calls over the wired Internet, constructs the resultant driving directions, and finally returns the results. The overall architecture and the facade call model are illustrated in Figure 2.

The Web service facade
Figure 2. Smart mobile application architecture

Web Service: FacadeServer

In our example, the facade is implemented using ASP.NET web services. The FacadeService class in the project MPfacade supports web methods such as getSessDirections (i.e., get text directions) and getSessMap (i.e., get a map), which utilize the MapPoint web service to complete their tasks. To understand the MapPoint API calls in the facade, please refer to the MapPoint SDK. The facade essentially aggregates the complex MapPoint API into several simple web methods.

Mobile Client: FacadeClient

On the client side, we need to support both the PocketPC and Smartphone UIs. Those two UIs must be developed in two separate projects, since the two devices have different screen sizes and support different sets of designer widgets. To reuse the business layer code, we put all of the facade-client code in the FacadeClient project. Both UI projects contain references to the FacadeClient project. In the next section, we will discuss the interaction between the .NET Compact Framework client and the ASP.NET facade.

Client and Server Integration

At a glance, it is trivial to build a mobile client for the facade. We could just add the facade service as a web reference to the project FacadeClient. However, by default, remote web service calls are stateless. Each request is independent. Without remembering the user state, the server needs to start fresh for every new request. In our example, that means it must build the entire route over again every time the client requests a segment map; this is very inefficient. A much better solution is to cache the calculated route in the facade server. In a multi-user environment, we have to retrieve the correct route object from the cache for each user. That requires the facade server to recognize requests from the same user and group web service requests into sessions. It works as follows.

When the client makes its first request, the server creates a session object and an ID. The ID is returned to the client. The client stores the ID and puts it in all subsequent requests to the same server. The server will then have a way to identify and link the request with session objects. The key is to exchange and keep track of session IDs. In the next two sections, we discuss two session tracking techniques: utilizing HTTP cookies and building session IDs into the RPC protocol.

HTTP Cookies

Since all of our web services calls in this example are made over the HTTP transport, we could leverage HTTP's built-in session tracking mechanism, HTTP cookies. Cookies are pieces of session identification strings embedded in HTTP headers. When the client makes its first connection, the ID is created and returned to the client via the HTTP Set-Cookie header. If the client is cookie-aware, it stores the cookie and puts it in the Cookie header in all subsequent requests. This is the best way to track sessions in ASP.NET applications, since the cookies are handled transparently to the application developers, and this makes efficient use of the HTTP infrastructure. To write cookie-aware ASP.NET web methods, we just need to add a true attribute in the method's meta data tag. A session object that is uniquely associated with the current cookie can be retrieved from the runtime context. We can cache the calculated route in the session object.

private CachedRoute getCache() {
  CachedRoute cache = (CachedRoute) Session["CachedRoute"];
    
    // This is a new session
  if (cache == null) 
  {
    cache = new CachedRoute ();
    Session["CachedRoute"] = cache;
  } 
  return cache;
}

[WebMethod(true)]
public String [] getSessDirections (String fromStreet, String fromCity, 
  String fromState, String fromZip, String toStreet, String toCity,
  String toState, String toZip) {
  CachedRoute cache = getCache();
  return getDirections(cache, fromStreet, fromCity, 
    fromState, fromZip, toStreet, toCity, toState, toZip);
}

All the client needs to do is to receive and remember the cookie. However, the .NET Compact Framework v1.0 HTTP client library does not have built-in cookie support (the CookieCollection object is not supported). In the .NET Compact Framework Service Pack 1 (SP1), which is built into Smartphone 2003 but requires manual install on PocketPC 2003, the application developer can override the GetWebRequest and GetWebResponse methods in the VS.NET-generated SOAP client-proxy class. We can manually build a decorator class that subclasses the client proxy and add cookie-handling logic to the GetWebRequest/GetWebResponse methods. The code snippet below shows the cookie-aware decorator methods. FacadeService is the web service proxy class generated by VS.NET when we added the web reference.

public class SessionFacadeService : FacadeService 
{
  private static string cookie = null;

  protected override WebRequest GetWebRequest(Uri uri) {
    HttpWebRequest req = (HttpWebRequest) base.GetWebRequest(uri);
    if (cookie != null) 
    {
      req.Headers.Add("Cookie", cookie);
    }
    return req;
  }

  protected override WebResponse GetWebResponse(WebRequest req)  {
    HttpWebResponse rep = (HttpWebResponse) base.GetWebResponse(req);
    if (rep.Headers["Set-Cookie"] != null) 
    {
      cookie = rep.Headers["Set-Cookie"];
    }
    return rep;
  }
}

Session ID in the RPC Protocol

For earlier devices that cannot upgrade to Service Pack 1, we cannot easily use cookies on the client side. The solution is to build the session ID into the RPC protocol as a mandatory call argument. An added benefit here is that this solution is not dependent on the underlying HTTP transport. If we extend the service in the future beyond HTTP (e.g., over an asynchronous messaging protocol), this approach would still work.

In this setup, the facade web method getSID creates an empty CachedRoute object, generates a random session ID based on the current time, stores it in the global cache, and then returns the session ID.

Random rand = new Random ();

[WebMethod]
public String getSID () {
  String sid = DateTime.Now.Ticks.ToString() + rand.Next().ToString();
  Context.Cache.Add(sid, new CachedRoute(), null, DateTime.MaxValue, 
                    TimeSpan.Zero, CacheItemPriority.Default, null);
  return sid;
}

The getSID method must be invoked at least once before any other facade remote method can be called. When a session ID is passed to a remote service method, the server calls the getCache method to locate the proper CachedRoute object.

private CachedRoute getCache(String sid) {
    return (CachedRoute) Context.Cache.Get(sid);
}

The getDirections method populates the CachedRoute object with route and segment objects; the getMap method renders a GIF map for the requested segment based on the route information in the CachedRoute object.

[WebMethod]
public String [] getSidDirections (String sid, String fromStreet, 
          String fromCity, String fromState, String fromZip, 
          String toStreet, String toCity, String toState, String toZip) {
  CachedRoute cache = getCache(sid);
  return getDirections(cache, fromStreet, fromCity, 
    fromState, fromZip, toStreet, toCity, toState, toZip);
}

In fact, a mobile client can cache several different routes using different session IDs. We can manage those IDs on the client side and further improve the efficiency of the application.

The Facade Client

The facade client MPClient has a useCookie flag, which indicates whether the client wants to use HTTP cookies for session tracking. Depending on the useCookie flag setting, MPClient instantiates the appropriate proxy object and dispatches to the corresponding remote methods.

public class MPClient {
  private String sid;
  private bool useCookie;
  private FacadeService facade;

  public MPClient(bool useCookie) {
    this.useCookie = useCookie;
    if (useCookie)  {
      facade = new SessionFacadeService ();
    } else  {
      facade = new FacadeService ();
      sid = facade.getSID ();
    }
  }

  public String [] getDirections(String fromStreet, String fromCity,
    String fromState, String fromZip, String toStreet,
    String toCity, String toState, String toZip) {
    if (useCookie) {
      return facade.getSessDirections(fromStreet, fromCity,
        fromState, fromZip, toStreet, toCity, toState, toZip);
    } else {
      return facade.getSidDirections(sid, fromStreet, fromCity,
        fromState, fromZip, toStreet, toCity, toState, toZip);
    }
  }

  // ...

}

For example, in the Smartphone UI, we use cookies for session tracking, while in the PocketPC UI, we use RPC arguments.

UI Design

With the facade in place, now it is time to develop the mobile front-end UI. We use the Windows Form visual designer in Visual Studio .NET for this task. As shown in Figure 3, the .NET Compact Framework visual UI designers for both Smartphone and PocketPC offer a wide selection of widgets and produce realistic-looking design layouts.

PocketPC and Smartphone Windows Form designers
Figure 3. PocketPC and Smartphone Windows Form Designers

All widgets have the native PocketPC or Smartphone look and feel. Services from the underlying OS, such as multiple text entry methods and predictive text, are available. The UI event-handling model is intuitive and takes advantage of advanced .NET language features such as the C# delegates.

PocketPC

PocketPC widgets such as the tabbed control, contextual menu, progress bar, and DataGrid are very useful in making the best use of the limited screen real estate on the pen-based mobile UI. The PocketPC client is based on tabbed pages navigation and it is shown in action in Figure 4.

The PocketPC 2003 UI in action
Figure 4. The PocketPC 2003 UI in Action

Smartphone

On Smartphones, fewer widgets are supported, due to the limited screen size and input methods (the gray controls on the designer are not supported). In particular, the button control is not supported. Instead, you have to use the menu control, which will be mapped to the two soft buttons on the Smartphone device. The left-side soft button can only be mapped to a single menu item for "one hand" operation. The right-side button can be mapped to a hierarchy of sub-menus. The smartphone client is based on multiple forms navigation (Figure 5). A static Controller class holds references to those forms and controls their display.

The Smartphone 2003 UI in action
Figure 5. The Smartphone 2003 UI in Action

public class Controller : System.Windows.Forms.Form {
  private static FromAddr from;
  private static ToAddr to;
  private static DirectionsList directionsList;
  private static DrivingMap drivingMap;
  private static Form current;

  private static MPClient mpclient;
  // ... ...
  
  // To enforce singleton pattern for the controller
  private Controller() {
    // We use HTTP cookie for session tracking
    mpclient = new MPClient (true);
  }
  
  static void Main() {
    from = new FromAddr ();
    to = new ToAddr ();
    directionsList = new DirectionsList ();
    drivingMap = new DrivingMap ();
  
    Application.Run(new Controller());
  }
  
  public static void showDirections (bool reload) {
    if (reload) {
      String [] directions = mpclient.getDirections(
               from.street, from.city, from.state, from.zip,
              to.street, to.city, to.state, to.zip);
      ArrayList al = new ArrayList ();
      al.Add("Overview Map");
      for (int i = 0; i < directions.Length; i++ ) {
        al.Add( directions[i] );
      }
      directionsList.listSource = al;
    }
    showForm (directionsList);
  }
  
  public static void showMap ()
  {
    int index = directionsList.selectedIndex;
    byte [] imgarray = mpclient.getMap(index, 160, 160);
    drivingMap.imageSource = 
      new Bitmap (new MemoryStream(imgarray));
    showForm (drivingMap);
  }

  public static void exit ()
  {
    from.Dispose ();
    to.Dispose ();
    directionsList.Dispose ();
    drivingMap.Dispose ();

    Application.Exit ();
  }
  
  // ... ...
}

Summary

The web-services-driven smart client is not only a powerful application paradigm for mobile solutions, but also a future convergence point of today's desktop and web applications. The .NET framework and .NET Compact Framework provide excellent support for this paradigm. In this article, we only scratched the surface by covering the simplest types of ASP.NET web methods. The .NET Compact Framework can be used to handle complex web-service protocols. An excellent article about using the .NET Compact Framework for WebService Enhancements (WSE) can be found here.

In this article, we introduced the web services facade -- a key component in many such systems. We also discussed web service integration issues that are specific to the current versions of the .NET Compact Framework. Near the end, we covered effective UI designs for different devices. Now, it's your turn to make the most out of that PocketPC or Smartphone device you got last Christmas!

Michael Juntao Yuan specializes in lightweight enterprise / web application, and end-to-end mobile application development.


Return to ONDotnet.com

Copyright © 2009 O'Reilly Media, Inc.