left-icon

ASP.NET MVC 4 Mobile Websites Succinctly®
by Lyle Luppes

Previous
Chapter

of
A
A
A

CHAPTER 4

Building an MVC Mobile Website

Building an MVC Mobile Website


Frodo: “Go back, Sam. I’m going to Mordor alone.”
Sam: “Of course you are. And I’m coming with you.”  
    From The Lord of the Rings: The Fellowship of the Ring

MVC 3 has the ability to create mobile-friendly code, but it isn’t a built-in feature. You have to write your own custom code and put it in the project, and it isn’t straightforward.

MVC 4 comes with the ability to turn on mobile support with just a few little lines of code in your application startup—it’s really simple to do. Let’s take a journey into the world of MVC 4 and mobile.

The Mobile Application Template

When you install MVC 42 and create your first project, you will immediately gravitate toward the Mobile Application template. It seems like the first thing you would go to, and you might be right. Let’s take a look at what it generates and see how that works out.

When you select this option, the template will generate a mobile website for you, and it will include the jQuery and jQuery.Mobile environments. jQuery.Mobile is one of the key components to easily making your website mobile-friendly. jQuery.Mobile is a framework built on top of jQuery that is designed to help you make mobile user interfaces. It doesn’t replace jQuery—it builds on it and enhances it. Spend a little time browsing the jQuery.Mobile site3, and you will find that they have spent a lot of time making it very easy to create mobile-friendly websites that play nicely on a variety of devices. The Microsoft team was wise to adopt this open-source project.

If you take this default project template and run it, you’ll see something like this:

Website Created with the Mobile Template

That’s not bad for a first start. However, there is one small problem with this approach: there is no desktop version!  This one serves up the mobile version to each and every device that comes to this website. It’s not mobile-friendly; it’s mobile-only.

If you think back to the previous chapter, and consider what you are trying to accomplish when building a mobile-friendly website, you will soon come to realize that you need to pay attention to three different form factors: small, medium, and large.

Form Factors to Consider for Mobile-Friendly Websites

And let’s not forget what’s coming your way in 2013!  Like it or not, you may have to think about this new format sooner than you think...

Project Glass, Anyone?

Trying to create one design that is going to work for all of these is usually an exercise in futility and will produce something that doesn’t work well on two out of three. We need some way to optimize our designs for each of the different platforms. Fortunately, that’s not too hard to do with the MVC platform.

The Internet Application Template

Let’s start again, and this time we’ll pick the Internet Application template. What we will get now is a website that is primarily optimized for the desktop platform. We’ll work with that and then enhance it to make it more mobile-friendly.

When you build and run this website, it will look almost exactly the same on your mobile device as it does on your desktop, as shown in the following pictures. Notice that in the mobile device view, the content has used a bit of responsive web design and re-flowed itself a bit to make it look a little bit better in that format.

Website Created with the Internet Application Template

For some websites, your mobile phone only shows a version of the site shrunk down to fit the screen of your mobile device (like my friend’s website that I mentioned in the first chapter). So why doesn’t our site based on the Internet Application template shrink down to a tiny version of itself? This template has avoided that problem by including one little line of magic code in its main layout page (look at \Views\Shared\_Layout.cshtml):

<meta name="viewport" content="width=device-width" />

That’s it!  The WebKit-based browsers used in the majority of mobile phones (like Android and iPhones) will respect that tag and will automatically try to resize and reflow the content to fit on the width of the current device. That’s one little tidbit you can apply to just about any website you are working on right now. (Go ahead. Go try it now on your current project. This book can wait. I know you want to.)

OK—are you back? Did it work? There are several other <meta> tags that we’ll discuss in Chapter 7 that can make your website more mobile-friendly—this is the first of many.

Our goal was to return different content to different types of devices. To do that, we will have to know what type of device is making the request, and for that we will look at the user agent. You probably already know that every time a browser sends a request to our server, it also sends a User-Agent string along with that request which identifies to the server what application is requesting the information. There are many different strings you might see. Here are a few examples:

  • Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5
  • Mozilla/5.0 (iPad; U; CPU OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5
  • Mozilla/5.0 (Linux; U; Android 2.3.5; en-us; HTC Vision Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
  • Mozilla/5.0 (BlackBerry; U; BlackBerry 9850; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0.115 Mobile Safari/534.11+
  • BlackBerry9700/5.0.0.862 Profile/MIDP-2.1 Configuration/CLDC-1.1 VendorID/167
  • Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 7.1; Trident/5.0)
  • Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; SLCC2; Media Center PC 6.0; InfoPath.3; MS-RTC LM 8; Zune 4.7)

We can use this information to make our website respond to different devices in a different way. In the next section, I’ll walk through all of the code needed to make this work.

Simulating a Mobile Device for Testing

Before we start on that, let’s take a detour and see how you can easily simulate a mobile device on your desktop. The easiest way that I have found is to use the Apple Safari browser. Once you’ve installed it, go to the Preferences settings and select the Advanced tab.

Advanced Tab under Preferences in Safari

Make sure that the Show Develop menu check box is selected and you’re almost ready. Remember discussing different user agent strings previously? Here is where you put them to use. Safari will let you easily change the user agent that it supplies to a website if you have the Develop menu setting turned on. Just go to the newly enabled Develop menu item and pick one.

User Agents Available in Safari

If you are interested in seeing the details for one of the user agent strings, just select it and let it refresh your page, then come back to this menu and select the Other option. Your currently selected user agent will be displayed and you can edit it.

Customize User Agent String

If you want to emulate an Android or BlackBerry device, you won’t find those options in the menu items of Apple’s browser, but you can simply go find the user agent string you want and paste it into this box and you’ll be in business. Remember, this is no substitute for testing your website on the actual device. It does provide a quick and dirty way to test your site, but there are some subtle differences in behavior on the mobile device that will come back to haunt you if you don’t do your final testing on an actual device.

Choosing a Browser in Visual Studio 2012

Recognizing Mobile Devices

Let’s get back to our main topic and enable our code to recognize different types of mobile devices. Open the Global.asax.cs file and go to the Application_Start method, and then insert the DisplayModeProvider code below that is shown after the BundleConfig.RegisterRoutes line:

using System.Web.WebPages;

protected void Application_Start()

{

  AreaRegistration.RegisterAllAreas();

  FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

  RouteConfig.RegisterRoutes(RouteTable.Routes);

  BundleConfig.RegisterBundles(BundleTable.Bundles);

  DisplayModeProvider.Instance.Modes.Insert(0,

    new DefaultDisplayMode("Phone")

  {

    ContextCondition = (context => (

      (context.GetOverriddenUserAgent() != null) &&

      (

        (context.GetOverriddenUserAgent().IndexOf("iPhone",

            StringComparison.OrdinalIgnoreCase) >= 0) ||

        (context.GetOverriddenUserAgent().IndexOf("iPod",

            StringComparison.OrdinalIgnoreCase) >= 0) ||

        (context.GetOverriddenUserAgent().IndexOf("Droid",

            StringComparison.OrdinalIgnoreCase) >= 0) ||

        (context.GetOverriddenUserAgent().IndexOf("Blackberry",

            StringComparison.OrdinalIgnoreCase) >= 0) ||

        (context.GetOverriddenUserAgent()

          .StartsWith("Blackberry",

             StringComparison.OrdinalIgnoreCase))

      )

    ))

  });

  DisplayModeProvider.Instance.Modes.Insert(0,

    new DefaultDisplayMode("Tablet")

  {

    ContextCondition = (context => (

      (context.GetOverriddenUserAgent() != null) &&

      (

        (context.GetOverriddenUserAgent().IndexOf("iPad",

            StringComparison.OrdinalIgnoreCase) >= 0) ||

        (context.GetOverriddenUserAgent().IndexOf("Playbook",

            StringComparison.OrdinalIgnoreCase) >= 0) ||

        (context.GetOverriddenUserAgent()

          .IndexOf("Transformer",

            StringComparison.OrdinalIgnoreCase) >= 0) ||

        (context.GetOverriddenUserAgent().IndexOf("Xoom",

            StringComparison.OrdinalIgnoreCase) >= 0)

      )

    ))

  });

}

I’ve inserted the two blocks of code that start with DisplayModeProvider (plus a using System.Web.WebPages; statement at the top of the file). These lines set up a new entry in the available DisplayModes table for this application. Each time a request is received by the application, it is evaluated to determine how that request should be formatted when it is processed. In this case, if the conditions are matched for one of these custom modes, then the name of that mode is injected into the name of the file. The conditions specified in the previous code sample look at the user agent string and check to see if there is a match.

For instance, if the client is an iPhone, it would send in a user agent string similar to this:

Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_3 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8J2 Safari/6533.18.5

Our application would then match that up and determine that it should use the Phone display mode. The MVC engine would then look at the view it was creating and slightly modify the file it was looking for:

What the client requested: /YourApp/SomeController/

The view a PC would get is based on: /Views/SomeController/Index.cshtml

The view an iPhone would get is based on: /Views/SomeController/Index.Phone.cshtml

When the controller builds up the HTML to return to the phone, it will base the request on the Index.Phone.cshtml file. With that information, we can easily create unique views that are designed specifically for the type of device that is browsing our site. Make two copies of the Home/Index.cshtml file and rename them to Index.Phone.cshtml and Index.Tablet.cshtml.

Including jQuery.Mobile

The first step in creating a truly different look and feel for each mobile device is to include the jQuery.Mobile package in our project. You can do this by opening up the Package Manager Console under Tools > Library Package Manager > Package Manager Console, and typing the following line: Install-Package jQuery.Mobile.

PM> Install-Package jQuery.Mobile

Attempting to resolve dependency 'jquery (≥ 1.6.4)'.

Successfully installed 'jQuery 1.6.4'.

Successfully installed 'jquery.mobile 1.1.0'.

Successfully removed 'jQuery 1.6.2' from Chapter4.

Successfully added 'jQuery 1.6.4' to Chapter4.

Successfully added 'jquery.mobile 1.1.0' to Chapter4.

Successfully uninstalled 'jQuery 1.6.2'.

That’s step one, but it doesn’t do much for you yet. If you run your project now, it will look exactly the same, with one minor difference: you should see a sliding transition animation when you switch between pages. Ignore that for now and we will come back to fix that in a few minutes.

Creating a Mobile Layout Page

The next step is to set up a unique Layout page for those mobile devices. In your \Views\Shared folder, you should find a _Layout.cshtml file, which is what all of your pages are based off of at this point. (This is analogous to the master page for all you ASP.NET Web Forms programmers out there.)  Copy that file to a new \Views\Shared\_Layout.Phone.cshtml file and that’s where we will start our customization.

When you open that up, you will see a few lines that look like this:

@Styles.Render("~/Content/themes/base/css", "~/Content/css")

@Scripts.Render("~/bundles/modernizr")

MVC 4 Bundles

The bundling feature is one of the new features of MVC 4 that you will really appreciate. If you have ever tried to optimize your website performance in previous versions of MVC 3 and ASP.NET, one of the things that you had to focus on was to minimize the number of web requests and to reduce the size of the data that was requested. In order to do this, there were several programs available that could minimize and concatenate any JavaScript or style sheets into one smaller file. For example, you might use the following scripts: jquery-1.6.4.min.js, jquery-ui.js, jquery.validate.js, and jquery.validate.unobtrusive.js. You could use the minimized versions of each of these (*.min.js) and considerably reduce the amount of data that you would download to your device, but it would still make four HTTP requests for these four files. By concatenating these files together, you could reduce it to one HTTP request. If you are running a PC on a local network, such as a developer using his or her desktop or testing against a local server, you would never notice the time it took to load those four files. On a mobile device that is running on a 3G (or 1G) network, this could amount to a huge increase in load time for the page.

MVC 4 attempts to alleviate this problem by providing you with a simple built-in way of combining and minifying files through use of a Bundle. By using the BundleUrl option, you can simply point to a directory and tell the page that you want everything in that directory lumped together into one file, and MVC will do it for you automatically.

That’s awesome—I love new features that do something for me that I used to have to do manually! However…

Creating a Custom Bundle

Sometimes those helpful things for your production site make it more difficult for you to develop. In our project, we have just included the jQuery.Mobile package. I mentioned that once we included jQuery.Mobile in our project, the desktop views would have sliding transitions, and we may not want that. We want those scripts to apply to our mobile pages, but not to change our desktop pages. So the question is how do we separate those files out into desktop and mobile versions and load only the files that we want?

Let’s see how we can create some custom bundles in our application by adding a bit of custom code in the new MVC 4 BundleConfig.cs file located in the App_Start folder. We’ll modify the RegisterBundles function to handle that. We’ll create a couple of custom bundles for our mobile version and specify only the files we are interested in.

Here is the code:

public static void RegisterBundles(BundleCollection bundles)

{

  [… existing bundle code goes here… ]

  bundles.Add(new ScriptBundle("~/bundles/MobileJS").Include(

    "~/Scripts/jquery.mobile-1.*",

    "~/Scripts/jquery-1.*"));

  bundles.Add(new StyleBundle("~/Content/MobileCSS").Include(

    "~/Content/jquery.mobile.structure-1.1.0.min.css",

    "~/Content/jquery.mobile-1.1.0.css"));

#if DEBUG

  BundleTable.EnableOptimizations = false;

#else

  BundleTable.EnableOptimizations = true;

#endif

}

If you are writing and debugging your own JavaScript and including those files in your bundles, you may want to control when that code gets minified so that it’s easier to debug. If the compilation tag in your Web.config is set to debug=true, no minification will take place. Alternatively, you can explicitly set the BundleTable.EnableOptimizations tag in your code in RegisterBundles, and that will control it as well and will override the Web.config settings.

Web.config Setting

<system.web>
    <compilation debug="true" />
</system.web>

Now that we have our bundles created, let’s put them into our layout files. Open your _Layout.Phone.cshtml file and replace the bundles/jquery tag with the new MobileJS tag and replace the css bundle with the new MobileCSS tag, like this:

Before

<!DOCTYPE html>

<html lang="en">

    <head>

        <meta charset="utf-8" />

      

      

        @Styles.Render("~/Content/css")

        @Scripts.Render("~/bundles/modernizr")

    </head>

    <body>

      

      

        @Scripts.Render("~/bundles/jquery")

        @RenderSection("scripts", required: false)

    </body>

</html>

After

<!DOCTYPE html>

<html lang="en">

    <head>

        <meta charset="utf-8" />

             

      

      @Styles.Render("~/Content/MobileCSS")

        @Scripts.Render("~/bundles/modernizr")

        @Scripts.Render("~/bundles/MobileJS")

    </head>

    <body>      

      

      

        @RenderSection("scripts", required: false)

    </body>

</html>

Save these changes, and then copy the _Layout.Phone.cshtml file and rename the copy _Layout.Tablet.cshtml. We’ll update it later with more features to differentiate the two types of layouts, but this will work for now. Let’s run our application and see what we have so far.

Desktop and Mobile Application Views

Using Our New Layout Files

Why hasn’t our site changed? It hasn’t changed because although we have created new layout files, we aren’t using them yet in any of our pages. To use a custom layout for any of your views, you need to add one line of code to the top of your view. In this case, edit the Index.Phone.cshtml file and add this line at the top:

@{ Layout = "../Shared/_Layout.Phone.cshtml"; }

Then edit the Index.Tablet.cshtml file and add this line at the top:

@{ Layout = "../Shared/_Layout.Tablet.cshtml"; }

Now try running it again while using a phone or tablet user agent, and you should see something that looks like this:

Application with New Layout Files

You still see the text that we saw before, but the formatting is gone, and we STILL don’t have a page that looks much like a mobile-friendly website. That’s because we are still dealing with the layout of a website targeting desktops.

Let’s replace the HTML in the body of the mobile layout page (_Layout.Phone.cshtml) with some code that is much simpler and is designed for mobile devices and jQuery.Mobile:

  <body>

    <div data-role="page" data-theme="b">

      <div data-role="header" data-theme="b">

        <h1>@ViewBag.Title</h1>

      </div>

      <div data-role="content" data-theme="d">

        <nav>

          <ul id="menu">

            <li>@Html.ActionLink("Home", "Index", "Home")</li>

            <li>@Html.ActionLink("About", "About", "Home")</li>

            <li>@Html.ActionLink("Contact", "Contact", "Home")</li>

          </ul>

        </nav>

@RenderSection("featured", false)

@RenderBody()

      </div>

    </div>

  </body>

This page has most of the same content sections as the _Layout.cshtml page but is formatted quite differently. Pay special attention to the data tags on the page, header, and content divs. Those are special tags to jQuery.Mobile. They give jQuery.Mobile more information about how to deal with these sections. There will be many data tags that you can use to customize your page, and we’ll see some of them shortly.

With this new layout in place, let’s try once more and see if our site is starting to take shape:

Application with Improved Appearance for Mobile Devices

That’s much better. It’s still not quite 100% there yet, but it’s starting to get there. We can see from this quick example that we are getting a page that is starting to look different from our desktop version. In the next section, we’ll continue customizing this page to enhance the look even further.

To sum this up, here is a short checklist of what we have done so far to make all this work:

  1. Created an MVC 4 project based on the Internet Template.
  2. Added the DisplayModeProvider code to the Global.asax to detect a phone or a tablet user agent.
  3. Included jQuery.Mobile in the project.
  4. Created a custom bundle so the mobile scripts wouldn’t affect the desktop pages.
  5. Created a custom Layout page in the Shared folder for a phone and a tablet.
  6. Created a phone and tablet version of each page and changed them to use the new layouts.
  7. Tested the site with Safari and a custom user agent.

That’s quite a list, isn’t it? I bet you’re thinking that this isn’t as easy as I promised it was going to be. In this chapter, you’ve been learning to walk so that later you can run. This process works much better if you understand the steps that need to take place so you don’t trip and fall when you start to run.

One of the nice new features in Visual Studio introduced with MVC 4 is the addition of recipes, which can help you automate many of these steps. By using a recipe like Lyle’s MVC 4 FoodTruck Recipe (available at http://nuget.org/packages/LCI.FoodTruck.MVC4/), you can automate most of these steps and make this entire process painless. I’ve done demos with this recipe where I’ve created a SQL Server database, added a table and data (by running a SQL script), then created a full website with desktop and mobile views in about 10 minutes. However, before you can do that, you need to understand all the steps involved first.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.