Site Meter
 
 

Category: Uncategorized

Using 51Degrees.Mobi Foundation for accurate mobile browser detection on ASP.NET MVC 3

Mobile devices continue to grow in popularity as a way to access the Web. If you’re building any kind of public-facing site, you probably way to make it look and behave well on mobiles just as on traditional desktop browsers.

ASP.NET MVC allows for lots of possible architectures to support this:

  1. You could render different views for mobiles, as in Scott Hanselman’s recent post
  2. You could have a separate MVC area for mobiles, so you can handle their requests using different controller logic as well as different views
  3. You could simply have a separate layout/master page for mobiles, but otherwise let them share the same controller logic and views as desktop browsers

Hopefully soon we’ll publish some updated and more detailed guidance about these options, but for now this blog post is about option (3) – the simplest of them all.

Setting up a mobile-specific Razor layout

One of the really neat aspects of the Razor view engine (the default in ASP.NET MVC 3) is that a lot of it can be controlled by procedural code, not just declarative statements. So, if you want to implement custom logic to control layout selection, just add some logic to ~/Views/_ViewStart.cshtml. For example, change this:

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

… to this:

@{
    Layout = Request.Browser.IsMobileDevice
        ? "~/Views/Shared/_LayoutMobile.cshtml"
        : "~/Views/Shared/_Layout.cshtml";
}

… and now it will attempt to use _LayoutMobile.cshtml for requests from mobiles. Next, of course, you’ll need to actually create _LayoutMobile.cshtml. To get started, you can just copy & paste the existing _Layout.chtml file, changing its name. To ensure we can tell the difference between the two, I’ll modify the “title” element to display a special message for mobiles:

<div id="title">
    <h1>My *mobile* app</h1>
</div>

Time to check it works. Perhaps the quickest way to simulate a mobile device (without downloading any emulators) is by using Firefox and its User Agent Switcher add-on: it already knows how to simulate the iPhone’s user agent string, for example. Here’s how my home page renders, first with the default Firefox user agent string, and second simulating the iPhone’s user agent string:

image

Spot the difference :)

At the point, you might think we’re done. Surely from here it’s just a matter of customizing _LayoutMobile.cshtml to better suit the small screen of a mobile device, right? Well, kind of. But how does Request.Browser.IsMobileDevice actually work? Is it always right?

Some popular mobile devices/browsers won’t be detected this way

In case you don’t know, Request.Browser is a core ASP.NET platform feature that can give you a lot of information about the type and capabilities of the browser making the current request. It works by comparing the incoming User-Agent header against regular expressions in a set of built-in .browser files. ASP.NET 4’s browser files are recent enough to detect iPhone, but not Opera Mobile or Android. For example, if you download the Opera Mobile emulator and visit the page we just created, here’s what you’ll see:

image

If you can read the tiny text, you’ll see it doesn’t say “My *mobile* app”.

One way to improve this is to add your own .browser files for newer devices and browsers – accounting for the many variations in their user agent strings. Then Request.Browser.IsMobileDevice could successfully recognize Opera Mobile. But if you don’t want to do all that work?

Improving device detection using the 51Degrees.Mobi package

51Degrees.Mobi Foundation is an open source .NET project that enhances Request.Browser so it gets its information from Wireless Universal Resource File (WURFL) – one of the most comprehensive and up-to-date databases of mobile device information. The great news is that 51Degrees.Mobi Foundation is now available as a NuGet package, so it’s incredibly easy to install and update.

If you haven’t already installed the NuGet package manager, do so right away! Next, install 51Degrees by entering the following into the NuGet Package Manager Console:

Install-Package 51Degrees.mobi

Easy! This does the following to your project:

  • Adds a reference to FiftyOne.Foundation.dll, the assembly containing the 51Degrees logic
  • Adds AppStart_51Degrees.cs to the root of your project. This enables the 51Degrees mobile detection provider, which populates Request.Browser information whenever you ask for it
  • Adds a recent copy of the WURFL device list to your project at ~/App_Data/wurfl.xml.gz
  • Adds a folder, ~/Mobile/ containing a Web Form that displays information about the device. We don’t want this in an ASP.NET MVC application – just delete the ~/Mobile folder that it added.
  • Adds a section to your Web.config file that configures 51Degrees.Mobi Foundation with some default settings. One of its default settings is to redirect mobile browsers to the URL ~/Mobile. This would be useful if you were setting up an MVC Area called “Mobile” for mobile browsers, but since we’re just changing the master page, we don’t want this redirection to happen. Disable it by modifying Web.config: Find the <redirect> element inside <fiftyOne>, and comment it out or delete it.

Now you’ve got a much more up-to-date device database. Here’s what you’ll see if you reload the site in Opera Mobile emulator:

 image

You can download newer versions of the WURFL database to pick up newly-released mobile devices and browsers at any time from its page on SourceForge. Whenever you download a new version, install it by copying it to the location ~/App_Data/wurfl.xml.gz, overwriting your previous version of that file. Note that WURFL does not yet appear to detect Windows Phone 7 WURFL does detect Windows Phone 7 already.

Improving the layout for small screens

OK, we’ve got as far as distinguishing mobiles from desktop browsers and rendering views with different Razor layout file. It’s beyond the scope of this blog post to explain all the dozens of HTML and CSS tricks you can use to create layouts that look great on the widest range of mobiles, but here’s one I want to mention:

When modern mobile browsers render web pages, they lay it out on a virtual “viewport” that by default is about as wide as a typical desktop browser window. Then, after rendering the page, they scale down the output to fit on the tiny device screen. That’s why the preceding Opera Mobile screenshots have really tiny body text: the HTML page was laid out for a screen around 1000px wide and then scaled down. The user is expected to zoom in and pan around to get a closer look at the text.

Mobiles do this as a workaround for the fact that most web pages assume you’re using a desktop browser. If the mobile didn’t do this, typical web pages wouldn’t fit horizontally and would end up getting hideously mangled. But if you’re designing a layout especially for mobiles, you’ll take account of the much smaller width and spare the user all that awkward zooming and panning.

How can you tell the mobile not to use a wide virtual viewport, but instead to lay out the page to match the device’s actual (narrow) width? You can use the unofficial “viewport” meta tag. Here’s an example. Add the following to the <head> section of _LayoutMobile.cshtml:

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

Now if you reload the page in Opera Mobile emulator, here’s what you’ll see:

image

Much better! The body text is now pretty much readable, and the user only needs to scroll vertically (not horizontally). No zooming required. The “viewport” meta tag is respected by most recent mobile devices/browsers, including Windows Phone 7 and iPhone. Read more about how iPhone interprets it here.

From here on, it’s up to you to customize your mobile layout, perhaps using a different CSS stylesheet, to look as neat as possible on mobiles. Of course, you can also inspect Request.Browser.IsMobileDevice in other parts of your code too (e.g., controllers or filters) if you need to vary your logic further.

Hello, Microsoft

Starting later this month, I’m going to be working for Microsoft – I just accepted a job on the Web Platform and Tools (WPT) team in the Developer Division. This is pretty exciting for me, as it means I’ll be able to directly focus my energy on pushing the MS web stack forwards, and will get to work with many of the very smart people who bring you technologies like ASP.NET and IIS.

In case I need to drop some names to clarify where I fit in, I’ll be somewhere many levels of management below ScottGu, and on the same team as Scott Hanselman.

Why do this?

I’m a web developer, so of course I’m personally motivated to make web development better! We all want our technologies to help us be more productive, solve bigger problems, and let us have more fun in the process, right? For someone who’s focused on the MS web stack for the last 7 years, where better to participate in the evolution of web development than inside Microsoft itself?

Well, that’s the big picture. On a more practical, immediate level I’m also keen to get involved with Developer Division’s leaning towards supporting open source development (e.g., notice that the NuGet project even accepts code contributions) and in advocating professional-grade development practices, whether they originate inside Microsoft or inside developer communities using any other technology platform.

A key part of WPT’s responsibility is to be aware of what developers want, and be sure we’re meeting your needs. As I find out what specific projects I’ll focus on, I’ll be asking for your feedback so I can reflect your views back into the collective product teams.

What changes, and what remains

  • This blog: It’s still mine and will continue.
  • Open source projects: The one I’m most actively working on is Knockout, an MVVM library for creating dynamic Web UIs. I’m still excited about this project and its potential, and it continues exactly as-is, and will evolve in whatever direction I and its user community wishes to take it. This isn’t a Microsoft product.
  • The Apress ASP.NET MVC book series: I’m discussing this with Apress at the moment. Hopefully we’ll get the excellent Adam Freeman to co-author the MVC 3 book, otherwise it might end up being very, very late… Thanks for all the enquiries about this – and no, we don’t have a publishing schedule yet.
  • Being an MVP: Shockingly, I’ll be dismissed from the MVP program, before I even got to go to my first MVP summit. Apparently this has happened to others before.
  • My location: I’ll be staying in the UK.

Knockout 1.1.0 + new project site launched

Yes, it’s been a while since my last blog post… Partly this is due to other work, and partly it’s because my community efforts lately have increasingly focused on open source projects.

In case you’re new to it, Knockout is a JavaScript library that brings declarative bindings and the Model-View-View Model pattern to your HTML. It makes it easier to build sophisticated, dynamic web UIs in a clean structure that handles complexity, not just an ad-hoc mass of jQuery event handlers and manual DOM manipulations.

Version 1.1.0 is a significant release that adds (compared to 1.05):

  • Various syntax improvements and simplifications (chained assignments, finding model functions automatically, new utility methods requested on the project forum)
  • Support for the newest version of jquery.tmpl template engine (supposedly, this will be be integrated into the core of jQuery 1.5)
  • Smaller download size (via a new minification technique)
  • IE 9 beta support, plus various compatibility fixes for IE 6 in obscure situations
  • Full documentation (link)
  • Whole new project website with easier-to-read live examples

It supports all mainstream browsers (IE 6+, Firefox 2+, Chrome, Safari (Win/Mac/iPhone), Opera). By now it’s been used by many developers in a range of projects, so I’m pretty confident it stands up to real-world situations.

Developers using ASP.NET MVC might want to see an example of integrating it with a KO UI. Knockout isn’t limited to ASP.NET MVC – it’s pure JavaScript, so it supports any server-side framework, such as Ruby on Rails, PHP, and others. Carl Hörberg created an example of using KO with Sinatra (a Ruby web framework) and WebSockets here.

Obviously this blog post has something of a marketing edge to it :) so you’ll want to form your own judgements. But personally I think that if you’re creating any nontrivial dynamic UI on the web, there’s a lot of benefit in structuring it nicely with a clear view model like KO helps you to do.

Check it out

Feedback and questions

If you have questions about how to use Knockout, please post on the project forum, not on this blog. That helps to keep things organised. Thanks!

If you have general comments or feedback (not support requests) then please go ahead and put a comment on this blog post.