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