How to Use ASP.NET MVC 4 Display Modes in Mobile Web Apps
Use display modes to serve up different views for desktop and mobile web browsers
January 2, 2013
![How to Use ASP.NET MVC 4 Display Modes in Mobile Web Apps How to Use ASP.NET MVC 4 Display Modes in Mobile Web Apps](https://eu-images.contentstack.com/v3/assets/blt07f68461ccd75245/blt8f8016af80c312b0/6619442d289adc7255646d2b/mobilephone-600-300_0_4.jpg?width=1280&auto=webp&quality=95&format=jpg&disable=upscale)
The web developer community has long supported mobile website development. Developers have used a variety of techniques, some client-based and someserver-based, to accommodate the widest range of browser clients. In this article, I'll discuss a feature in ASP.NET MVC 4 called display modes that givesASP.NET web developers more help in supporting a variety of browsers in their mobile web applications. I will explain how using display modes helps withmobile browser detection in web apps, then demonstrate how to use display modes in a sample ASP.NET MVC 4 web application. But first, we'll look briefly atsome options that have been available to web developers for dealing with mobile websites.
Handling Mobile Websites
One technique, specific to the client, has been to create a responsive web design, using Cascading Style Sheets (CSS) to expand or contract the websitedepending on the available viewport. Sites like this have rolled their own CSS or used a framework such as Twitter Bootstrap or the 960 Grid System.Another technique is to create a flexible design with percentage-based widths, so that the page naturally expands or contracts as the viewport changes.More options exist, and all these options are valid client-side options for handling multiple-sized viewports.
We are not limited to solutions on the client to solve the problem, however. When it comes to server-side technologies, mobile development has always been an option inWeb Forms and ASP.NET MVC. For instance, Scott Hanselman previously published acustom view enginefor ASP.NET MVC 3 that provides mobile support. The view engine detects information about the browser making the request, and if it determines that thebrowser is a mobile browser, the view engine serves up a mobile view to the client.
The WURFL and 51Degrees.mobi frameworks also support Web Forms and MVC; each of these products candetect a mobile device and redirect to another page or perform another action. Common to the .NET Framework is the ability to detect a mobile browser usingthe HttpRequest.Browser.IsMobileDevice property. However, solutions like WURFL and 51Degrees.mobi use a custom database with device configurations thatprovide more advanced capabilities than the .NET Framework.
With ASP.NET MVC 4, the .NET Framework solves some of these problems through the display modes feature but goes further in its solution. The display modesfeature provides an alternative view mechanism that is displayed to the user when a certain condition is met. Display modes are not restricted to mobileviews, though that is the feature's primary use. A display mode uses a lambda expression, matching a condition on the HttpContextBase class. If thecondition matches, the specific view to the display mode is served up from the view engine to the user. Note that we are not talking about separatecontrollers, just the views themselves.
Creating a Display Mode
As I mentioned, the most common scenario is a mobile view, whereby the display mode detects a mobile browser and serves up a mobile view. However, limitinguse of a display mode to only serving up mobile views does a disservice to the feature. Display modes can serve a variety of purposes. A display mode couldbe a mode that checks the current user's authentication status and serves up an unauthenticated view to the anonymous user. A display mode could check asingle type of device (such as an iPad).
From a more technical perspective, a display mode in ASP.NET MVC is represented by the IDisplayMode interface and subsequently the DefaultDisplayModeclass. The MVC framework uses the DefaultDisplayMode class to represent both desktop and mobile browsers.
It might seem odd to use the same class to represent both types of browsers. However, the display mode uses a public ContextCondition property with agetter and setter, taking a lambda expression that specifies a matching condition. This lambda expression accepts a reference to HttpContextBase, returninga Boolean; this means that whatever condition you want to match on the current request is pretty easily achievable. By default, the mobile definitionchecks the HttpContextBase.GetOverriddenBrowser().IsMobileDevice property to see whether the device is a mobile device. GetOverriddenBrowser() is a newextension method on HttpContextBase for getting an instance of the browser.
There are two ways to create a custom display mode. The first way is to instantiate the DefaultDisplayMode class and set the ContextCondition property, asexplained previously. The second way is to create a class that inherits from the DefaultDisplayMode class and set the ContextCondition property in theconstructor. I chose the latter option, as shown in Listing 1.
Listing 1: Opera Mobile Emulator Display Mode
public class OperaMobiDisplayMode : DefaultDisplayMode{public OperaMobiDisplayMode(): base("Mobile"){ContextCondition = (context => IsMobile(context.GetOverriddenUserAgent()));}public static bool IsMobile(string useragentString){return useragentString.IndexOf("Opera Mobi", StringComparison.InvariantCultureIgnoreCase) >= 0;}}
One shortcoming of the .NET Framework's support for checking a mobile device is that .NET does not support Opera Mobile Emulator. To support Opera MobileEmulator for testing purposes, the display mode in Listing 1 loads a mobile view when ASP.NET MVC detects a user agent string containing "Opera Mobi".Display modes always have a fallback; this means that if a view does not match the naming convention set up by the display mode, the default display modeis used. Using this design, we can easily support and isolate displays for all kinds of devices, simply by checking the user agent or any other HTTPrequest parameter.
Now that we have the display mode, we can register it in the Application_Start event handler, as in Listing 2. The display mode is inserted into theDisplayModeProvider.Instance.Modes collection. Once the display mode is in the collection, any request by an Opera Mobile Emulator serves up a mobileversion, as defined by the string sent to the base constructor.
Listing 2: Registering Display Modes
protected void Application_Start(){DisplayModeProvider.Instance.Modes.Insert(0, new UnauthenticatedDisplayMode());DisplayModeProvider.Instance.Modes.Insert(0, new OperaMobiDisplayMode())}
Display modes are executed in order, so it's important that you insert them in the correct order. Note there are two already defined in the Modescollection.
Let's look at another example, this time thinking out of the box. For instance, maybe you want to display a view for a user who is not authenticated on thewebsite. A display mode can interrogate the current principal for its authentication status and display a separate view just for unauthenticated users.Take a look at the code sample in Listing 3; since the display mode is based upon HttpContextBase (the type of the sole parameter), we can interrogate thecurrent principal for its authentication status.
Listing 3: Display Mode for Displaying a Separate View for Unauthenticated Users
public class UnauthenticatedDisplayMode : DefaultDisplayMode {public UnauthenticatedDisplayMode(): base("Unauthenticated") {this.ContextCondition = ctx => ctx.User == null || ctx.User.Identity.IsAuthenticated == false;}}
In the base constructor, note that we pass "Unauthenticated", which needs to be part of the name of the view (as in Home.Unauthenticated.cshtml).
Note that using a display mode in this way could lead to collisions; it becomes more difficult to display an unauthenticated mobile view, as two displaymodes cannot coexist. Furthermore, creating hybrid display modes can easily lead to organized chaos. Plan the use of this feature carefully.
Setting Up an Alternative View
An alternative view has the same name as an action method, but with an additional suffix. Let's set up an alternative view for the Index action method inthe Home controller. With an already existing Index.cshtml in place, we can add a second view using the Add View screen in Visual Studio, shown in Figure1.
Figure 1: Creating an Alternative View
To begin, right-click the view folder and create a new view. In the Add View dialog box, enter the name view.Mobile, and specify the appropriatemodel.
Now we have two views, Index.cshtml and Index.Mobile.cshtml, both linked to the Index action. You might wonder how mobile views work with layout pages.After all, a mobile view could refer to a separate mobile layout file. This is in fact how it can be done: An application can have _layout.cshtml as theroot layout page, while using _layout.Mobile.cshtml as the mobile layout. This allows the application to point to the same layout page definition but usediffering layouts, depending on the current display mode.
For setting up the markup of a mobile view, Microsoft includes jQuery Mobile,jQuery's mobile framework designed to provide a native experience on a mobile device. jQuery Mobile is easy to set up and straightforward to implement (youcan find an example of using jQuery Mobile in my article "Get Started Using jQuery Mobile for Mobile Web Development"). However, you are not required to use jQuery Mobile. I chose not to use it, instead opting for a minimalist design. Going with a minimalist designensures that the page size stays small and works on the largest variety of browsers available.
Testing Display Modes
The task of testing display modes can be complicated if you don't have a variety of devices to test on and accessible web space to host your application.Following are some utilities that can help you in this regard:
There are also various third-party utilities that are helpful with mobile testing -- for example, BrowserStack or Keynote MITE. Some available utilities emulate a browser within an existing browsersession. Using these emulators gives you a better idea of what's going on in your application, although the emulator results are not a guarantee of howyour website will look on the actual device.
Sample Application
Let's look at a sample application using customer-related data from the SQL Server AdventureWorks sample database. The application uses two views, one fordesktop and one for mobile. For desktop browsers, the application displays a table structure that shows all the customer information in a single row. Thetable is one of the more common representations of user data, as it provides an efficient means for viewing data. Take a look at Listing 4.
Listing 4: Displaying a List of Customers in a Table
@foreach (var customer in customers){}IDAccountTypeSales [email protected]@customer.AccountNumber@(customer.CustomerType == "S" ? "Store" : "Internet")@customer.SalesTerritory.Name@customer.ModifiedDate.ToShortDateString()@Html.ActionLink("View Sales", "View", "Sales", new { c = customer.CustomerID }, null)
This table works great for desktop browsers, but it's too wide to display on a 480px screen. To give users a better mobile experience, the table istransformed into a vertical structure, using a series of div elements. Using a vertical flow ensures no vertical scrolling, fits the page easily within a480px width, and can expand when the device rotates to landscape. Take a look at the alternative in Listing 5.
Listing 5: Customers View in Mobile Format
@foreach (var customer in customers){@customer.AccountNumber (ID# @customer.CustomerID)Type: @(customer.CustomerType == "S" ? "Store" : "Internet")Territory: @customer.SalesTerritory.Name@customer.ModifiedDate.ToShortDateString()@Html.ActionLink("View Sales", "View", "Sales", new { c = customer.CustomerID }, null)..}
The default view renders using a table, as shown in Figure 2.
Figure 2: Rendering the View for a Desktop Browser
For a mobile browser, the view transforms vertically using div elements, as in Figure 3.
Figure 3: Rendering the View for a Mobile Browser (Opera Mobile Emulator)
Be aware that JavaScript's varying support for accommodating different types of devices will make debugging mobile web apps more difficult. Modern desktopbrowsers provide a lot of convenient information that informs developers of everything going on within the lifecycle of a page. jQuery is usually a safebet for mobile web apps because of the amount of effort its developers spent on achieving cross-browser compatibility. An alternative strategy could be touse graceful degradation, whereby the view is set up as a server-side solution that jQuery "takes over," handling certain UI features on the client side.
I've chosen to use jQuery for the following example, which requests an action method and returns a partial view through a $.ajax call. The contents arereturned as a string and injected into the UI. Listing 6 renders a table; the individual details of each sale load in the next row, dynamically populatedupon the user's click of a link.
Listing 6: Loading Details Data Using Ajax
@foreach (var sale in sales){..Details}
Each details row has a unique ID, using the primary key as a unique-name generator. When the Details link is clicked, the details view is toggled. When thedetails view is displayed, the loadDetails method makes an Ajax request to load sales data and injects in the HTML response. The view could have renderedthe additional markup on the server; however, doing that would increase the size of the page and could slow its rendering. It's more efficient to use Ajaxto populate this extraneous content, which the user might not even view.
Points to Consider When Using Multiple Views
Let's look at what we just created. The application serves two views from a single controller's action method. This means we have two views with nearlyidentical code, now duplicated. The most challenging aspect of code duplication is the need to keep markup in sync while making the appropriate mobile viewadjustments. The more display modes you have, the more maintenance required, which must be factored into any solution.
There are several ways to work around this challenge. A global helper can store snippets of markup in a centralized place, but this method does not alwayssolve the duplicate-rendering problem. Partial views provide the same benefit and have the same drawbacks. The Html.Action method can have a different setof drawbacks, with not as many solutions. In some scenarios, I relied on using custom HTML helpers, componentsthat more easily masked the complications of multiple views. The real complexity we developers face is that different data structures are needed fordifferent viewports, making it harder to define a common user interface.
An interesting point to note from Listing 4 and Listing 5 is that both views implement the same rendering technique. A view can be built in a variety ofways: on the server, on the client loaded from an Ajax request to the server that returns UI markup, or via JSON and client-side binding through aframework like Knockout. Withthe first approach, the view renders on the server using a server-side model instance that has data. With the latter two options, the initial view renderswithout a server-side model.
It's important for both views to use the same rendering approach -- otherwise, the architecture becomes radically more difficult. For instance, if youwanted to use a client-side templating approach using Knockout on a desktop browser, but a server-side approach for mobile devices, the challenges ofhandling the two different responses can be handled, but doing so is much more difficult. It would require the action method to know the renderingtechnique used, which creates a tight coupling. For instance, the action method in Listing 7 is built with the mindset of a server-side rendering approach.
Listing 7: Action Setup for Server-Side Rendering
public ActionResult All(int page = 0){const int count = 20;ViewBag.Page = page;var ctx = new AdventureWorksEntities();ViewBag.Sales = ctx.SalesOrderHeaders.OrderByDescending(i => i.ModifiedDate) .Skip(page * count).Take(count).ToList();return base.View();}
If we were, alternatively, using a client-side rendering approach, we would not be loading the data at the time of rendering the view. Instead, a separateaction method would return JSON data to the caller. With this approach, we find ourselves customizing the action methods to the response when the desktopview uses client-side rendering and the mobile view uses server-side rendering.
Each device has different hardware capabilities; not all devices have quad-core processors like the Google Nexus 7. Slower devices might render markup moreslowly, especially for web applications that use a lot of JavaScript. There are various reasons for this: As JavaScript modifies the Document Object Model(DOM), the browser triggers a repainting of the page. More repaintings or reflows of the page mean the browser spends more time rendering the UI.
Finally, when desktop browsers were the predominant browsers in use, developers could get away with supporting only three to five browsers. Now developershave to factor in many more browsers and varying levels of support for browsers depending on the device's OS version.
The Power of Display Modes
As you've seen, ASP.NET MVC 4's display modes feature is a powerful tool for mobile development -- but the display modes feature is not limited to mobileweb apps. You can use display modes to display any alternative view, which is tied to an existing controller. Defining a custom DefaultDisplayModeimplementation enables an alternative display mode to support mobile devices, a specific device (like an iPad), unauthenticated users, or whatever otherconditions you can think of. Display modes in MVC work by allowing you to define a second view (or additional views) with the same name but a differentsuffix matching what the display mode expects. A display mode is registered with the DisplayModeProvider instance.
Desktop browser applications tend to lay out the user interface horizontally, whereas for mobile devices with smaller viewports (especially when limited inportrait mode at 480px), you'll want to render content more vertically. Doing so renders the page on the client with minimal horizontal scroll. All viewimplementations can render using data on the server or client, but it's important to pick a consistent approach when creating the user interface. Using adifferent approach per display mode can work, but implementation is significantly more difficult.
Brian Mainsis a Microsoft MVP and consultant with Computer Aid, where he works with nonprofit and state government organizations.
Email: [email protected]
About the Author
You May Also Like