MVC Areas Anti-Pattern

I was working on the design of a small site where we have public display of information in one format and a set of administrative screens that allow authorised users to create and edit the information.

“I know”, I thought, “this is a perfect case for MVC Areas” – and boy was I wrong!

I should have realised that the problems had started when all the routing started playing up..

  1. Route names must be unique across *all* areas
  2. If there are controller names in common in different areas, all routes need to be updated to bind the namespace of the controller you want!

Yuck! – did the MVC team think about the open-closed principle?

Then I realised I’d made a category error – mis-applying the area concept. I was making the same sort of error that people make when implementing SOA, breaking down services according to functional granularity rather than business function.

So, instead of having two Product controllers, one in the main area, the other in the admin area, I should have one Product controller, still securing the appropriate methods, and still using routes to present some of the views under ~/admin/product and some under ~/product.

Areas should be reserved for coherent chunks of business functionality e.g. Sales, Marketing etc and I’m still not particularly happy that if I have a concept in common e.g. Customer, then the routes are going to clash, but I’m glad I realised my error before I’d built even more in the wrong direction.

Route Testing and MVC 2.0 Areas

I’ve been using the MvcContrib.TestHelper class for a while now to get rather nice fluent testing of the routes in my MVC applications.

A typical test class would look like this

public class CategoryRoutesFixture : RoutesFixture
{
    private const int categoryId = 34;

    private static string BaseUrl
    {
        get { return "~/admin/Category"; }
    }

    [Test]
    public void Index()
    {
        BaseUrl.ShouldMapTo(x => x.Index());
    }

    [Test]
    public void Create()
    {
        (BaseUrl + "/create").ShouldMapTo(x => x.Create());
    }

    [Test]
    public void Show()
    {
        (BaseUrl + "/" + categoryId).ShouldMapTo(x => x.Show(categoryId));
    }

    [Test]
    public void Edit()
    {
        (BaseUrl + string.Format("/{0}/edit", categoryId)).ShouldMapTo(x => x.Edit(categoryId));
    }
}

The base class just takes care of initialising the routes collection from the MvcApplication.

I’ve just had a need to use the new Areas functionality in MVC 2.0, and one interesting wrinkle (there are a few!) is that that the RegisterAllAreas functionality wasn’t built with testing particularly in mind as it seems to need a running instance of ASP.NET to function correctly. After trying a few things and wading through even more blog posts I finally found an answer on StackOverflow.

The TestHelper class is not area aware, so the workaround is to configure the RoutesCollection appropriately for the class you are testing, so now for my main area I have

protected override void InitializeRoutes(RouteCollection routes)
{
    MvcApplication.RegisterRoutes(routes);
}

Whereas in my admin area I have

protected override void InitializeRoutes(RouteCollection routes)
{
    RouteTable.Routes.Clear();
    var adminReg = new AdminAreaRegistration();
    adminReg.RegisterArea(new AreaRegistrationContext(adminReg.AreaName, RouteTable.Routes));
}

Not particularly tricky once you know about it, but a pain to discover if you don't

Algorithm Performance

I was chatting to a colleague recently who although he was a very good programmer, did not have a computer science/maths background – this was fine until he wanted to use bubble sort on a large(ish) (100k) number of records and I had to explain to him about how algorithms that take n^2 time are not your friend for big (or even little) n.

One of the most important decisions you can make when optimizing an application is the up-front choice of algorithm to use, performance tuning and optimization can make a difference but you are very lucky to achieve 2x-5x improvement, to be able to make 10x or 100x improvement in your application you need decent algorithm choice.

Here’s a little table I put together to help explain why you have to be careful and also know the time/space performance of any algorithm you put in your applications.

Items const ln n log n n n^2 n^3 2^n 3^n n!
1 1 0 0 1 1 1 2 3 1
10 1 2 1 10 100 1,000 1,024 5.90E+04 3.63E+06
100 1 5 2 100 10,000 1,000,000 1.268E+30 5.15E+47 9.33E+157
1,000 1 7 3 1.00E+03 1.00E+06 1.00E+09 1.07E+301    
10,000 1 9 4 1.00E+04 1.00E+08 1.00E+12      
100,000 1 12 5 1.00E+05 1.00E+10 1.00E+15      
1,000,000 1 14 6 1.00E+06 1.00E+12 1.00E+18      
10,000,000 1 16 7 1.00E+07 1.00E+14 1.00E+21      

Now is this the approximate time/space growth you will get; how long your process will take will depend on the cost of each operation and to give you a guide, here’s now many units there are in one year

  Seconds Milliseconds Microseconds
1 year 3.16E+07 3.16E+10 3.16E+13

So if you happen to pick O(n^3) algorithm you are going to have to waiting between 9 minutes and around 0 months to solve for just a 1,000 items! Notice also that as the notation power grows, even micro-second execution times (or expanding onto Cloud infrastructure) isn’t going to help too much.

PS Nice little tool called Tabelizer took my original spreadsheet and converted it to HTML for me.

Automating Visual Studio Templates

I find Visual Studio Item Templates very useful, but a lot of teams I encounter haven’t really adopted them as they can be a pain to construct. Here’s the technique I use to manage the templates and make it painless to add new ones and modify existing templates if they need to change. What we do is put the templates into source control and then use a build process to automate the production and distribution of the zip files.

There are two types of templates, project and item and they are accessed via directories configured under the Visual Studio options dialog

vstemplates

When working in a team, it is a good idea to map these two directories to a central location – that way as new templates are developed or improved the entire team benefits at once.

A template is a actually just a zip file containing one or more files plus a template file in XML that tell Visual Studio what to do – and that’s part of the problem. The directory structure in the zip must reflect exactly the structure where you want to put the files in the project and the templates themselves must be structured into a directory hierarchy to get the sections support in Visual Studio, for example see the screen shot of my MVP presentation tier templates.

vstemplates2

So, first of all create a root directory for all your templates, and then create two main subdirectories; items and projects. In each create subdirectories to classify your templates, e.g. Core, Data, Web, etc. In the appropriate directory you then need a directory per template, see below

vstemplates3

This is a simple template I have for creating a flag enum, i.e. an enum that is a bit field – the source is shown below.

namespace $rootnamespace$
{
    using System;

    /// <summary>
    /// 
    /// </summary>
    [Flags]
    public enum $filename$
    {
        // Suggest using hex rather than decimals as below to avoid overlapping/missing values
        A = 0x1,
        B = 0x2,
        C = 0x4,
        D = 0x8,
        E = 0x10,
        F = Ox20
    }
}

There are two macro replace values in the file, rootnamespace, which is replaced by the namespace of the directory you create the file in, and filename which is replaced by the value you enter in the Add Item dialog. We also have to produce the accompanying template file which must be called MyTemplate.vstemplate

<VSTemplate Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="Item">
  <TemplateData>
    <DefaultName>Flags.cs</DefaultName>
    <Name>Flag Enum</Name>
    <Description>Enum that is meant to be a set of flags</Description>
    <ProjectType>CSharp</ProjectType>
    <SortOrder>10</SortOrder>
    <Icon Package="{FAE04EC1-301F-11d3-BF4B-00C04F79EFBC}" ID="4515" />
  </TemplateData>
  <TemplateContent>
    <References />
    <ProjectItem SubType="Code" TargetFileName="$fileinputname$.cs" ReplaceParameters="true">Enum.cs</ProjectItem>
  </TemplateContent>
</VSTemplate>

Now next we need the MSBuild Community Tasks assembly and an MSBuild project file, items.proj

<?xml version="1.0" encoding="UTF-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" >
	<!-- Basic properties -->
	<PropertyGroup>
		<ToolsPath Condition="'$(ToolsPath)' == ''">C:\Program Files</ToolsPath>
	</PropertyGroup>
	
	<!-- Import a bunch of external targets -->
	<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>

	<!-- The templates we want to produce -->
	<ItemGroup>
		...
		<ItemTemplate Include="FlagEnum" />
		...
		<ItemTemplate Include="ViewBundle">
			<Category>Web\</Category>
		</ItemTemplate>
		...
	</ItemGroup>

	<!-- Ok, standard action is to create clean zip files -->
	<Target Name="Build" DependsOnTargets="Clean;Zip;" />

	<Target Name="Clean">
		<!-- Need this for the first time through when Build doesn't exist -->
		<MakeDir Directories="Build" Condition="!Exists('Build')" />
		<!-- Can't delete it if it has contents, so delete them first -->
		<Delete Include="Build\**\*.*" Condition="!Exists('Build')" />
		<RemoveDir Directories="Build" />
		<MakeDir Directories="Build" Condition="!Exists('Build')" />
	</Target>

	<Target Name="Zip" Outputs="%(ItemTemplate.Identity)" >
		<MakeDir Directories="Build\%(ItemTemplate.Category)" Condition="%(ItemTemplate.Category) != ''" />
		<CreateItem Include="$(MSBuildProjectDirectory)\%(ItemTemplate.Category)%(ItemTemplate.Identity)\**\*.*" 
			Exclude="$(MSBuildProjectDirectory)\%(ItemTemplate.Category)%(ItemTemplate.Identity)\**\_svn\**\*.*;$(MSBuildProjectDirectory)\%(ItemTemplate.Category)%(ItemTemplate.Identity)\**\.svn\**\*.*">
			<Output TaskParameter="Include" ItemName="ZipFiles" />
		</CreateItem>
		<Zip Files="@(ZipFiles)" 
			ZipFileName="$(MSBuildProjectDirectory)\Build\%(ItemTemplate.Category)%(ItemTemplate.Identity).zip" 
			WorkingDirectory="$(MSBuildProjectDirectory)\%(ItemTemplate.Category)%(ItemTemplate.Identity)" />
	</Target>
</Project>

I suggest keeping the template files in alphabetic order in the target list irrespective of directory, it’s much easier to work out if you have missed one out that way.

Now if you set up a project in your favourite continuous integration server, whenever any developer creates or improves a template, the build process produces all the zip files and then can copy them to the shared directory.

MVC 2 EditorForModel and DropDownList

Sometimes doing very basic things can be quite tricky in new technologies; case in point presenting a DropDownList (a ComboBox to those, including me, with a VB background) using the new EditorForModel syntax in ASP.NET MVC 2.

I had a little class in my MVP framework called IdLabel which as the name implied just held an Id and a Label so that I wasn’t forced to have a separate display and edit model for every trivial case, so I wanted to do the same sort of thing when writing my shiny new MVC apps. There’s a class called SelectListItem which fits the bill, but unfortunately a decision late in the MVC 2 Beta meant that by default, the object display/edit templates will not process anything other than basic types.

There is a slight hacky workaround which is to implement your own TypeConverter to tell the framework that it can be turned into a string, but this is normally then coupled by using an Attribute at compile time – and we don’t own SelectListItem. Fortunately, there’s a way around this using a little bit of reflection

public static class TypeUtility
{
    /// <summary>
    /// Registers a type converter against a type we don't own
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TConverter"></typeparam>
    public static void RegisterTypeConverter()
        where TConverter : TypeConverter
    {
        var attr = new Attribute[1];

        var vConv = new TypeConverterAttribute(typeof(TConverter));
        attr[0] = vConv;
        TypeDescriptor.AddAttributes(typeof(T), attr);
    }
}

So now starting with our very simple domain model

public class Supplier
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Supplier Supplier { get; set; }
}

we can have an equally simple view model

public class ProductViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    [DropDownList]
    public SelectListItem Supplier { get; set; }
}
Now the custom DropDownList attribute and associated classes are taken from Kazi's blog with the slight modification of adding a couple of constructor overloads so that the defaults work for SelectListItem.

Having done all that we can proceed to what the controller has to do, what’s shown below is a simplification of my current controller which I'll tell you about shortly.

public ProductController 
{
     ...
     public ActionResult Edit(int id)
     {
          var entity = repository.FindOne(id);
          var model = builder.Convert(entity);
          
          var types = repository.FindAll();
          ViewData["SupplierList"] = builder.Convert(types);

          return VIew(model);
     }
     ...
}

The builder abstracts all of the work mapping the domain and view models and is based on AutoMapper.

Then we come to the display template, idea here is to show the label rather than the idea – one extension I have in mind is to convert this to a URL to allow display/edit of the related data.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<script runat="server">
    string FormattedModelValue
    {
        get
        {
            // TODO: Might want to test for DropDownList attribute for other complex models.
            if (Model == null)
            {
                return null;
            }
            return Model is SelectListItem ? ((SelectListItem) Model).Text : Model.ToString();
        }        
    }
</script>
<%= Html.Encode(FormattedModelValue) %>

The next bit is the edit template. I’m using majic strings to couple the list definition of the DropDownList to avoid having to make the views strongly-typed on SelectLists; I view this as outside of the scope of the view model, though you may disagree. If there’s a need to alter this, the first parameter of the DropDownList attribute takes the ViewData key name.

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%@ Import Namespace="Hippo.Web.Mvc.Templating" %>
<script runat="server">
    DropDownListAttribute GetDropDownListAttribute()
    {
        var metaData = ViewData.ModelMetadata as FieldTemplateMetadata;

        return (metaData != null) ? metaData.Attributes.OfType<DropDownListAttribute>().SingleOrDefault() : null;
    }
    
    IEnumerable<SelectListItem> GetSelectList()
    {
        var metaData = ViewData.ModelMetadata as FieldTemplateMetadata;        
        if (metaData == null)
        {
            return null;
        }

        var attribute = metaData.Attributes.OfType<DropDownListAttribute>().SingleOrDefault();
        if (attribute == null)
        {
            return null;
        }

        var key = attribute.ViewDataKey ?? (metaData.PropertyName + "List");
        var selected = attribute.GetSelectedValue(Model);
        // This makes it work for both SelectList and any other enumerable
        var sl = new SelectList(ViewData[key] as IEnumerable, attribute.DataValueField, attribute.DataTextField, selected);

        return sl;
    }
</script>
<% var attribute = GetDropDownListAttribute();%>
<% if (attribute != null) {%>
    <%= Html.DropDownList(null, GetSelectList(), attribute.OptionLabel, attribute.HtmlAttributes) %>
<% }%>
<% else {%>
    <%= Html.DisplayForModel()%>
<% }%>

The non-obvious problem here is that due to a bug in MVC 2, the Html.DropDownList builder ignores any selected item that you pass it and also does not look at the model (the offending line appears to be line 188 in SelectExtensions). The trick I found (today) was to push the Model value into the ViewData against the PropertyName, it does pick that up and pushes it as the selected item – there won’t be anything else there as we have a strongly-typed view, apart from the SelectLists.

One other thing to note is that Kazi’s DropDownList attribute can be given a list of anything and you can specify the Value and Text properties to be pushed into the SelectList. Also, your model doesn’t have to use SelectListItem, but if you don’t be prepared to write a TypeConverter each time you want a DropDownList!

Debugging ASP.NET MVC 2 Source Code

I'm trying to write some templates for MVC 2 and one of the most useful things I've found is being able to step into the source code and see how it is actually interpreting what you've written.

It's easy enough to acquire the source, but what you might not have done before is set up a symbol server. A symbol server is a location that the Windows and Visual Studio debugging tools can use to obtain pdb files, so that you can debug almost anything, including drivers and the operating system!

Setup Symbol Server

  1. Create a directory, preferably in a shared location if there's more than one of you as this stuff can get quite big.
  2. Change the directory to allow compression as pdb's will typically compress by > 50%.
  3. Add a new system environment variable _NT_SYMBOL_PATH and set it to SRV*<Shared Directory>*http://referencesource.microsoft.com/symbols;http://msdl.microsoft.com/download/symbols
    vssrc2

Enable Debug Symbols in Visual Studio

  1. Install the debugging tools for Windows and run Start Menu|Programs|Microsoft Windows SDK 7.1|Visual Studio Registration|Windows SDK Configuration Tool; this allows Visual Studio to use the symbols.
  2. Run Visual Studio and go to Tools -> Option -> Debugging -> General
  3. Uncheck Enable Just My Code
  4. Check Enable .NET Framework source stepping
    vssrc1
  5. Change to Symbols
  6. Update "Cache symbols from symbol servers to this directory" to point at your shared symbol directory, then hit "Load symbols from Microsoft symbol servers", this will take a while and chew up about 111Mb (~48Mb compressed)
  7. Put a break point in one of you controllers and run through to that point.
  8. Pick a stack frame from System.Web.Mvc from Call Stack and select Load Symbols if it is not disabled and then Go To Source Code, picking the location you have put MVC 2
    vssrc3

One other interesting angle on this is Symbol Source who are providing symbol/source service for a bunch of open source projects including NHibernate, Castle and MVC Contrib

Four things you need to know about Recaptcha

Working on a project where we needed a (slight) proof of humaness, and we opted to use Recaptcha as it has a fairly simple integration with .NET.

Was fine until we wanted to use custom styling to tie in with the site which is when the fun started!  A few hours later, after downloading the project's sample app, I found some things out that I thought I'd share with you...

1. The Recaptcha control must be positioned after the recaptcha_image div and recaptcha_response_field

2. The killer: your recaptcha_response_field must have a name attribute of recaptcha_response_field as well as its id - otherwise Recaptcha won't see it.

3. You can specify your public/private key in the web.config AppSettings rather than against the control; RecaptchaPublicKey and RecaptchaPrivateKey respectively.

4. You can turn off Recaptcha validation either by setting the SkipRecaptcha property of the control or RecaptchaSkipValidation.

The first two are the most important to getting Recaptcha to work with custom styling;  I know the properties are documented on the control, but I managed to miss them for a couple of hours so I thought others might do the same

 

Subversion Upgrade and svn:externals changes

I'm just in the process of restructuring my source control environment, splitting the single subversion repository into multiple repositories.

Couple of reasons for this..

My repository is getting a bit big at 1.5Gb a big chunk of this are binary files produced by my continous integration process, so I want to break this out to a dedicated repository.

I'd also like to put each client's work into a separate repository, this makes it easier to archive off and/or remove it at the end of a project as there's no way to delete files from a repository apart from dumping it and filtering it into a new one.

One nice new feature I've found that was introduced in 1.5 (I'm using 1.6.4) is the new syntax for svn:externals

Externals are a way of referencing another repository location which can be in the same repository or a different one. This is how I use my floating tags idea to keep projects up to date across minor changes.

In the project's lib directory, I have a svn:externals entry that points at all the libraries that the project depends on

The old format looked like this..

logging svn://myrepository.com/Binaries/Log4Net/tags/1.2.10.0/bin
nhibernate svn://myrepository.com/Binaries/NHibernate/tags/2.0.x/bin

In svn 1.5 they have introduced a couple of new syntax options that means that you don't have to embed the access type (svn, http, https etc) or the server, but the syntax changes slightly to

/Binaries/Log4Net/tags/1.2.10.0/bin logging
/Binaries/NHibernate/tags/2.0.x/bin nhibernate

This will make life much easier if I have to relocate a repository etc. Check out the release notes for more details

Quality Myths

Microsoft has published the results of some empirical studies about how development practices affect quality
  • Test Driven Development improves quality by 60 to 90 percent but takes 15 to 35 percent more ‘up front’ time. The time spent is compensated by savings in maintenance time later on.
  • Team & organization structure has a huge impact on quality. Although this is conventional wisdom the study publishes figures to prove this. The metrics used  data such as how many engineers are involved in a project, how many times individual source files were modified.
  • Code coverage in tests must be used intelligently, and has less overall impact than other factors.

Another paper hi-lights the issues of not running the unit tests....

"Specifically, recent contact with the IBM team indicated that in one of the subsequent releases (more than five releases since the case study) some members of the team (grown 50% since the first release) have taken some shortcuts by not running the unit tests, and consequently the defect density increased temporally compared to previous releases."

A friend of mine pointed me at this video as a further illustration

Swine Flu

Just recovering from flu at the moment and I'm an official Swine Flu statistic.

Not the nicest of bugs, couldn't keep any food down until the anti-virals kicked in but the funniest thing about the whole episode is the screening questionnaire to see if you qualify for the Tamiflu.

First question is whether you are enquiring on behalf of yourself or someone else, on being told I that I was asking for myself the call centre staff (apologetically) asked

"Are you conscious?"

Now I'm not sure if this is some form of modified Turing test, but I think this belongs on the other branch of the decision tree :-)