August 2012

Volume 27 Number 08

Cutting Edge - Mobile Site Development, Part 3: Routing Requests

By Dino Esposito | August 2012

Dino EspositoMore often than not, a mobile site is the subset of a larger site built for a desktop audience. A desktop user often visits your site using, for example, a laptop with a high screen resolution and significant computing power. In addition, the user relies on stable connectivity and isn’t particularly concerned about draining the battery. All these parameters make a huge difference for architects and developers of Web sites, as well as domain experts. When it comes to mobile sites, the hardest part is not coding but figuring out the use cases to code—and before that, the business cases for which you want to have a mobile site (or a mobile application).

The mobile site exists to make it easier for users on the go to consume the most relevant services that you already expose through the main Web site. So let’s assume we have a well-defined set of use cases and we’re ready to start coding and producing some good markup. But, first and foremost, how do we reach the mobile site?

I firmly believe that a mobile site should be a standalone site that corresponds to a distinct IIS application. This greatly simplifies the development experience. You focus only on mobile use cases. You optimize rendering and the application layer only for mobile use cases. You deal only with technologies and tools related to mobile scenarios. Finally, you test it more easily.

On the other hand, as a user, I hate having to type a distinct URL just to view the mobile version of a site in which I’m interested. Wouldn’t it be great if you could just type or bookmark www.contoso.com and let the site figure out whether you’re coming from a mobile device or a laptop? Once your origin is ascertained, the site could possibly redirect you to the mobile site. Applying such a strategy can deliver a nice experience, but this requires some assumptions and having some machinery in place.

Routing Users to the Right Site

Let’s assume there are two distinct Web sites in place—say, www.contoso.com and m.contoso.com. The user, however, isn’t expected to know about the m-site; she only knows about the main Web site. So she types www.contoso.com into her mobile device. Some code hosted in the main site intercepts the request and examines the user agent string. If the request is coming from a desktop browser, nothing happens and the request proceeds as usual. If the requesting browser is hosted on a mobile device, the user is redirected to a landing page where she’s asked to choose between the full site and the mobile site. Figure 1 offers a graphical view of the strategy I’m outlining.

A Strategy for Routing Users to the Most Appropriate Site
Figure 1 A Strategy for Routing Users to the Most Appropriate Site

More generally, both sites have an interceptor that filters any incoming requests and redirects to a landing page if the requesting device isn’t compatible with the type of the site. To keep things even simpler, you can also let laptops view mobile pages if explicitly requested and host only one landing page for when the main site is requested from a mobile device.

This strategy only explains what to do on the first request to a site—typically directed to the homepage. For successive requests that the user can make as she works with the site, you don’t want the interceptor to kick in again and show the landing page. Let’s see how to implement this strategy.

An HTTP Module to Route Requests

In ASP.NET, the standard way to intercept incoming requests is installing a HTTP module. For each intercepted request, the HTTP module will examine the user agent string and determine whether or not the browser is hosted on a mobile device. If the browser runs on a mobile device, the HTTP module redirects the user to a given landing page; if not, it will simply let the request pass and be processed as usual. Figure 2 shows the source code of a sample HTTP module for routing mobile requests to a (mobile) landing page.

Figure 2 A Mobile Router Component Implemented as an HTTP Module

public class MobileRouterModule : IHttpModule
{
  private const String ForceFullSiteCookieName = "FullSiteMode";
  public void Dispose()
  {
  }
 public void Init(HttpApplication context)
 {
   context.BeginRequest += OnBeginRequest;
 }
 private static void OnBeginRequest(Object sender, EventArgs e)
 {
   var app = sender as HttpApplication;
   if (app == null)
     throw new ArgumentNullException("sender");
   // Check whether it is a mobile site
   var isMobileDevice = IsMobileUserAgent(app);
   // The mobile user confirmed to view the desktop site 
   if (isMobileDevice && ForceFullSite(app))
   {
     app.Response.AppendCookie(new HttpCookie(ForceFullSiteCookieName));
     return;
   }
   // The mobile user is navigating through the desktop site
   if (isMobileDevice && HasFullSiteCookie(app))
     return;
   // The mobile user is attempting to view a desktop page
   if (isMobileDevice)
     ToMobileLandingPage(app);
 }
}

There are basically three use-case scenarios. One is when the user with a mobile device reaches a landing page and confirms she wants to view the full site. Another scenario is when the mobile user requests a page on the full site because she’s following a link in one of the full-site pages. Put another way, the mobile user received the landing page, confirmed she wants to view the full site and is now navigating through the site. Finally, the third scenario is when the mobile user is trying to visit the full site for the first time in that browser session. In the first two cases, the HTTP module lets the request pass. In the last case, it simply redirects the mobile user to an ad hoc landing page.

The landing page will be a mobile-optimized page that shows a message to the user and offers links to the homepage of the desktop site or mobile site. Figure 3 shows a sample landing page. You can try it out live by pointing your own device to easycourt.net/contosoen.

A Sample Landing Page for a Mobile Site
Figure 3 A Sample Landing Page for a Mobile Site

The URL behind the “Mobile site” link points to the mobile site homepage. The other link points to the homepage of the full site with an extra query string parameter. The name and role of this parameter are up to you, but the name could be something like this: https://www.contoso.com?mode=full.

This parameter will be checked by the HTTP module through one of the functions mentioned in Figure 2, as shown here:

private static Boolean ForceFullSite(HttpApplication app)
{
  var full = app.Context.Request.QueryString["mode"];
  if (!String.IsNullOrEmpty(full))
    return String.Equals(full, "full", 
      StringComparison.InvariantCultureIgnoreCase);
  return false;
}

You see in Figure 2 that the user’s choice is stored in a cookie. This means that a user who expressly chose to navigate to the full site with a mobile device won’t be bothered any longer with a landing page as long as the cookie is available.

Before I discuss the structure of the landing page in more detail, let me specify how the HTTP module understands whether the user clicked to view the full site or is navigating through the full site. In Figure 2 you see that the following code is used to check whether the cookie for viewing the full site is found:

private static Boolean HasFullSiteCookie(HttpApplication app)
{
  var cookie = app.Context.Request.Cookies[FullSiteModeCookie];
  return cookie != null;
}

If there’s no cookie and no query string parameter, the user accessing the desktop site from a mobile device is simply redirected to the landing page:

private static void ToMobileLandingPage(HttpApplication app)
{
  var landingPage = ConfigurationManager.AppSettings["MobileLandingPage"];
  if (!String.IsNullOrEmpty(landingPage))
    app.Context.Response.Redirect(landingPage);
}

The key point is that the user might be redirected to the landing page only the first time she attempts to access a given desktop site from a mobile device. From that point on, any further requests have extra information that prevents the HTTP module from redirecting.

Detecting Mobile Devices

Of all the code you see in Figure 2, only one piece remains to fully explain: how you detect whether the requesting device is a mobile device. This can be achieved in different ways and with different levels of reliability. For example, you can simply rely on some code like that shown in Figure 4. It attempts to query the user agent string for some mobile-only keywords.

Figure 4 Querying the User Agent String for Mobile-Only Keywords

private static Boolean HasAnyMobileKeyword(String userAgent)
{
  string ua = userAgent.ToLower();
  return (ua.Contains("midp") ||
    ua.Contains("mobile") ||
    ua.Contains("android") ||
    ua.Contains("samsung") ||
    ua.Contains("nokia") ||
    ua.Contains("phone") ||
    ua.Contains("opera mini") ||
    ua.Contains("opera mobi") ||
    ua.Contains("blackberry") ||
    ua.Contains("symbian") ||
    ua.Contains("j2me") ||
    ua.Contains("windows ce") ||
    ua.Contains("vodafone") ||
    ua.Contains("ipad;") ||
    ua.Contains("maemo") ||
    ua.Contains("palm") ||
    ua.Contains("fennec") ||
    ua.Contains("wireless") ||
    ua.Contains("htc") ||
    ua.Contains("nintendo") ||
    ua.Contains("zunewp7") ||
    ua.Contains("silk");
}

The list of keywords isn’t exhaustive, but it’s fairly representative of the mobile universe. This code may be extended at will to make it work better and better as new devices appear and as more mobile users start visiting your site. But that’s precisely the point. Are you willing to constantly update this piece of code? Not having to revise such code is just one of the benefits that a Device Description Repository (DDR) offers. A DDR is a library built on top of a database that contains user agent strings. All a DDR does is parse the user agent and return a list of known capabilities. I said “known” and not “detected” because that’s precisely the case. A DDR gets its information statically from a frequently updated database. It doesn’t detect capabilities on the device. However, this is an advantage of DDR solutions rather than a limitation! Behind DDR there’s human intervention, and human work establishes whether a given device has a given capability. Some capabilities can be detected algorithmically, but the returned value isn’t always entirely reliable. Some other capabilities—the majority, in fact—can’t be detected algorithmically but can be useful to know in order to intelligently decide which markup to serve to a given device.

Popular DDRs for the ASP.NET space are Wireless Universal Resource File, or WURFL, and 51degrees, as discussed in my previous column (msdn.microsoft.com/magazine/jj190798). Because both of these frameworks have a free offering for limited (mostly cloud-based) use, you might want to pick one of them even if you only need to determine whether a device is mobile or not. At least you’ll save yourself the burden of frequently updating your IsMobile function to keep up with new devices and corner cases.

Optimize for Different Devices

Wrapping up, I believe that Web sites should offer an optimized set of pages to different devices, whether they’re smartphones, tablets or laptops. This is best achieved if you can offer different Web sites or at least physically different views that you can manage and maintain separately. However, this separation should always be transparent to visitors of the site. The site should be reachable through a unique URL. You let the underlying platform do the magic of understanding the type of device and switch to the most appropriate view. In my next column I’ll use DDRs to discuss an implementation of different views for different devices.


Dino Esposito is the author of “Architecting Mobile Solutions for the Enterprise” (Microsoft Press, 2012) and “Programming ASP.NET MVC 3” (Microsoft Press, 2011), and coauthor of “Microsoft .NET: Architecting Applications for the Enterprise” (Microsoft Press, 2008). Based in Italy, Esposito is a frequent speaker at industry events worldwide. Follow him on Twitter at twitter.com/despos.

Thanks to the following technical expert for reviewing this article: Pranav Rastogi