July 2013

Volume 28 Number 7

Cutting Edge - Creating Mobile-Optimized Views in ASP.NET MVC 4

By Dino Esposito | July 2013

Dino EspositoIf you scratch the surface of common-sense considerations about programming mobile sites, you find an inherent contradiction. On one hand, you hear people screaming about being (or willing to be) mobile-first in their approach to programming applications and sites. On the other hand, you often hear the same people praise CSS media queries and liquid layouts. The contradiction I see is that the common use being made of CSS media queries and liquid layouts doesn’t put the mobile perspective before everything—it’s not a mobile-first technique. In this article I’ll explain how to use server-side logic to offer up the best display for a given device, incorporating a new feature of ASP.NET MVC 4 called display modes.

The problem isn’t CSS media queries as a technology. The problem isn’t even responsive Web design (RWD) as the supporting methodology of CSS media queries—if not the technology’s inspiring philosophy. So what makes the use of CSS media queries and liquid layouts a “mobile-last” approach? A clue can be found right in the slogan used to push this approach: A single codebase can serve multiple views. In this perspective, CSS—a client-side technology—is used to switch between views, and JavaScript is used to adapt views further when CSS isn’t enough.

As I see things, in this approach there’s the underlying proposition of serving all devices the same content, just adjusting the page layout to fit the screen size. In doing so, you might not be able to offer the best possible experience to users. I believe you reasonably should aim at having a single codebase—a common ground of Web APIs—but should definitely focus on specific use cases for each class of devices you intend to support. The term “mobile” makes little sense today, as it’s being replaced by classes of devices such as smartphones, tablets, laptops and smart TVs—not to mention wearable devices such as eyeglass displays and smart wristwatches.

About a year ago, I presented in this column a server-side approach to take with ASP.NET MVC site development: to build ad hoc views for each class of supported devices (“Mobile Site Development: Markup,” msdn.microsoft.com/magazine/jj133814). I did that in the context of ASP.NET MVC 3. Nicely enough, ASP.NET MVC 4 comes with the aforementioned display modes, which easily can be employed to implement server-side logic that intelligently serves the best view and content for a given device. To be really effective, this approach requires that you know as much as possible about the capabilities of the requesting device. However, besides basic information about the screen size and current orientation, there’s not much else that can be detected on the client. You then need to resort to a server repository of device information.

Introducing Display Modes in ASP.NET MVC 4

Before I start delving deep into display modes, let me state up front that this article (as well as display mode technology itself) is mainly concerned with building a new, unique site that dynamically binds the same URL to different views. If you already have a Web site and want to provide a companion site optimized for some (mobile) devices, well, that’s a different story. You can still use this column as a guide for building the companion site, but unifying URLs with an existing parent site requires different tools.

In ASP.NET MVC 4, display modes are a system feature that extends the classic behavior of view engines with the ability to pick the view file that’s most appropriate for the requesting device. In the aforementioned article for ASP.NET MVC 3, I used a custom view engine for this purpose. In that solution I also was limited to Razor views. With display modes, your controller methods will still invoke, say, a view named Index, and the ASP.NET MVC runtime will instead pick up a view file named index.mobile.cshtml if the requesting device is known to be a mobile device.

This is great news, as it means you can still have a single codebase for your site. You just need to add extra CSHTML view files for each class of device you intend to support. To start playing with display modes, let’s have a look at the code sample in Figure 1.

Figure 1 The Standard List of Supported Display Modes

<h2>
  Display Modes currently active
  (@DisplayModeProvider.Instance.Modes.Count mode(s))
</h2>
<ul>
@{
  foreach(var d in DisplayModeProvider.Instance.Modes)
  {
    <li>@(String.IsNullOrEmpty(d.DisplayModeId)
      ?"default" :d.DisplayModeId)</li>
  }
}
</ul>

The page in the code in Figure 1 shows the standard list of supported display modes. Figure 2 shows the output generated by the page.

Default List of Display Modes
Figure 2 Default List of Display Modes

ASP.NET MVC 4 display modes follow a few conventions. In particular, each display mode is associated with a keyword. The keyword is used to compose the name of the corresponding view file. The default display mode is bound to an empty string. As a result, the following view files are correctly handled by any ASP.NET MVC 4 application without any further intervention from you: index.cshtml and index.mobile.cshtml.

To see a demo, copy the index.cshtml file to a new file named index.mobile.cshtml and add it to the project. To distinguish between the two files, add the following to the mobile file:

<div style="border-bottom: solid 1px #000">Mobile view</div>

If you run the application and test it using Internet Explorer or another desktop browser, nothing changes. Try hitting F12 to bring up Internet Explorer Developer Tools and set a mobile user agent (UA) by selecting Tools | Change user agent string, as shown in Figure 3.

Forcing a Mobile User Agent into Internet Explorer for Testing Purposes
Figure 3 Forcing a Mobile User Agent into Internet Explorer for Testing Purposes

I’ve already configured a few mobile and tablet UAs. For example, you can use the following, which identifies the requesting browser as an HTC Desire Android smartphone:

Mozilla/5.0 (Linux; U; Android 2.1; xx-xx; HTC Desire Build/ERE27)
AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2

Figure 4 shows what you get from the ASP.NET MVC 4 site. The page being served from the same pair of controller and action methods is index.mobile.cshtml. More important, all of this took place without any change in the programming style and without learning any new skills.

Switching to a Mobile View
Figure 4 Switching to a Mobile View

Going Beyond the Basics

What’s been discussed so far is the bare minimum of what you can—and should—do in your mobile site development. Two key points need to be addressed to turn display modes into a solution for a realistic site. One is exploring ways to add multiple display modes. The other is exploring ways to inject some ad hoc logic to detect devices more reliably.

The built-in logic used by ASP.NET MVC to detect mobile devices isn’t all that reliable. It probably works with most smartphones, but it fails with older cell phones. For example, consider the following UA:

SAMSUNG-GT-S3370/S3370DDJD4 SHP/VPP/R5 Dolfin/1.5 Qtv/5.3
SMM-MMS/1.2.0 profile/MIDP-2.1 configuration/CLDC-1.1 OPN-N

This UA refers to a legacy phone (fairly popular a couple years ago) running a proprietary OS and a WebKit-based custom browser. The phone doesn’t support Wi-Fi connectivity, but it does have surprisingly good HTML-rendering capabilities. The screen is tinier than most smartphones, but it’s touch-enabled. With the basic display mode support from ASP.NET MVC, this phone isn’t recognized as a mobile device and is served the full versions of pages. This has two drawbacks. First, users can hardly view content because it will be stretched and wrapped around the screen. Second, a lot of content will be downloaded, and because the phone doesn’t support Wi-Fi connectivity, all of this likely happens on a 3G connection—certainly slow and possibly expensive for the user.

When I raise this point, some people reply that their sites just don’t support these types of legacy phones. That’s perfectly sound, but wouldn’t it be nice to send a polite message to the user in that case instead of letting things go uncontrolled? To be able to send a message such as, “Sorry, the site can’t be viewed on your device,” you still need to recognize the device properly and understand that it’s different from, say, an iPhone. Furthermore, whether you can safely ignore legacy devices is a business—not implementation—decision. Not serving older generations of devices could affect your business beyond imagination. So, let’s see how to add multiple display modes to a site to properly serve multiple classes of devices.

Classes of Devices

A modern Web site offers the best possible experience regardless of the device type. “Best possible experience” means providing ad hoc use cases, selected data and specific functions. The resulting markup has to be device-specific. If you adjust things on the client, instead—as happens when you rely on CSS media queries—you actually have a unified vision of the pages and then just adapt them to tinier screens. This mostly means hiding some blocks, flowing some others vertically and perhaps requesting a lighter set of visuals. The unified vision of the page is often the desktop page. Personally, I wouldn’t call this a mobile-first approach.

By saying “device type,” I don’t mean distinguishing an iPhone device from a Windows Phone device. Rather, I aim to use logic that can serve different markup to smartphones, tablets and laptops. So in ASP.NET MVC 4, I’d have at least three display modes: smartphone, tablet and default (for desktop browsers). I’ll add a new DisplayConfig class to be invoked in App_Start (see Figure 5).

Figure 5 The DisplayConfig Class

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

The class first empties the provided collection of display modes. In this way, it gets rid of default modes. Next, the code fills up the provided system collection with a newly created list of display modes. A new display mode is an instance of the DefaultDisplayMode class. The name of the mode is set through the constructor. The logic that determines whether a given UA is matched is set through the property ContextCondition.

The ContextCondition property is a delegate that accepts an HttpContextBase object and returns a Boolean. The body of the delegate is all about snooping into the HTTP context of the current request in order to determine whether the given display mode is appropriate. In Figure 5, I use a few extension methods to keep code highly readable. Figure 6 lists those extensions methods.

Figure 6 Extension Methods to Keep Code Clear

public static class HttpRequestBaseExtensions
{
  public static Boolean IsDesktop(this HttpRequestBase request)
  {
    return true;
  }
  public static Boolean IsSmartphone(this HttpRequestBase request)
  {
    return IsSmartPhoneInternal(request.UserAgent);
  }
  public static Boolean IsTablet(this HttpRequestBase request)
  {
    return IsTabletInternal(request.UserAgent);
  }
  // More code here.
}

All the code discussed so far is pure infrastructure. You end up with one method to write for each display mode. Each method takes a UA and must return a Boolean answer. Here’s a very basic routine to check for tablets:

private static Boolean IsTabletInternal(String userAgent)
{
  var ua = userAgent.ToLower();
  return ua.Contains("ipad") || ua.Contains("gt-");
}

This routine is only guaranteed to successfully detect iPad and Galaxy Tab devices, but you can see the point about how these context condition routines should be written. You might want to add more code to check for smartphones, at the very least. To detect tablets and smartphones, you can take advantage of any open source or commercial Device Description Repository (DDR) framework. I’ll discuss that in more detail in my next column.

Serious Business

A server-side approach to mobile sites may not always be necessary, but it’s a serious matter whenever there’s some business behind the site. I wouldn’t recommend a server-side approach for, say, a conference site or any sort of short-lived site. However, a business site aimed at the largest possible audience needs to emphasize optimization for devices beyond just plain rendering for mobile.

On the client, you’re limited to browser window size and orientation, and you can’t check the OS or touch capabilities—or check for more advanced things such as whether the device supports wireless, streaming, inline images, SMS and more. Display modes make it particularly easy to implement a multi-view approach in  ASP.NET MVC 4.

In my next column I’ll cap off my argument by showing how to integrate the DDR used by Facebook—Wireless Universal Resource File (WURFL)—with ASP.NET MVC 4.


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: Mani Subramanian (Microsoft)
Mani Subramanian has been involved in development and testing of software projects for the past 12 years with a focus on SOA, cloud computing and core.net.