August 2013

Volume 28 Number 8

Cutting Edge - Creating Mobile-Optimized Views in ASP.NET MVC 4, Part 2: Using WURFL

By Dino Esposito | August 2013

Dino EspositoOld memories of the browser wars of a decade ago still scare developers today. One of the reasons for the universal success of jQuery can be found in its ability to hide subtle and less-subtle differences in the Document Object Model (DOM) and JavaScript implementations across browsers. Today, developers supposedly can focus on features and forget about specific browser capabilities. Really? This is true for desktop browsers—but much less so for mobile browsers.

Mobile browsers form a space that’s much more fragmented than desktop browsers were a decade ago. The number of different desktop browsers to take into account can be measured in tens; the number of different mobile browsers has an order of magnitude of thousands. Device form factors likely will evolve in both directions—getting smaller as with smartphones and mini-tablets, but also larger as with smart TVs. The key to success today and tomorrow is in serving users of each class of devices an appropriate experience. For that, you need to detect the device first and then its capabilities.

The Good Old Browser Capabilities Database

Since version 1.0, ASP.NET has offered a browser capabilities database. The Browser property exposed by the HttpRequest object could be queried for a small set of capabilities of the requesting browser. The mechanics of the browser capabilities infrastructure are fairly simple and effective. When building the HttpRequest object, the ASP.NET runtime grabs the user agent string and runs it by the ASP.NET browser database. Using the user agent string as the key, it retrieves a list of known capabilities and stores values into an HttpBrowserCapabilities object that developers access via Request.Browser. As far as I can see, this feature is unique to ASP.NET, and no other Web development platform has anything similar.

As you look into the underpinnings of browser capabilities it should become clear that this framework suffers from a relevant shortcoming: To be effective, the database that stores browser capabilities must be constantly updated as new devices and browser versions hit the market.

Originally, Microsoft designed the browser capabilities framework to help distinguish among a few desktop browsers. The advent of mobile devices completely changed the magnitude of the problem. For a while, Microsoft supported the Mobile Device Browser File (MDBF) project (mdbf.codeplex.com), aimed at creating a rich database of capability definitions for individual mobile devices and browsers. The idea was that by simply replacing the standard .browser files you get with ASP.NET with the MDBF database, you could access detailed browser and mobile device information through Request.Browser. A couple of years ago, however, the project was discontinued. But the underlying idea remains quite valid and probably the most effective way to serve tailor-made and highly optimized content to a few classes of devices. I’ll explore how to do that using ASP.NET MVC 4. In the upcoming example, any information about devices is provided by the Wireless Universal Resource FiLe (WURFL) at wurfl.sourceforge.net. Among other things, WURFL is the Device Description Repository (DDR) used by many large organizations, including Google and Facebook. You can read more about WURFL and DDRs in my previous series of columns about mobile site development, starting with “Mobile Site Development: Markup” (msdn.microsoft.com/magazine/jj133814).

The Mobile Face of ASP.NET MVC 4

In ASP.NET MVC 4, by invoking the code in Figure 1 from within global.asax, you prepare the ground for having up to three different representations of the same Razor view.

Figure 1 Instructing ASP.NET MVC 4 to Support Up to Three Display Modes of the Same Razor View

public class DisplayConfig
{
  public static void RegisterDisplayModes(
    IList<IDisplayMode> displayModes)
  {
    var modeSmartphone = new DefaultDisplayMode("smart")
    {
      ContextCondition = (c => c.Request.IsSmartphone())
   };
   var modeTablet = new DefaultDisplayMode("tablet")
   {
     ContextCondition = (c => c.Request.IsTablet())
   };
   var modeDesktop = new DefaultDisplayMode("")
   {
     ContextCondition = (c => c.Request.IsDesktop())
   };
   displayModes.Clear();
   displayModes.Add(modeSmartphone);
   displayModes.Add(modeTablet);
   displayModes.Add(modeDesktop);
  }
}

RegisterDisplayModes instructs the ASP.NET MVC 4 runtime to consider three distinct display modes for each view. This means that every time a controller invokes a view, the actual name of the view (say, “index”) will be examined by the display mode provider and will be changed to index.smart or index.tablet if the context condition defined for smartphones or tablets is verified. The order in which display mode objects are inserted in the provider is key. The search, in fact, stops at the first match. Suppose, for example, that the HTTP request results in the following code:

public ActionResult Index(){  return View();}

While resolving the view name, ASP.NET MVC 4 will go through the display modes collection and first check the smartphone display mode. The context condition for smartphones returns either true or false depending on the implementation of IsSmartphone. If true, then a view with the “smart” suffix is selected if any exists. Otherwise, the search continues with the next available display modes.

Defining the number of display modes is up to you, as is deciding the conditions that determine which requests belong to which display modes.

To map a request to a display mode you need to do some device detection. However, you aren’t going to have one view for each possible device, but rather one view for each class of devices you intend to support in your application.

Making Device Detection Smart

At the end of the day, device detection is about sniffing the user agent string. User agent strings aren’t an exact science and might require a lot of parsing and normalization work to be digestible and easily mapped to a list of capabilities. Maintaining such a database is expensive, because you should look at every new browser version and device release and OS customization done by OEMs. In addition, for each unique device identified, you should figure out capabilities and store them efficiently in a database.

A few companies are active in this industry and sell their products according to various models, including fairly inexpensive cloud-based solutions. The most popular framework for device detection is the aforementioned WURFL—a cross-platform library available for a variety of languages that’s also open source according to the Affero General Public License (AGPL). For ASP.NET MVC 4 developers, WURFL is also available as a NuGet package. In the Microsoft .NET Framework space, another choice is provided by the 51Degrees database (51degrees.mobi). In the next section, I’ll examine how a device-detection framework can be used to route display modes in an ASP.NET MVC 4 application.

Adding WURFL to Display Modes

The code in Figure 1 is essentially centered on the Context­Condition delegate:

Boolean ContextCondition(HttpContextBase)

The signature is self-explanatory: It passes the HTTP context and expects a Boolean answer. The logic in the delegate should consume any information in the HTTP context and determine whether the request can be served a view as intended by the display mode. As an example, I’ll start from where I left off in my last column, “Creating Mobile-Optimized Views in ASP.NET MVC 4”  (msdn.microsoft.com/magazine/dn296507). The IsTablet method used in Figure 1 is an extension method added to the HttpRequestBase class. Here’s its code:

public static class HttpRequestBaseExtensions
{
  public static Boolean IsTablet(this HttpRequestBase request)
  {
    var ua = userAgent.ToLower();
    return ua.Contains("ipad") || ua.Contains("gt-");
  }
}

The quick evolution of mobile devices is making it more difficult to find and maintain a static definition of what a tablet or smartphone is. Being a tablet or a smartphone can hardly be considered as a physical characteristic such as whether the device supports Flash video (.flv) streaming or inline images. The class of device is more of a virtual capability whose definition is entirely up to the development team. Virtual capabilities typically are implemented as the logical combination of multiple physical capabilities.

To add WURFL to your ASP.NET MVC 4 code, just invoke NuGet and get the official WURFL API. The package installs the WURFL database—a zipped file—in the App_Data folder. The database is a relatively recent snapshot of device information; to get updates on a weekly basis, you need to buy a commercial license from ScientiaMobile (scientiamobile.com).

Once WURFL is in place, you add the following line to Application_Start:

WURFLManagerBuilder.Build(new ApplicationConfigurer());

This will load the database into memory and ensure that all the data is cached for the quickest possible access. To run a WURFL query, you need the following code that must run in each and every request for an HTML view:

var userAgent = ...; // Typically read from Request object
var device = WURFLManagerBuilder.Instance.GetDeviceForRequest(userAgent);

Again, the code is self-describing. The WURFL framework gets the user agent and returns (in a matter of milliseconds) all the information it knows about the device. The information is expressed in the form of a name/value collection where both the name of the capability and its returned value are strings. Turning strings into strongly typed data (for example, integers or Booleans) is your responsibility. WURFL offers more than 500 capabilities per device catalogued in several categories. Clearly, you’re not interested in all of them. I’d say that a more realistic number is one-tenth of that, which is also in line with the number of capabilities supported by the now-dead MDBF project. Anyway, that number amounts to a lot more capabilities than you can check with CSS3 media queries. Media queries have five total properties, only one or two of which (width and orientation) are often used. Here’s how to reliably check for tablets using WURFL:

public static class HttpRequestBaseExtensions
{
  public static Boolean IsTablet(this HttpRequestBase request)
  {
    var device =
       WURFLManagerBuilder.Instance.GetDeviceForRequest(userAgent);
   return device.IsTablet();
  }
}

IsTablet is an extension method to the WURFL IDevice type that I just created to overcome the weakly typed nature of WURFL:

public static Boolean IsTablet(this IDevice device){
  return device.GetCapability("is_tablet").ToBool();
}

Note that ToBool is yet another extension method that just wraps up a call to Boolean.TryParse.

The usefulness of extension methods to keep the code clear and elegant is even more apparent in the sample code that detects smartphones, shown in Figure 2. There’s probably no common definition of what a smartphone is that’s acceptable to everybody. By combining multiple WURFL properties, you can create your own definition of a smartphone, as shown in Figure 2.

Figure 2 Defining a Smartphone as a Virtual Capability

public static class HttpRequestBaseExtensions
{
  public static Boolean IsSmartphone(this HttpRequestBase request)
  {
    var device =
      WURFLManagerBuilder.Instance.GetDeviceForRequest(userAgent);
    return device.IsWireless() && !device.IsTablet() &&
      device.IsTouch() &&
      device.Width() > 320 &&
      (device.HasOs("android", new Version(2, 2)) ||
      device.HasOs("iphone os", new Version(3, 2)) ||
      device.HasOs("windows phone os", new Version(7, 1)) ||
      device.HasOs("rim os", new Version(6, 0)));
  }
}

The code in Figure 2 defines a smartphone as a wireless device that isn’t a tablet, is touch-enabled, is at least 320 pixels wide and runs any of the specified OSes. All of the methods used on the device variable are extension methods built on top of WURFL native capabilities.

Server-Side Detection and Client-Side Responsive Design

The focus in some segments of the industry on client-side detection of features is justified by the goal of leveraging advanced HTML5 and CSS3 capabilities in Web sites. However, this has little to do with making sites mobile-friendly. Client-side feature detection is limited to what the browser allows detection of—at best the five properties to which you gain access through media queries and whatever can be programmatically tested. To distinguish an Android device from an iPhone, you still need user agent sniffing—not to mention that running Android 2.2, for example, doesn’t say much about the actual device capabilities.

If you really need to serve ad hoc markup to devices (small and large), then server-side device and feature detection is the only way to go. WURFL makes it quick and easy. 

Server-side detection and client-side responsive design aren’t an either/or choice. Server-side detection is only about identifying the device and the related display mode. The markup you serve can easily contain media queries, liquid layouts and whatever else helps make the result better. If you like acronyms, this is what RESS (standing for Responsive Design + Server-Side Components) is all about. Server-side detection just adds one extra level of abstraction over the process of building tailor-made views.


Dino Esposito is the author of “Architecting Mobile Solutions for the Enterprise” (Microsoft Press, 2012) and the forthcoming “Programming ASP.NET MVC 5” from Microsoft Press. A technical evangelist for the .NET and Android platforms at JetBrains, and frequent speaker at industry events worldwide, Esposito shares his vision of software at software2cents.wordpress.com and on Twitter at Twitter.com/despos.

Thanks to the following technical expert for reviewing this article: Mani Subramanian (Microsoft)