Thursday, 10 November 2011

My 70-511 Study Guide

 

Greetings.  The leaves are falling here in London and there’s a bit of a chill in the air, but occasionally there’s also a ray of sunshine!

Speaking of rays of sunshine, I recently experienced the shaft of light from heaven which accompanies the joy of passing the 70-511 Microsoft Certification exam 

:-/. 

The joy (and relief) mostly occurred when it was over and I passed!

Full disclosure here, I failed it the first time, just by a few points, then passed it the second time (also by a few points).  Some people find these exams easy, but in all honesty, I’m not one of those people.  I found it to be a pretty difficult test, mainly because it’s just an immense amount of material you have to memorize.

Another annoying thing I find about this particular exam is that it’s a test both about WPF (Windows Presentation Foundation, which I think is a cool and modern technology, and similar to the Silverlight work I’ve been doing in the last year or two, or integrating Silverlight with SharePoint).  But also, it’s a test about Windows Forms programming, which, they argue, is still viable and you might find yourself on a client site doing a Windows Forms project.  (Do the words “legacy app” mean anything to anybody?)

Personally I think it ought to be two separate tests, but I guess if they did that, nobody would bother with the Win Forms one, because it’s old technology and therefore uninteresting to a lot of developers, who naturally prefer to learn the cutting edge stuff (is WPF cutting edge?  That’s another question.  Anyway it’s cooler than Windows Forms in my opinion). 

Putting aside, of course, the whole current debate about whether WPF and Silverlight are being killed by Windows 8, HTML5, CSS, etc.  Arguably, given that whole question, even WPF is an obsolete technology.  Be that as it may, I’m currently pursuing an MCPD to add to my employer’s offerings in this area, and this was one of the exams which is part of that larger goal.  (Next up:  70-513!  I’m actually looking forward to that one, in some strange way.  WCF is quite interesting and useful).

Well, I’ve seen this a number of times in my career, where I’ve spent years working with a particular Microsoft technology (I was a Visual FoxPro programmer for years), and they end up killing it off because they’ve decided to promote a different paradigm.  This is a big topic, also endlessly debated on the web, and I’ll leave my two cents for another blog post, but suffice it to say, that’s life in the fast lane, buddy.  You gotta roll with the changes.  To quote two rock song cliches.  I’ve had to reinvent myself a number of times, and it’s not exactly fun, but I do like to eat and have a roof over my head.

If you choose a career path which involves using technologies created by an organization such as Microsoft, which modernizes stuff as time permits and as they see fit, or if you want to do software development in general, then adapting to constant change is obviously just part of the game.  What doesn’t kill you will make you stronger!

Anyway, I also went through my usual ambivalence about the whole process.  Generally I spend a lot of time thinking, why do I have to cram all these obscure facts into my head?  (And my wife gets to suffer through me moaning about it for several weeks!)  But I’ve taken 3 of these exams now and invariably I later found myself on a project, actually using some of the stuff I learned from studying for the exam, and eating my words. 

So I’m trying to learn, over time, how to grin and bear it.  In the end, you do end up being more knowledgeable on the other side, and often it’s one’s familiarity with obscure facts about the technologies you’re working with, and general command of your material, that help make you a better developer.  And despite a range of opinions I’ve heard regarding the actual value of these certifications in the marketplace, these exams, I must admit, do actually force you to learn a lot of the more obscure minutae which you might have bothered with otherwise.

However, as I did with another test (see my earlier blog posts), I thought, why can’t they just give you a reference that’s organized in the same way as the test, that gives you a set of hyperlinks to those topics on MSDN?  If they just said, here’s the material you’ll be tested on; go memorize this, and you’ll pass. 

Well, unfortunately it’s not that simple.  To me it appears to be largely about testing your ability to find stuff that’s buried somewhere deep in the pages of MSDN.  Which obviously doesn’t make you a good developer, and although I guess it does force you to dig for stuff, to me it feels like a bit of a waste of time.

So with that in mind, I thought, as long as I’m studying for this thing, I might as well produce a reference that might be useful to myself in the future, and maybe for somebody else studying for this beast.  And it may be a useful reference for these technologies in general.  So enough blathering.  Here’s my 70-511 Study Guide.

(To create these, basically I create a giant Word doc, based on the “skills measured”, and paste in hyperlinks as I’m studying for the test.  Then I save it as HTML.  Word creates some pretty horrible HTML but there you go).

It won’t mean you don’t have to memorize this stuff also, but it may make life a bit easier by putting stuff in one place.  Lotsa luck my friend! 

:-)

Monday, 20 June 2011

Close SharePoint Modal Dialog from within Silverlight

This took me a fair bit of searching to figure out, and there’s probably a number of better (or at least different) ways of doing this, but this seems to work for me, it’s just a few lines of code, it’s non-invasive, and you don’t have to tweak the page hosting your Silverlight object. 

So… imagine you’ve got a Silverlight application running inside of a SharePoint modal dialog.  You want to allow the user to click a button in Silverlight (say, a “Save” button after saving some data to some web service using WCF), to dismiss the modal dialog.

This is simply a combination of two techniques, shown here and here.  You’d put this code in the code-behind of your user control, e.g. MainPage.xaml.cs.  Using MVVM you could bind an ICommand to your button, or if you’re not using MVVM, you could just put this in the Click event of a button in the code behind.

 public void CloseWindow()
 {
     var Script = HtmlPage.Document.CreateElement("script" );
     Script.SetAttribute("type", "text/javascript" );
     Script.SetProperty("text", "function CloseDialog() { window.frameElement.commitPopup(); }" );
     HtmlPage.Document.DocumentElement.AppendChild(Script);
     HtmlPage.Window.Invoke("CloseDialog" );
 }
 

Friday, 15 April 2011

Thanks Razorfish!

Tuesday April 19th, 2011 will be my last day at Razorfish London.  After a couple weeks of holiday in the States, in early May I’ll be starting a new job as a Senior Consultant at Hitachi Consulting located near London Bridge.

I learned a great deal while I was at Razorfish and got a chance to work with some incredibly talented creative people and front-end developers. 

Some amazing changes in the world of mobile, cloud computing and various other areas will be sweeping the planet in the coming years, and as one of the world’s premier media agencies, Razorfish will be at the forefront of these changes. 

With respect to my own work at Razorfish London, I learned a lot about SharePoint, web services, LINQ, jQuery, and particularly MVC 2 (and a bit of MVC 3); test-driven development; as well as a good bit of Silverlight and Microsoft Surface dev work.

So I just wanted to write a quick blog post to say thanks to my managers and colleagues.  I’ll miss you guys, but it was time for a change.  I really appreciated the opportunity to work with you and I wish everyone at Razorfish all the best. 

And I’m looking forward to some holiday!  Then it’s on to new challenges at Hitachi.

Best Regards,

-Dave

London, UK

Tuesday, 29 March 2011

Code, Quality, and NDepend

I got the idea of Quality with a capital “Q” ingrained upon me years ago when I read the philosophical novel Zen and the Art of Motorcycle Maintenance.  The main thing I took away from the book is that whatever human endeavor you are engaged in, you should let your actions be governed by a desire to do things well, with a constant and abiding interest in achieving the highest possible Quality.  Naturally this idea can (and should) be applied to the complex world of software development, particularly with respect to the question of Code Quality. 

It’s not always easy to live this way.  Whatever point we happen to be at in our lives or upon our career path, our knowledge only goes so far.  And sometimes we take shortcuts; it’s often tempting to take the easy (or lazy) way out, thinking we don’t have time to do things well or to do them right.

However, in this day and age, .Net developers are fortunate to have a plethora of 3rd party tools available to us to help us easily examine and improve the quality of our code.

Along those lines, I am appreciative I was asked by C# MVP Patrick Smacchia to take a look at his tool NDepend which extensively analyzes your .Net code to look for flaws based on rules you can configure, in the interest of improving Code Quality.  I ran it against a small MVC2 project I’m working on and it’s fascinating what I’ve learned just from a cursory examination.

I will say at this point I’m only scratching the surface of what this tool can do, but I can say even at this early stage that I would highly recommend it as a valuable addition to any .Net development toolbox, and I’m finding NDepend is teaching me things about my code and about .Net development in general that make me want to use and explore it a lot further.

When you install NDepend you have the option to install it as a Visual Studio add-in, which I did.  That enables an NDepend menu within VS:

NDependMenu

I chose the option “Attach new NDepend Project…” and then chose “Run Analysis.”  The following dialog is displayed:

NDBeginnerDialog

Now, you can choose one of the options shown here or select “Skip”, but by default, NDepend runs and displays the results of its analysis in your browser; a portion of the page is shown here:

Report

In addition to the metrics and configurable CQL rules (Code Query Language), right off the bat you get some cool and interesting diagrams like the “Dependency Graph”:

DependencyGraph

You also get things like a “Summary of CQL Rules Violated”:

CQLRulesViolated

What if there are too many flaws reported?  I clicked on the “Code Quality from Now” link and got this dialog:

CodeQualityFromNow

What if I don’t like the default set of CQL rules that NDepend gives me, or I want to change the rules to better suit my own needs?  I can choose the “CQL Query Explorer” from the NDepend menu:

CQLQueryExplorerMenuItem

The CQL Query Explorer looks like this:

CQLQueryExplorer

Double-clicking on an item in the list, for example the “Methods too big (NbILInstructions)” item, brings up the CQL Query Editor:

CQLQueryEdit

It may be difficult to look at the flaws in your code, but, let’s face it:  it takes a strong person to admit that their method is too big.  ;-)

All kidding aside, I think you get the idea… the CQL language has a very intuitive SQL-like syntax, and you could decide you’d prefer a different value for the number of IL instructions, etc. 

Once again this is just the tip of the iceberg, but clearly NDepend is a great tool created by some very bright people.  I’m looking forward to mastering it more fully.

Monday, 28 March 2011

PowerShell 2.0 for Windows Server 2008 R2

This post is simply a brief moan about a particular instance of poor documentation on Microsoft’s web sites, and an attempt to fill that gap.

I’ve been reading the Pragmatic Programmer which advocates learning new languages on a regular basis, and also learning your computer’s shell language instead of just relying on the GUI.  I’ve dabbled in a bit of PowerShell and I have a sense of how powerful it is for manipulating SharePoint, SQL Server, the Windows OS, and anything else you might like to manipulate with script, but haven’t made the time to really learn it, so I thought that would be a great way to apply those recommendations.  So I thought I’d get onto by Windows Server 2008 R2 development VM and download the latest version of PowerShell (2.0). 

That’s why I thought I’d write this quick post.  If you followed the above thought process, you might experience the same confusion I did as a PowerShell newbie.

You might run across pages like this one (which I found useless, not least of which was because it talks about running SCONFIG.CMD, which is supposed to just be installed on your Win Server 2008 box by defult, but apparently isn’t):

http://support.microsoft.com/kb/976736

Or messages like the post shown on this page:

WinMgmtFrame

Huh?  I’m running Windows Server 2008 R2, why is it telling me to go to the Windows 7 Solution Center?  (And if you go there, you’ll find that’s not helpful).

Anyway the answer is found on this page:

http://answers.microsoft.com/en-us/windows/forum/windows_7-windows_programs/powershell-v2-missing-in-ultimate-x64-v1-only/f614919f-a427-47b2-b220-4ed8dc29b415

(The answer being, if you simply launch the PowerShell icon and issue the “get-host” command, you find that PowerShell 2.0 is installed on Windows Server 2008 R2 by default, so there’s nothing you need to do).

And some more info (and a refreshing Microsoft admission that they themselves are responsible for the confusion):

http://blogs.msdn.com/b/powershell/archive/2010/05/14/powershell-v2-is-available.aspx

I do agree with some of the comments on that page.  Dear MS, if you’re going to rename a product (e.g. renaming “PowerShell” to “Windows Management Framework”, or at least rolling PowerShell into this larger “suite”), how about a little bit better documentation and more consistency on MSDN and/or TechNet?  Like something that comes up easily in search engines.  I tried searching in Bing on the MSDN or TechNet sites for a simple phrase like “PowerShell Windows Server 2008 R2” and found the search results were fairly useless.  Maybe we’re spoiled in this age of search engines, but it did seem to waste at least a half hour of my life, which seems a slightly high price to obtain a simple fact.  Maybe this post may someday save somebody else a half hour.

Now let’s see, where was I… oh yeah, I wanted to start learning PowerShell!  ;-)

Wednesday, 2 March 2011

Using XML Serialization to render front-end web pages from a custom CMS built in MVC2

This post is about a technique I developed on a recent project which may be of interest.  This project seemed naturally to call for SharePoint 2010 as it had a CMS component, but it needed to be hosted in the Windows Azure cloud.  As of this writing, (although some seem to have tried with an Azure VM role) it generally doesn’t seem to be possible to host SharePoint in Windows Azure; I guess it’s because the kind of “wrapper” that they have you put around an Azure application (the “role entry point”) so they can manage it in the cloud, and the stateless nature of Windows Azure apps, doesn’t really lend itself to SharePoint’s architecture.  So I decided to do the project using ASP.NET’s MVC2 Framework and building a custom CMS, in which I used XML serialization to enable a simple publishing capability to provide users with “preview” and “live” versions of web pages. 

I needed to ramp up quickly, and as I’ve generally been impressed with the quality of Apress technical books in the past, I looked at what they were offering in terms of books on MVC2.  I was pleased to discover this book, “Pro ASP.NET MVC2 Framework” (2nd edition) by Steven Sanderson.  (There’s already a version available for MVC3, but it’s not out on Kindle yet.  I may extoll the virtues of my Kindle in another post, which I have become totally addicted to, but suffice it to say these thick technical books are a lot easier to carry around in Kindle form, and they’re generally about 10 GBP cheaper in the UK).  Anyway Sanderson’s MVC2 book is brilliant; he’s very clear and thorough, and I highly recommend his books.  He taught me a lot about MVC2, which seems light-years ahead of traditional ASP.NET, but also a lot about TDD and associated TDD tools such as Nunit, Ninject and Moq.  I read the book, went through the walk-through on how to build the sample “SportsStore” app, then built my own application based on the architecture he uses on “SportsStore”.  As he does in the book, I used LINQ to SQL for ORM; I used Visual Studio 2010 as my development environment.

My idea to address the CMS requirement was that users would edit data in a “SiteObjects” table (analagous to Sanderson’s “Products” table), where each “SiteObject” record represents a single piece of data that would appear on a web page.  Then they would “publish” that data by clicking a hyperlink in the “Admin” area.  This would serialize the data to XML, which would then be stored in a column in a “PageObjects” table, where each “PageObject” record represents a single web page in the site.  There was a column in the PageObjects table for the “preview” version, and another for the “live” version.  A user could request the preview version by including a parameter in the URL’s query string (e.g. “?preview=true”).

Incidentally this setup also made it possible to send the data out for translation by a translation service, which would receive the English version of the XML file, and would then return to us a translated version of the file (e.g. Spanish); the Spanish file could then be uploaded, deserialized to populate the appropriate Spanish records in the SiteObjects table; at the same time the “preview” field would be updated; then when the CMS admin person was ready, they could click another hyperlink in the Admin area and “publish” (i.e. copy) that XML to the “live” field which was visibile by default when viewing the site.

A single main method in my controller acted as the entry point to the application, determining which page the user wanted, and which language they wanted to display it in, based on the URL and the routing configuration.  Based on those parameters, the method would then make a call to a factory method in my “repository” class which would find the appropriate “PageObjects” record and return the XML containing the data needed to render the page.

Here’s a screenshot of a portion of a “PageObject” record as seen in SQL server where you can see the start of the XML data that resides in the “LiveXMLData” field and the “PreviewXMLData” field.

HubPageEnglish

Here’s a bit more about how the XML looks:

<?xml version="1.0" encoding="utf-8"?>

<PageDataDefinition xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <PageObjectID>15</PageObjectID>

  <PageObjectName>HubPage-English</PageObjectName>

  <PageTypeID>1</PageTypeID>

  <PageTypeName>HubPage</PageTypeName>

  <LanguageID>1</LanguageID>

  <LanguageName>Irish English</LanguageName>

  <LanguageCode>en-ie</LanguageCode>

  <RegionCode>ie</RegionCode>

  <AltLangCode>en</AltLangCode>

  <ArtistID>8</ArtistID>

  <ArtistName>No Specific Artist</ArtistName>

  <PageNameUrlFragment>hub-page</PageNameUrlFragment>

  <Modules>

    <Module ModuleID="1" ModuleName="HubPage">

      <SiteObjects>

        <SiteObject SiteObjectID="1" SiteObjectName="HubPage_PageTitle" SiteObjectType="TextWithoutURL" ModuleID="1" LanguageID="1" ArtistID="8" EasyAccessShortKey="hp_pgtitle">

          <SODescription>This should contain the page title, if it is a title that is specific to the hub page.</SODescription>

          <LastUpdated>1/17/2011 2:22:12 PM</LastUpdated>

          <UpdatedBy>Super_1</UpdatedBy>

          <Value>My Really Cool Hub Page Title</Value>

        </SiteObject>

Here’s the PageDataDefinition class:

using System;

using System.Collections.Generic;

using System.IO;

using System.Text;

using System.Xml;

using System.Xml.Serialization;

 

namespace ClientProjectName.Domain.Entities

{

    [Serializable]

    public class PageDataDefinition

    {

        #region constructors

 

        public PageDataDefinition()

        {

            ModuleDataDefinitions = new List<ModuleDataDefinition>();

        }

 

        public PageDataDefinition(List<ModuleDataDefinition> moduleDataDefinitions)

        {

            ModuleDataDefinitions = moduleDataDefinitions;

        }

 

        #endregion

 

        #region properties

 

        [XmlElement("PageObjectID")]

        public string PageObjectID { get; set; }

 

        [XmlElement("PageObjectName")]

        public string PageObjectName { get; set; }

 

        [XmlElement("PageTypeID")]

        public string PageTypeID { get; set; }

 

        [XmlElement("PageTypeName")]

        public string PageTypeName { get; set; }

 

        [XmlElement("LanguageID")]

        public string LanguageID { get; set; }

 

        [XmlElement("LanguageName")]

        public string LanguageName { get; set; }

 

        [XmlElement("LanguageCode")]

        public string LanguageCode { get; set; }

 

        [XmlElement("RegionCode")]

        public string RegionCode { get; set; }

 

        [XmlElement("AltLangCode")]

        public string AltLangCode { get; set; }

 

        [XmlElement("ArtistID")]

        public string ArtistID { get; set; }

 

        [XmlElement("ArtistName")]

        public string ArtistName { get; set; }

 

        [XmlElement("PageNameUrlFragment")]

        public string PageNameUrlFragment { get; set; }

 

        [XmlArray("Modules"), XmlArrayItem("Module")]

        public List<ModuleDataDefinition> ModuleDataDefinitions { get; set; }

 

        #endregion

 

        public static PageDataDefinition Deserialize(string xmlString, Type type)

        {

            XmlSerializer serializer = new XmlSerializer(type);

 

            using (StringReader reader = new StringReader(xmlString))

            {

                return (PageDataDefinition)serializer.Deserialize(reader);

            }

        }

 

        public static string Serialize(PageDataDefinition pageDataDefinition)

        {

            XmlSerializer serializer = new XmlSerializer(pageDataDefinition.GetType());

 

            using (MemoryStream ms = new MemoryStream())

            {

                using (XmlTextWriter xmlWriter = new XmlTextWriter(ms, Encoding.UTF8))

                {

                    serializer.Serialize(xmlWriter, pageDataDefinition);

 

                    xmlWriter.Flush();

 

                    ms.Seek(0, SeekOrigin.Begin);

 

                    using (StreamReader reader = new StreamReader(ms, Encoding.UTF8))

                    {

                        return reader.ReadToEnd();

                    }

                }

            }

        }

 

    }

}

 

 

Here’s a bit of code used in the main MVC2 controller to get the desired PageObject:

        // get the PageObject based on the passed (or default) parameters

        var pageObjectToShow = pageObjectsRepository.PageObjects.FirstOrDefault(x =>

            ((x.Language.LanguageCode == languageCode) && x.PageNameUrlFragment == pageName));

Here’s the call from the controller to a method in the repository that tells whether to get the preview or live version of the XML:

        // get the PageDataDefinition object by deserializing the XML in the PageObject.LiveXMLData field

        var pageDataDefinitionToShow = pageObjectsRepository.GetPDD(pageObjectToShow,

            usePreview ? Constants.XmlDataState.Preview : Constants.XmlDataState.Live);

Here’s the “GetPDD” method:

        // we only want to deserialize when a page is requested, for performance reasons

        public PageDataDefinition GetPDD(PageObject po, Constants.XmlDataState xmlDataState)

        {

            var httpContext = HttpContext.Current;

            PageDataDefinition pageDataDefinition = null;

 

            try

            {

                // assumes XML exists in the database and is in the correct format.         

                pageDataDefinition = PageDataDefinition.Deserialize(

                        xmlDataState == Constants.XmlDataState.Live

                        ? po.LiveXMLData

                        : po.PreviewXMLData,

                        typeof(PageDataDefinition));

            }

            catch (Exception e)

            {

                // If we fail to get the XML, it's fatal.

                var utilities = new Utilities.Utilities();

                var pageObjectRef = String.Format("PageObjectID = {0}, PageObjectName={1}",

                                            po.PageObjectID,

                                            po.PageObjectName);

 

                utilities.LogEvent(connectionString,

                                   Constants.AppEvents.Error,

                                   Constants.LogShortDescriptions.ErrorGettingPDDInPageObjectsRepository +

                                   " - Exception msg = " + e.Message,

                                   pageObjectRef,

                                   httpContext.User.Identity.Name);

            }

 

            return pageDataDefinition;

        }

The “PageDataDefinition” object is a deserialized complex type containing a hierarchy of “page”, “modules” and “site objects” where the page is the highest-level container; the “module” represents a lower level container (which can be rendered as a partial-page view in MVC2, i.e. an ASCX file); and each “module” contains a set of site objects.

Then, rather than forcing front-end developers to make complex calls to navigate the hierarchy of the PageDataDefinition class, in my Model class (this is a “ViewModel” object or “Data Transfer” object as described by Sanderson in his book), I flatten the hierarchy by creating a “Get( )” method which allows them to simply pass in the parameters for the object they want, and it returns the desired object from a dictionary.  Here’s the code that sets up the dictionary:

public class MyViewModel

{

    public Dictionary<string, SiteObjectDataDefinition> SODDLookup { get; set; }

// etc… and here’s the method:

public void PopulateSODDLookup(PageDataDefinition thePDD)

{

    foreach (var mdd in thePDD.ModuleDataDefinitions)

    {

        foreach (var sodd in mdd.SiteObjectDataDefinitions)

        {

            var soddKey =

                sodd.EasyAccessShortKey +

                "-M" + sodd.ModuleID.Trim() +

                "-L" + sodd.LanguageID.Trim() +

                "-A" + sodd.ArtistID.Trim();

 

            try

            {

                SODDLookup.Add(soddKey, sodd);

            }

            catch (Exception ex)

            {

                // this is mainly useful during development;

                // this should never happen in production as it would imply

                // a bad setup in the database (normally such errors would occur if

                // the app is attempting to add a key that's already in the dictionary)

                Utilities.LogEvent(ConnectionString,

                                Constants.AppEvents.Error,

                                Constants.LogShortDescriptions.ErrorPopulatingSODDLookup,

                                "SODDKey = " + soddKey + ", Error = " + ex.Message,

                                "G7Con");

            }                   

        }

    }

}

… and here’s the “Get( )” method… note the rendering of the error message, this enabled front-end devs to know if their call was incorrect with respect to the data in the database:

public SiteObjectDataDefinition Get(string theKey)

{           

    SiteObjectDataDefinition retVal = null;

 

    // if the language is not specified, get it from the context

    if (theKey.Contains("L?"))

    {

        theKey = theKey.Replace("L?", "L" + PDD.LanguageID.Trim());

    }

 

    // if the artist is not specified, get it from the context

    if (theKey.Contains("A?"))

    {

        theKey = theKey.Replace("A?", "A" + PDD.ArtistID.Trim());

    }

 

    if ( !SODDLookup.TryGetValue(theKey, out retVal) )

    {

        var errMsg = "SiteObject not found, bad call to Get() method:  " + theKey;

        retVal = new SiteObjectDataDefinition { URL = errMsg, Value = errMsg, ClickthroughUrl = errMsg };

    }

 

    return retVal;

 

}

So the front-end markup for a call to this method (typically in an ASCX file) would look like this (note the “EasyAccessShortKey” attribute in the XML example above; that acts as the key to the dictionary):

<%@ Control Language = "C#" Inherits = "System.Web.Mvc.ViewUserControl<ClientProjectName.WebUI.Models.MyViewModel>" %>

<section id="about">

    <div class="pos1">

        <header>

            <h2><%: Model.Get("hpb_abouttitle-M9-L?-A2").Value %></h2>

 

Anyway you get the idea.  Perhaps this will be food for thought for somebody!  Best wishes, –Dave

Wednesday, 16 February 2011

Request.Browser.IsMobileDevice

It's known that the .Net framework's "Request.Browser.IsMobileDevice" is not entirely reliable in all cases as evidenced by the fact that our MVC2 site wasn't correctly detecting Android as a mobile, and as evidenced by some hits you can see in this search:

http://www.bing.com/search?q=request.browser.ismobiledevice&src=IE-SearchBox&FORM=IE8SRC

If we really want reliable mobile detection we need to incorporate the WURFL database (a giant XML file of every mobile device - see http://wurfl.sourceforge.net/ ) and from what I’ve seen, the preferred implementation of this for .Net appears to be “51degrees.mobi” …

http://51degrees.codeplex.com/

On the MVC2 project I’ve been working on recently, I was using 51degrees.mobi in development; it seemed very effective, and you can do incredibly granular detection with it, but was a bit heavyweight for my particular project, the requirements of which were (in the case of mobile detection) simply to detect whether it was a mobile device, and display a different view if so.  Our list of supported mobiles was quite small, and the only one that weren’t being detected correctly by the “Request.Browser.IsMobileDevice” flag were Android phones.

So I was just using “Request.Browser.IsMobileDevice” which was working fine until I heard about the Android issue. 

Anyway, the following is a bit of a hack, but I just handled that case in a specific way… I looked at the "user agent" value that comes across in the request.  I also looked (physically, not in code) at the WURFL XML file that comes with 51degress.mobi, for a generic Android phone, because I assume that’s how WURFL is doing its detection anyway.  In the WURFL database, the user agent string for a generic Android is:

Mozilla/5.0 (Linux; U; Android 0.5; en-us) AppleWebKit/522+ (KHTML, like Gecko) Safari/419.3

So it seemed safe to assume “Android” would exist in the user agent string; so now I'm just looking for the word "android" (converted to lower case in code) in the user agent string, and if it's found, I tell the app to behave just like it does with other mobile devices.

// special case; Android phones were not being detected as mobiles by Request.Browser.IsMobile;

// this is a quick & dirty solution.  The preferred solution would be to integrate the WURFL database

// and the DLLs from http://51degrees.codeplex.com/ but it's too heavyweight of a solution for this

 

var useragent = Request.UserAgent;

var isAndroid = false;

 

if (useragent != null)

{

    if (useragent.ToLower().Contains(Constants.MobileDevices.Android))

    {

        isAndroid = true;

    }           

}

 

if (Request.Browser.IsMobileDevice || isAndroid)

{

    // … do something specific for mobiles, particularly, display the mobile view

I tested it with a "user agent switcher" add-on for Firefox that I found here:

http://chrispederick.com/work/user-agent-switcher/features/

and it correctly went to the mobile version of the site as if I were running on an Android.

The add-on might not work in every case, but in this situation it did the job, and is bit easier than using a mobile emulator.

Anyway again, a bit of a hack, but turned out to be an effective quick and dirty solution to this particular problem.

Tuesday, 11 January 2011

Server error in “AUTHENTICATE” application…

I couldn’t help but be amused…

I received an email from the Microsoft Certification Program telling me I needed to log into their site just to keep my ID active.  So I clicked the link in the email that said “Log into the MCP Member Site”…

Email

 

On the login page I entered my Windows Live ID, and got a YSOD (Yellow Screen of Death)!

Error

Tsk tsk!

Happens to the best of ‘em…