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.
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.
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.

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.
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.
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:
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.

Figure 2. Smart mobile application architecture
FacadeServerIn 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.
FacadeClientOn 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.
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.
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;
}
}
|
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 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.
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.

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 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.

Figure 4. The PocketPC 2003 UI in Action
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.

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 ();
}
// ... ...
}
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.