Mix: Mobile Web Sites with ASP.NET MVC and the Mobile Browser Definition File
UPDATE from 2011: These View Engines have a subtle release mode caching bug. Peter Mourfield and I have released a better MobileViewEngine for ASP.NET MVC 3 that is closer to what MVC 4 will look like. The updated blog post with the new MobileViewEngine is here.
I gave a talk at Mix 09 today called File | New Company: Creating NerdDinner.com with Microsoft ASP.NET MVC. It was a fun, if challenging talk to do. I did it it with no slides at all. Just me and Visual Studio. It was one of two talks at Mix that had just code. I wonder if it'll catch on? ;)
Anyway, it was quite the tightrope walk. I'll post the video here as soon as it's posted on the Mix 09 Sessions Site.
UPDATED: Here's the link to the video of my Mix09 talk:
Session Video: File | New Company: Creating NerdDinner.com with Microsoft ASP.NET MVC
The general structure was to start a File | New Company and build as much of NerdDinner.com as I could in the 75 minutes allotted.
Here's a few of the highlights...
XHTML Strict
I pointed out how nice and easy it is to get a site to validate as XHTML Strict using ASP.NET MVC. You've got complete control over every bit that goes out on the wire. Kudos to Michael Bach for caring. I'm still not 100% convinced that XHTML Strict is as crucially important as the <ul-mafia/> says it is, but it's a simple thing to do it you keep the markup clean, simple and semantic. ;)
Mobile and ASP.NET MVC
The talk was about developing on ASP.NET MVC, not about mobile, but it was easy to make the site available on mobile devices when I got wind of what the Mobile Browse Platform Team (in Microsoft's Dublin office) was releasing at Mix.
They released the Mobile Device Browser File on CodePlex under the Ms-PL license. It's created from a database from many sources, including the popular WURFL mobile device capabilities database, actual device tests, UAProfs, contributions, logs, and elsewhere. These sources are composited, stored in a database of thousands and thousands of devices. Then that's combined with the actual logs of mobile device traffic and this file with the top 1500 or so actual devices is created to get the broadest reach with a manageable file size.
It's a mobile.browser file that contains definitions for hundreds of the top individual mobile devices and browsers that hit Microsoft mobile sites. At run time, ASP.NET uses the information in the request header to determine what type of device/browser has made the request.
It detects the mobile device hitting your site and makes available 67 capabilities describing the requesting device. These capabilities range from screen size to cookie support to CSS support. It's everything you need to adaptively render content for mobile phones and devices.
This information is exposed to the developer through the Request.Browser property. The format of the .browser file is XML and the schema is defined here: Browser Definition File Schema. The Browser Definition File was introduced in the .NET Framework version 2.0. In earlier versions of the .NET Framework, the browserCaps element was used to define browser definitions in configuration files.
Now, ASP.NET MVC doesn't know anything about Mobile. Here's what I did to enable NerdDinner on Windows Mobile and iPhone.
First, I downloaded the new Mobile Device Browser File and put it in \App_Browsers\Devices in my ASP.NET project. Just by dropping this file in the App_Browser\Devices folder, I automatically get all these 67 capabilities populated in the Request.Browser option. I can address them like Request.Browser["AjaxSupportsGetElementByID"]. Just open up the mobile.browser file to see all your choices. There's also extensive documentation. They'll welcome bug reports and patches.
The guys at Ascentium that I met at Mix threw me some code and we created a basic MobileCapableWebFormViewEngine. Kind of a long name, but basically I need to have ASP.NET MVC look in different folders for a View if the device is mobile.
For example, ordinarily if you're in the Home Controller and the Index action, the ViewEngine's FindView() method gets called and will look in /Views/Home for Index.aspx.
The Mobile ViewEngine needs to detect the device and change where we look. I could just make a "Mobile" version and call it a day. However, since we've got a nice tree structure here, why not set up:
- /Views/Home
- /View/Home/Mobile
- /View/Home/Mobile/iPhone
- /View/Home/Mobile/MobileIE
etc...so, now we can have many different files, any combination of them.
We can also have things fallback neatly. For example, we can create a really specific View, say, for a Nokia "Whatever" when it needs the Details, but that Nokia will use the standard Mobile view in all other situations. This is accomplished by just the folder convention.
Here's a simple example to start.:
public class MobileCapableWebFormViewEngine : WebFormViewEngine
{
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
ViewEngineResult result = null;
var request = controllerContext.HttpContext.Request;
// Avoid unnecessary checks if this device isn't suspected to be a mobile device
if (request.Browser.IsMobileDevice)
{
result = base.FindView(controllerContext, "Mobile/" + viewName, masterName, useCache);
}
//Fall back to desktop view if no other view has been selected
if (result == null || result.View == null)
{
result = base.FindView(controllerContext, viewName, masterName, useCache);
}
return result;
}
}
This can be expanded on like this (and in a number of other ways...switch statements, tables, conventions, it's up to you to map the Views as you like.
public class MobileCapableWebFormViewEngine : WebFormViewEngine
{
public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
ViewEngineResult result = null;
var request = controllerContext.HttpContext.Request;
//This could be replaced with a switch statement as other advanced / device specific views are created
if (UserAgentIs(controllerContext, "iPhone"))
{
result = base.FindView(controllerContext, "Mobile/iPhone/" + viewName, masterName, useCache);
}
// Avoid unnecessary checks if this device isn't suspected to be a mobile device
if (request.Browser.IsMobileDevice)
{
if (UserAgentIs(controllerContext, "MSIEMobile 6"))
{
result = base.FindView(controllerContext, "Mobile/MobileIE6/" + viewName, masterName, useCache);
}
else if (UserAgentIs(controllerContext, "PocketIE") && request.Browser.MajorVersion >= 4)
{
result = base.FindView(controllerContext, "Mobile/PocketIE/" + viewName, masterName, useCache);
}
//Fall back to default mobile view if no other mobile view has already been set
if ((result == null || result.View == null) &&
request.Browser.IsMobileDevice)
{
result = base.FindView(controllerContext, "Mobile/" + viewName, masterName, useCache);
}
}
//Fall back to desktop view if no other view has been selected
if (result == null || result.View == null)
{
result = base.FindView(controllerContext, viewName, masterName, useCache);
}
return result;
}
private bool UserAgentIs(ControllerContext controllerContext, string userAgentToTest)
{
return (controllerContext.HttpContext.Request.UserAgent.IndexOf(userAgentToTest, StringComparison.OrdinalIgnoreCase) > 0);
}
}
Remember when I said there were 67 capabilities for each of the devices? I might need a custom view for a device, but in many instances, I might just want to modify some small aspect of a few based on the browser's characteristics like screen width or height. I could control the Mobile ViewPort like this for phones that support it.
<meta name="viewport" content="width=<%= Request.Browser["ScreenPixelsWidth"] %>, height=<%=Request.Browser["ScreenPixelsHeight"]%>"/>
A more advanced example might be this. Say I store all my images in PNG format, but I come upon a phone that doesn't support PNG. I might automatically transcode my PNGs into JPGs. Same with a phone that supports WAV but not MP3.
Windows Mobile and iPhone
Armed with this, it was just a few hours work for my simple NerdDinner app to get mobile enabled. Now that I'm learning more about what devices can do what, I'll check all this in and continue to add functionality.
For iPhone I used Joe Hewitt's IUI JavaScript and CSS Framework (and the iPhone Simulator). The iPhone includes a lot of -webkit CSS extensions so the view did need be custom. It just doesn't work at all on other browsers, but it looks great on the iPhone. For Windows Mobile, I downloaded the free Windows Mobile 6.1.4 Emulator Images and the Device Emulator.
Again, I can do whatever I like with the markup, so on these devices, clicking the phone number initiates a call, clicking a map takes you to a mobile map solution, etc.
I'll be checking this in to the NerdDinner CodePlex project in the next few days. I'm really stoked that these guys released this data file. I just dropped it in, and ASP.NET suddenly got a lot smarter and I can now make great sites for any device. After this prototyping exercise, it's time for me to think about the interaction design for the mobile experience, rather than just "down-porting" the desktop site.
All in all, great fun, and a boon to ASP.NET and developers interested in mobile.
About Scott
Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.
About Newsletter
I was exactly looking for WAP support extension on ASP.NET MVC and there you go with this post.
Hope the link for session video will be avaialbe soon. This video accompnied by scottgu's chapter 1 on Professional ASP.NET MVC 1.0 will be a great Hit! so awaiting the video...
thanks.
Ruchit S.
*************************
I've been developing mobile sites using ASP.NET 2.0 for years, and I've always hated Micorsoft's half-assed approach to content adaptation. ASP.NET assumes the content-type for most mobile phones should be WML despite the fact that most phone phones these days support HTML. Not to mention that when HTML is served with the WML content type, the browser normally will complain that it's not properly formated WML (e.g. unencoded '&')...well of course it's not, it's HTML.
I can really see nothing new in the above, apart from the release of a new Mobile Device Browser File XML file. ASP.NET ships with a number of browser files installed in the 'GAC' so I guess this is simply an update? Microsoft must think new mobile phones are being released at a snails pace if they only release browser update files every few years. Not to mention that the current XML file seems hopelessly inadequate.
I think Microsoft would have been far better creating a provider-pattern-based architecture around the 'browser' capabilies property. Then different providers could be created to interface with far superior device databases such as WURL, DeviceAtlas and such.
You mention that the Mobile Browse Platform Team is based in Dublin... well so are dotMobi, the people behind DeviceAtlas and a number of other mobile initiatives.
I don't want to some across as negative. I really like a lot of what ASP.NET provides, and I'm looking forward to using MVC. But considering I'm an avid ASP.NET mobile web developer, and I will NEVER use the Mobile Device Browser definition file in it's current form, I can't help but think Microsoft has got this one badly wrong.
http://www.deviceatlas.com/
http://wurfl.sourceforge.net/
I have no affiliation with either of the above projects, outside of being a certified dotMobi web developer.
I'm the PM on the Mobile Browse Platform team, we publish the file on CodePlex. The mobile.browsers file available at http://mdbf.codeplex.com is a replacement to the the file in the GAC. As mentioned in the artical we will be updating this file regularly. As I mentioned during my talk (http://sessions.visitmix.com/MIX09/T85M) Windows Live uses a similar approach.
The file released on codeplex targets over 500 of the most popular mobile phones in the market today, and the majority of these devices are HTML enabled. As you mentioned in your post there are lots of mobile companies in Dublin and many ways to solve this problem and this approach my not suit your requirements, however we think it may be of use to many others.
We are all aware that new mobile devices are released all the time, and we hope our regular updates will be of some help. I would encourage you to check out the file and let us know what you think, there are issues and discussion forums provided on our CodePlex site and I would encourage you to download our file, try it out, and let us know what you think.
Oh, and ScottGu is now 3rd (and 1st human Scott) but you are now 10th, so congratulations, first page!
So m.mysite.com would kick into the mobile site, whereas www.mysite.com would be left alone, or, if detecting a mobile browser, puts a link to the m. FQDN on every page.
Chris
I want to display fro some page different page depending on the browser like IE 8 for example..
Is your view engine the best?? basically i want to have pages that are "legacy" and gradually build pages that are for IE8 and that are more standards compliant on per page basis. The newer pages gradually being the only pages as the older and noncompliant browsers are phased out.
Joe Mele
www.youseful.com
It's not so much about you releasing it often (although we'll all have to wait and see if Microsoft's often is the same as 'new devices hit the market' often), but more about the complexity of the file itself, which is in turn hard to tailor to one's own needs and no way to "patch" it nicely. For instance, you cover a lot of devices, but a lot of devices are also missing. Among them, the old, but still popular, Sony Ericsson T610i... As I wrote on the codeplex site, it _is_ a nice and welcome effort after all.
I also agree with the "provider" approach, which would make more sense to me. One of the providers could/should be the MDBF engine with a file. BTW, where in the pipeline does ASP.NET read this file and 'detects' a device? (I wasn't able to find much information about it) Does it cache the capabilties, or does it "lookup" the device for every request?
Thanks, Miha.
The HttpBrowserCapabilities object is cached and might be used again for a different request from the same type of browser.
Did you need a Mac to try your application on the iPhone or there's another way to do it ?
Basically, I just want to know if there's a Windows solution to install Application on the iPhone.
Thanks, nice article.
a google for scott turns up hanselman in third and the guu in 5th
you can feel better about that
I see you talking about expectations, and then as you move onto another topic, I see you type "expectations" and do the jazz hands long after you've talked about them.
(I've got the latest Silverlight and its the same with IE7 and FF3.)
I really want to watch this, but I just can't without going totally crazy. Does anyone have any ideas please?
Thanks, Bill.
User-Agent: Mozilla/5.0 (X11; U; Linux i586; chrome://navigator/locale/navigator.properties; rv:1.9a9pre) Gecko
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Which is preferable, mis-identifying a mobile device as a regular browser, or vice versa ? Yeah, it's an oddball combination of hardware / software, just thought I'd point this out in case it's not the XO's "fault".
I do have a question though. In your controller classes you detect if there are any problems, and then pass the problems on to the view. My issue is; you use a catch all to grab those errors;
[AcceptVerbs(HttpVerbs.Post), Authorize]
public ActionResult Edit(int id, FormCollection collection) {
...
try {
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id=dinner.DinnerID });
}
catch {
ModelState.AddModelErrors(dinner.GetRuleViolations());
return View(new DinnerFormViewModel(dinner));
}
To me, this is bad practice. As anything that occurs in that page will be thrown away and be treated as a User Error. For example, what would happen if the SQL server went down? Do you and the rest of the team advocate catching all? I would love to get your insight on this.
Thanks,
-Zach
Comments are closed.
These sites came in handy:
http://ready.mobi/launch.jsp?locale=en_EN
http://validator.w3.org/#validate_by_uri+with_options (select the mobile property)
https://addons.mozilla.org/en-US/firefox/addon/1345 Mobile Profile for Firefox
The only issue I had was changing the ContentType on the response stream, I changed it in the Master Page, therefore I used ActionFilterAttribute
public override void OnActionExecuting(ActionExecutingContext filterContext)
public override void OnResultExecuted(ResultExecutedContext filterContext)
This allowed me to change the response content type and it all worked!
Cheers for a great article though!!
Sarkie