WindowsDevCenter.com
oreilly.comSafari Books Online.Conferences.

advertisement


AddThis Social Bookmark Button

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;
  }
}

Pages: 1, 2

Next Pagearrow