Archive

Archive for the ‘C#’ Category

Serving different views for mobile devices in ASP.NET MVC

May 3rd, 2010

As browsing becomes more commonplace on phones, sub-notebooks and (within the next year or so) Tablet PCs, there’s an increased appetite to tailor your user experience for people using these “non-desktop” devices.  You can leverage your existing application infrastructure without having to create costly or outsource applications for specific (*cough* iPhone) platforms that have lots of market share, to the exclusion of others (*cough* iPhone).

There are some excellent examples of this in the wild, Facebook and the BBC do a great job of this already.

So what about us ASP.NET MVC types?  Well thankfully, there’s a lot of stuff built in to the framework to allow us to do this with relative ease.  First you’re going to need a few things..

1) Go grab the latest Mobile Device Browser File from http://mdbf.codeplex.com.  If you’re familiar with the old “Browser Caps”, it’s the same sort of thing.  A regularly updated collection of device data.  It’s pretty interesting on it’s own, breaking down incoming devices by user agent / headers and offering you various stats (touch enabled, screen resolution etc).  You’ll probably want to keep this up to date periodically.

2) A new ViewEngine!  Thankfully, ASP.NET MVC has a pretty flexible pipeline when it comes to slotting in new ViewEngines.  The most transparent way to switch out which view you’re serving for any given request is to override some of the logic in the default ViewEngine to look elsewhere when a View is requested by the MVC framework.

3) A way to test this stuff.  I normally break out the “User Agent Switcher” FireFox plugin which you can grab here: https://addons.mozilla.org/en-US/firefox/addon/59

 

The View Engine

In order to keep this as close to vanilla MVC as possible, I’m going to extend the regular WebFormsViewEngine to add mobile device detection and view overriding.  What I’m going to do is check for a mobile browser when a request reaches the view engine, and if one is found, add some extra paths to look for the view files in at the top of the list of locations searched.  By doing this, we can prioritise the mobile edition of a website if the user is visiting from a phone, while degrading gracefully, allowing the regular version of the website to be served if a mobile version of a given page isn’t available.  This actually allows us to support mobile views piece by piece rather than forcing us to support the entire site out of the box.

Unfortunately, a few of the methods surrounding view resolution are marked as private in the WebFormsViewEngine and as such are inaccessible.  I’ve had to reflect in and copy a couple of methods to get around this.  Ideally the access modifier on these could be changed in later versions of the framework.

The key method we have to work with is

public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{ … }

What we’re going to do is add a few extra locations based on the browser type.  With the mobile device browser file installed, this is really simple:

public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
    if (controllerContext == null)
    {
        throw new ArgumentNullException("controllerContext");
    }
    if (String.IsNullOrEmpty(viewName))
    {
        throw new ArgumentException("viewName");
    }

    List<string> viewLocationsSearched;
    List<string> masterLocationsSearched;

    string[] viewLocationsToSearch = ViewLocationFormats;
    string[] masterLocationsToSearch = MasterLocationFormats;

    viewLocationsToSearch = AddMobileViewLocations(controllerContext, viewLocationsToSearch, MobileViewLocationFormats);
    masterLocationsToSearch = AddMobileViewLocations(controllerContext, masterLocationsToSearch, MobileMasterLocationFormats);

    string controllerName = controllerContext.RouteData.GetRequiredString("controller");
    string viewPath = GetPath(controllerContext, viewLocationsToSearch, viewName, controllerName, CacheKeyPrefixView, useCache, out viewLocationsSearched);
    string masterPath = GetPath(controllerContext, masterLocationsToSearch, masterName, controllerName, CacheKeyPrefixMaster, useCache, out masterLocationsSearched);

    if (String.IsNullOrEmpty(viewPath)
        || (String.IsNullOrEmpty(masterPath)
        && !String.IsNullOrEmpty(masterName)))
    {
        return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
    }

    return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
}

You’ll notice there’s a few methods that get called in there.  The most important of which is “AddMobileViewLocations”.  This really is where all the legwork is done, and looks like this

public class SwitchingViewEngine : WebFormViewEngine
{
    private const string CacheKeyFormat = ":ViewCacheEntry:{0}:{1}:{2}:{3}:";
    private const string CacheKeyPrefixMaster = "Master";
    private const string CacheKeyPrefixView = "View";
    private static readonly List<string> EmptyLocations = new List<string>();

    protected string[] MobileViewLocationFormats { get; private set; }
    protected string[] MobileMasterLocationFormats { get; private set; }

    public SwitchingViewEngine()
    {
        ViewLocationFormats = new[]
                                  {
                                      "~/Views/{1}/{0}.aspx", "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.aspx",
                                      "~/Views/Shared/{0}.ascx"
                                  };

        MobileViewLocationFormats = new[]
                                        {
                                            "~/Views/{1}/{0}.mobile.aspx", "~/Views/{1}/{0}.mobile.ascx",
                                            "~/Views/Shared/{0}.mobile.aspx",
                                            "~/Views/Shared/{0}.mobile.ascx"
                                        };

        MasterLocationFormats = new[] {"~/Views/{1}/{0}.master", "~/Views/Shared/{0}.master"};
        MobileMasterLocationFormats = new[] {"~/Views/{1}/{0}.mobile.master", "~/Views/Shared/{0}.mobile.master"};
    }

    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {   …    }

    private static string[] AddMobileViewLocations(ControllerContext controllerContext,
                                                   string[] viewLocationsToSearch,
                                                   IEnumerable<string> mobileViewLocations)
    {
        if (controllerContext == null
            || controllerContext.HttpContext == null
            || controllerContext.HttpContext.Request == null
            || controllerContext.HttpContext.Request.Browser == null
            || viewLocationsToSearch == null
            || viewLocationsToSearch.Length == 0
            || mobileViewLocations == null
            || mobileViewLocations.ToList().Count == 0
            || !controllerContext.HttpContext.Request.Browser.IsMobileDevice)
        {
            return viewLocationsToSearch;
        }

        var mobileViews = viewLocationsToSearch.ToList();
        foreach (var view in mobileViewLocations.Reverse())
        {
            mobileViews.Insert(0, view);
        }

        viewLocationsToSearch = mobileViews.ToArray();

        return viewLocationsToSearch;
    }

This method takes the current ViewLocations that are defined at the top of the class, does a bunch of guard checks (to prevent mobile switching crashing your request.. call me paranoid), then verifies that controllerContext.HttpContext.Request.Browser.IsMobileDevice is true.  This check makes use of the browser device file.  If all the checks pass, it inserts the new “mobile view paths” at the very top of the list of paths to be searched when resolving the location of a view file.  The calling method then subsequently calls the method “GetPath” (which is one of the private methods I’ve had to reflect out of the framework source code).  GetPath searches the supplied list of potential view locations, and returns as soon as it finds a match.  In our case, if the browser is mobile, and a view file with the extension mobile.aspx is found, this will be the first view resolved and returned.

The full code listing for the view engine (don’t worry, there’s a link at the bottom to grab all of this in one archive):

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Mvc;

namespace MultipleViewMvcExample.DemoCode
{
    public class SwitchingViewEngine : WebFormViewEngine
    {
        private const string CacheKeyFormat = ":ViewCacheEntry:{0}:{1}:{2}:{3}:";
        private const string CacheKeyPrefixMaster = "Master";
        private const string CacheKeyPrefixView = "View";
        private static readonly List<string> EmptyLocations = new List<string>();

        protected string[] MobileViewLocationFormats { get; private set; }
        protected string[] MobileMasterLocationFormats { get; private set; }

        public SwitchingViewEngine()
        {
            ViewLocationFormats = new[]
                                      {
                                          "~/Views/{1}/{0}.aspx", "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.aspx",
                                          "~/Views/Shared/{0}.ascx"
                                      };

            MobileViewLocationFormats = new[]
                                            {
                                                "~/Views/{1}/{0}.mobile.aspx", "~/Views/{1}/{0}.mobile.ascx",
                                                "~/Views/Shared/{0}.mobile.aspx",
                                                "~/Views/Shared/{0}.mobile.ascx"
                                            };

            MasterLocationFormats = new[] {"~/Views/{1}/{0}.master", "~/Views/Shared/{0}.master"};
            MobileMasterLocationFormats = new[] {"~/Views/{1}/{0}.mobile.master", "~/Views/Shared/{0}.mobile.master"};
        }

        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (String.IsNullOrEmpty(viewName))
            {
                throw new ArgumentException("viewName");
            }

            List<string> viewLocationsSearched;
            List<string> masterLocationsSearched;

            string[] viewLocationsToSearch = ViewLocationFormats;
            string[] masterLocationsToSearch = MasterLocationFormats;

            viewLocationsToSearch = AddMobileViewLocations(controllerContext, viewLocationsToSearch, MobileViewLocationFormats);
            masterLocationsToSearch = AddMobileViewLocations(controllerContext, masterLocationsToSearch, MobileMasterLocationFormats);

            string controllerName = controllerContext.RouteData.GetRequiredString("controller");
            string viewPath = GetPath(controllerContext, viewLocationsToSearch, viewName, controllerName, CacheKeyPrefixView, useCache, out viewLocationsSearched);
            string masterPath = GetPath(controllerContext, masterLocationsToSearch, masterName, controllerName, CacheKeyPrefixMaster, useCache, out masterLocationsSearched);

            if (String.IsNullOrEmpty(viewPath)
                || (String.IsNullOrEmpty(masterPath)
                && !String.IsNullOrEmpty(masterName)))
            {
                return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
            }

            return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
        }

        private static string[] AddMobileViewLocations(ControllerContext controllerContext,
                                                       string[] viewLocationsToSearch,
                                                       IEnumerable<string> mobileViewLocations)
        {
            if (controllerContext == null
                || controllerContext.HttpContext == null
                || controllerContext.HttpContext.Request == null
                || controllerContext.HttpContext.Request.Browser == null
                || viewLocationsToSearch == null
                || viewLocationsToSearch.Length == 0
                || mobileViewLocations == null
                || mobileViewLocations.ToList().Count == 0
                || !controllerContext.HttpContext.Request.Browser.IsMobileDevice)
            {
                return viewLocationsToSearch;
            }

            var mobileViews = viewLocationsToSearch.ToList();
            foreach (var view in mobileViewLocations.Reverse())
            {
                mobileViews.Insert(0, view);
            }

            viewLocationsToSearch = mobileViews.ToArray();

            return viewLocationsToSearch;
        }

        private string GetPath(ControllerContext controllerContext, string[] locations, string name,
                               string controllerName, string cacheKeyPrefix, bool useCache,
                               out List<string> searchedLocations)
        {
            searchedLocations = EmptyLocations;
            if (string.IsNullOrEmpty(name))
            {
                return string.Empty;
            }
            if ((locations == null) || (locations.Length == 0))
            {
                throw new InvalidOperationException("Property cannot be null or empty.");
            }
            bool flag = IsSpecificPath(name);
            string key = CreateCacheKey(cacheKeyPrefix, name, flag ? string.Empty : controllerName);
            if (useCache)
            {
                string viewLocation = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, key);
                if (viewLocation != null)
                {
                    return viewLocation;
                }
            }
            if (!flag)
            {
                return GetPathFromGeneralName(controllerContext, locations, name, controllerName, key,ref searchedLocations);
            }
            return GetPathFromSpecificName(controllerContext, name, key, ref searchedLocations);
        }
        private static bool IsSpecificPath(string name)
        {
            char ch = name[0];
            if (ch != ‘~’)
            {
                return (ch == ‘/’);
            }
            return true;
        }

        private string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey,
                                               ref List<string> searchedLocations)
        {
            string virtualPath = name;
            if (!FileExists(controllerContext, name))
            {
                virtualPath = string.Empty;
                searchedLocations = new List<string> {name};
            }
            ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath);
            return virtualPath;
        }

        private string GetPathFromGeneralName(ControllerContext controllerContext, string[] locations, string name,
                                              string controllerName, string cacheKey, ref List<string> searchedLocations)
        {
            string virtualPath = string.Empty;
            searchedLocations = new List<string>();
            for (int i = 0; i < locations.Length; i++)
            {
                string str2 = string.Format(CultureInfo.InvariantCulture, locations[i],
                                            new object[] {name, controllerName});
                if (FileExists(controllerContext, str2))
                {
                    searchedLocations = EmptyLocations;
                    virtualPath = str2;
                    ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath);
                    return virtualPath;
                }
                searchedLocations[i] = str2;
            }
            return virtualPath;
        }

        private string CreateCacheKey(string prefix, string name, string controllerName)
        {
            return String.Format(CultureInfo.InvariantCulture, CacheKeyFormat,
                                 GetType().AssemblyQualifiedName, prefix, name, controllerName);
        }
    }
}

 

The Wiring

Now you have your view engine, you need to register it as the default view engine in your MVC application.  Easy!  Open up your Global.aspx.cs file and add the following to ApplicationStart

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new SwitchingViewEngine());

Done!

Now you need to actually add the browser detection file to your application.  Presuming you downloaded the latest archive from the codeplex url at the top of this article, all you need to do is copy the supplied mobile.browser file to App_Browsers/Device/* in your MVC application.

That’s all the wiring you need to get everything up and running.

If you’ve done it right, a default “New MVC Template” project with these additions might look something like this:

image

For the sake of this demo, I put the view engine in a “DemoCode” sub-namespace. You don’t want to do that, put it somewhere sensible!

The more astute reader might now notice that my Views/Home directory in the above screenshot has an extra file, not supplied by the template, called “Index.mobile.aspx”.  Likewise, my /Views/Shared directory has Site.mobile.Master.  These are files I want the view engine to resolve if a user hits the http://localhost/Home default route from a mobile device.

Index.mobile.aspx looks like this:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.mobile.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
    Mobile Home Page
</asp:Content>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
    <h2><%= Html.Encode(ViewData["Message"]) %></h2>
    This is my mobile index page.
</asp:Content>

and Site.mobile.Master looks like this:

<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
</head>

<body>
    <div class="page">

        <div id="header">
            <div id="title">
                <h1>My MVC Application - mobile master page</h1>
            </div>
            <div id="logindisplay">
                <% Html.RenderPartial("LogOnUserControl"); %>
            </div>
            <div id="menucontainer">
                <ul id="menu">             
                    <li><%= Html.ActionLink("Home", "Index", "Home")%></li>
                    <li><%= Html.ActionLink("About", "About", "Home")%></li>
                </ul>
            </div>
        </div>

        <div id="main">
            <asp:ContentPlaceHolder ID="MainContent" runat="server" />

            <div id="footer">
            </div>
        </div>
    </div>
</body>
</html>

Nothing especially revolutionary.

 

Testing

First, install that FireFox plugin I mentioned at the top of the article, create a new MVC project (just use the template), and wire up the view engine and browser file.  Add some extra views with the .mobile.aspx prefix.  Or download the sample attached to the bottom of this post!

Start the site up in Cassini (Visual Studios default web server) and hit /Home.  You should see this:

image

Now, lets use the new FireFox plugin…

image

Select iPhone 3.0 from that menu and refresh the page…

image

Bang!  The more eagle eye reader might have notice that all I did in my “mobile” master page, was delete the CSS reference from the default MVC template, thus the above screenshot.

And that’s it.

 

Further Thoughts

This solution goes quite a way, but here are a few other ideas:

  • Don’t just do browser type detection, detect and switch on subdomain, so any visitors hitting http://m.mysite.com get a different view.
  • Allow the user to opt-out of the reduced view with a session cookie.
  • Switch views to a low-fi version to victimise IE6 users!
  • Target tablet PCs based on resolution to build a “touch UI”

It’s all pretty simple.  The really nice thing about this solution is that your designers can just add these mobile views as and when they see fit, as the same action methods that execute for the “full fat” website are run, and the same strongly typed view models (which you’re using, right? get out of here with your ViewData..) are delivered.  Designers can implement portable websites, piece by piece, just with a little view engine change.

As with all internet code, your mileage may vary, but this technique works for me.

You can download a working VS2008 solution (so long as you have ASP.NET MVC1 installed on your system) containing all the code used above from: http://github.com/davidwhitney/MultipleViewMvcExample

Automatic Html Encoding in ASP.NET 4.0

April 13th, 2010

I spent today at Microsofts Techdays Visual Studio 2010 launch event in London.  Lots of interesting stuff, covered in depth all over the internet (just Google, or bing, if you’re a sadist “changes from .NET 3.5 to .NET 4.0″).  A tiny thing that caught my attention for it’s pure utility to the masses is a new operator in ASP.NET 4.0 that deals with Html Encoding of data implicity.

You’ll likely be familiar (especially if you’re working with ASP.NET MVC) with the <%= notation for referencing properties in the context of the ASP page.  In ASP.NET 4.0 this has been joined by <%: This addition automagically HtmlEncodes any content between the opening and closing tags to prevent repetitive tag soup of <%=HttpUtility.HtmlEncode(myProperty)%> all over your views, and removes the temptation to push HtmlEncoding into your Controller or Model, two places where encoding really shouldn’t be a concern.

Just struck me as a nice little change that’ll make everyday life that little bit easier for a majority of web developers. Sure it’s not quite the new Xaml designer (which is a work of beauty) or Intellitrace (which looked like a total game changer for retrospective debugging), but you know, it’s the little things that count.

C# Access Modifiers Are Type Specific, NOT Instance Specific

February 17th, 2010

Here’s an interesting example from a brief discussion I was having on twitter yesterday with @DotNetWill.

Did you realize that access modifiers in .NET are type specific rather than instance specific. It’s not a weird edge case, it is exactly how the language spec lays it out, but it’s not how most people think access modifiers work. This is because it’s not very often that any given type will have a reference to ANOTHER instance of that type, it just tends to not come up.

Either way, could make for some hilariously difficult debugging if you weren’t aware of it and something was “playing with your privates” by reference.

You might have seen this kind of usage in a singlet*on, constructor or builder class (or as @jagregory pointed out, cloning methods), but generally it’s just not a very common usage example. However, it WILL both compile and execute.

// Example of access modifiers being specific to a type not an instance
public class MyType
{
     private MyType _innerMyType;

     public MyType()
     {
     }

     public void MakeInnerMyType()
     {
          _innerMyType = new MyType();
          _innerMyType._innerMyType = new MyType();
     }
}

Nothing ground breaking, but a fun and interesting little example illustrating a common misconception.

ASP.NET MVC View Engine That Supports View Path Inheritance

January 19th, 2010

I was working on a small MVC project where we were dealing with Inherited controllers (SomeController was inherited by SomeMoreSpecificController) and we decided that it’d be nice to have a similar hierarchy of sharing and inheritance at the View level.

Unfortunately, out of the box, ASP.net MVC looks in two default locations for your views and partials by convention.  The first is /Views/ControllerName/ViewName.aspx, the second is /Views/Shared/ViewName.aspx.  We wanted to allow SomeController to have it’s own set of more generic views, that could later be overridden in special cases by the views provided by SomeMoreSpecificController.

In order to do this in ASP.net MVC, you need to override the default view engine to change the location that the runtime looks for your views.

“Here’s one I made earlier”.

Using this ViewEngine, if you call an action method on SomeMoreSpecificController it’ll first check /Views/SomeMoreSpecificController/…, then /Views/SomeController/… (the base class), then finally /Views/Shared, allowing you a little more control over the organisation of your views.

using System.Collections.Generic;
using System.Web.Mvc;
using System;
using System.Globalization;
using System.Linq;

namespace MyMvc.Mvc
{

    public class InheranceViewEngine : WebFormViewEngine
    {
        private const string CacheKeyFormat = ":ViewCacheEntry:{0}:{1}:{2}:{3}:";
        private const string CacheKeyPrefixMaster = "Master";
        private const string CacheKeyPrefixView = "View";
        private static readonly List<string> EmptyLocations= new List<string>();

        public InheranceViewEngine()
        {
            ViewLocationFormats = new[]
                                  {
                                      "~/Views/{1}/{0}.aspx", "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.aspx",
                                      "~/Views/Shared/{0}.ascx"
                                  };
        }

        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (String.IsNullOrEmpty(viewName))
            {
                throw new ArgumentException("viewName");
            }

            List<string> viewLocationsSearched;
            List<string> masterLocationsSearched;

            string controllerName = controllerContext.RouteData.GetRequiredString("controller");
            string viewPath = GetPath(controllerContext, ViewLocationFormats, viewName, controllerName, CacheKeyPrefixView, useCache, out viewLocationsSearched);
            string masterPath = GetPath(controllerContext, MasterLocationFormats, masterName, controllerName, CacheKeyPrefixMaster, useCache, out masterLocationsSearched);

            if (String.IsNullOrEmpty(viewPath) || (String.IsNullOrEmpty(masterPath) && !String.IsNullOrEmpty(masterName)))
            {
                return new ViewEngineResult(viewLocationsSearched.Union(masterLocationsSearched));
            }

            return new ViewEngineResult(CreateView(controllerContext, viewPath, masterPath), this);
        }

        public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            List<string> strArray;
            if (controllerContext == null) { throw new ArgumentNullException("controllerContext"); }
            if (string.IsNullOrEmpty(partialViewName)) { throw new ArgumentException("Partial View Name is null or empty.", "partialViewName"); }
            string requiredString = controllerContext.RouteData.GetRequiredString("controller");
            string str2 = GetPath(controllerContext, PartialViewLocationFormats, partialViewName, requiredString, "Partial", useCache, out strArray);
            if (string.IsNullOrEmpty(str2))
            {
                return new ViewEngineResult(strArray);
            }

            return new ViewEngineResult(CreatePartialView(controllerContext, str2), this);
        }

        private string GetPath(ControllerContext controllerContext, string[] locations, string name, string controllerName, string cacheKeyPrefix, bool useCache, out List<string> searchedLocations)
        {
            searchedLocations = EmptyLocations;

            if (String.IsNullOrEmpty(name))
            {
                return String.Empty;
            }

            if (locations == null || locations.Length == 0)
            {
                throw new InvalidOperationException();
            }

            bool nameRepresentsPath = IsSpecificPath(name);
            string cacheKey = CreateCacheKey(cacheKeyPrefix, name, (nameRepresentsPath) ? String.Empty : controllerName);

            if (useCache)
            {
                string result = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, cacheKey);

                if (result != null)
                {
                    return result;
                }
            }

            if (nameRepresentsPath)
            {
                return GetPathFromSpecificName(controllerContext, name, cacheKey, ref searchedLocations);
            }
            return GetPathFromGeneralName(controllerContext, locations, name, controllerName, cacheKey, ref searchedLocations);
        }

        private string GetPathFromGeneralName(ControllerContext controllerContext, string[] locations, string name, string controllerName, string cacheKey, ref List<string> searchedLocations)
        {
            string result = String.Empty;
            searchedLocations = new List<string>();

            for (int i = 0; i < locations.Length; i++)
            {
                string virtualPath = String.Format(CultureInfo.InvariantCulture, locations[i], name, controllerName);
                if (FileExists(controllerContext, virtualPath))
                {
                    searchedLocations = EmptyLocations;
                    result = virtualPath;
                    ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result);
                    return result;
                }
                searchedLocations.Add(virtualPath);
            }

            return GetPathFromGeneralNameOfBaseTypes(controllerContext.Controller.GetType(), locations, name, controllerContext, cacheKey, result, ref searchedLocations);
        }

        private string GetPathFromGeneralNameOfBaseTypes(Type descendantType, string[] locations, string name, ControllerContext controllerContext, string cacheKey, string result, ref List<string> searchedLocations)
        {
            Type baseControllerType = descendantType;
            if (baseControllerType == null
                || !baseControllerType.Name.Contains("Controller")
                || baseControllerType.Name == "Controller")
            {
                return result;
            }

            for (int i = 0;i < locations.Length;i++)
            {
                string baseControllerName = baseControllerType.Name.Replace("Controller", "");
                string virtualPath = String.Format(CultureInfo.InvariantCulture, locations[i], name, baseControllerName);

                if (!string.IsNullOrEmpty(virtualPath) &&
                    FileExists(controllerContext, virtualPath))
                {
                    searchedLocations = EmptyLocations;
                    result = virtualPath;
                    ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result);
                    return result;
                }

                searchedLocations.Add(virtualPath);
            }

            return GetPathFromGeneralNameOfBaseTypes(baseControllerType.BaseType, locations, name, controllerContext,
                                                     cacheKey, result, ref searchedLocations);
        }

        private string CreateCacheKey(string prefix, string name, string controllerName)
        {
            return String.Format(CultureInfo.InvariantCulture, CacheKeyFormat,
                                 GetType().AssemblyQualifiedName, prefix, name, controllerName);
        }

        private string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey, ref List<string> searchedLocations)
        {
            string result = name;

            if (!FileExists(controllerContext, name))
            {
                result = String.Empty;
                searchedLocations = new List<string>{ name };
            }

            ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, result);
            return result;
        }

        private static bool IsSpecificPath(string name)
        {
            char c = name[0];
            return (c == ‘~’ || c == ‘/’);
        }

    }
}

Writing Presentable Code Pt.1 – Properties and Variables

November 4th, 2009

At work we’re currently discussing coding standards, specifically to synchronise development in two countries and keep the style consistent across the teams.  You know, the usual stuff. 

When people start discussing coding standards, it quickly devolves into a religious debate and honestly, I think a lot of it comes down to personal preference.  Because of that, I’m going to spend a post or two telling your why you’re wrong and why I wouldn’t take your code to dinner however much it offered to put out.  Because clearly my way is the only right way!

Joking aside, I want to go into some detail on how I present and write my code, and hopefully explain why.  It’s all going to be slanted towards (who do I think I’m kidding, it’s going to be in) C# so as ever, your mileage may vary with any advice you extrapolate.  I’m going to start out by showing you some bad examples, attempt to explain why I think they’re bad, and offer my alternative.

Properties and Variables

The way you declare your properties and variables is seemingly insignificant, but if you get it wrong it trashes the readability of your code.  Take this code sample for example:

image

All I’ve done in the above screenshot is declare a few properties, a few instance variables and a constructor.  And it looks awful and un-maintainable despite the lack of any significant code smell, all due to the manner in which I’ve declared the variables.  It’s a laundry list of mistakes.

  1. Using field backed properties when an auto-property will suffice.
  2. Defining auto-properties split across multiple lines for no explicable reason.
  3. Adding utterly redundant code comments (the code-criticism comments aside).
  4. Terrible and ambiguous variable naming.
  5. Variable names that contain hints at data types.

The above code sample is practically unreadable, even without the comments, it’s long winded and obtuse:

image

Now, I come from the school of thinking that is pretty much convinced that typing things is bad, repeating yourself is bad, hell, writing code is bad.  So don’t.  Less really is more, pick your favourite buzz phrase.  Cleaning up your code should involve making it as simple and as clear as is humanly possible.

Thankfully, if you take advantage of the language features of C#3, you can quickly make something like that look like this:

image

Just by tidying up the way you declare and use your variables, you can make your code eminently more readable.  If you compare the two examples, you’ll see that all I’ve done is

Use single line declarations for auto-properties.

  • Why waste 3-5 lines on an auto-property that can easily fit one one without any loss in readability.

Removed data backed properties in exchange for auto-properties with access modifiers on the setter.

  • Functionally equivalent and far neater

Renamed badly named properties (in the first example “FLineOfAddress”) to be more meaningful.

  • Remove abbreviations where possible, they damage readability
  • Assume the maintainer of your code has no business knowledge, make things easy
  • Meaning is always better in variable names than in comments / meta-data
  • Don’t fear long variable names, modern IDEs have auto-complete, you don’t have to type that stuff by hand.  Embrace your tooling!
  • If you can’t tell what’s in your property or variable from it’s name, you’ve failed, go back and try again.
    • This honestly includes stuff like foreach(var item in MyCollection) and StringBuilder sb = new StringBuilder();  Both bad and wrong, don’t do it.

Only retained comments where the comment data is truly meaningful. 

  • The above example isn’t particularly good (everyone knows what a URL is), but only keep comments in your code where they add something that you couldn’t attain with careful renaming and code restructuring / refactoring.  The meaning of your code should be obvious to the reader without metadata.

Stick to a solid naming convention for public / private / protected variables and properties.

  • The well trodden convention I’m following above is lowerCamelCase plus…
    • A leading underscore for private instance variables (determining scope)
    • Regular lowerCamelCase for local variables
    • UpperCamelCase for property names, constants and statics.
    • No data types in your variable names.  This is not 1980. The IDE gives you all that lovely meta-data, don’t give yourself RSI duplicating it in your variable names.

Cleaning up usage

  • Removing this., you get the same scoping from using _ by convention in your variable names, save those fingers from RSI…
  • Using instance and local variables instantly becomes clearer by sticking to convention.

Using var to reduce duplication in code.

This is often controversial but I feel that using var, for the most part, reduces the amount of typing required without any loss of clarity.  Take the following examples:

image
It’s clear to me that no clarity is lost by not typing "StringBuilder” twice.  It’s still right there in front of you and allows you to keep your variable declarations more uniform.  Despite popular misconception this doesn’t affect the type safety of C#, the language and your variable are still strongly typed, the compiler just infers that when you said var you meant StringBuilder at compile time.   If it isn’t really obvious what an object is when you instantiate it, you’re probably doing something really wrong elsewhere.

People occasionally like to argue that while for declarations var is all well and good, when you’re using it for return values it causes a loss of clarity.  It’s an interesting point but always feels slightly off the mark to me.  Whenever people attempt to give me an example of this lack of clarity, it’s always that their variables or properties are ambiguously or inappropriately named, and the code clarity can be regained and even improved by naming the variables involved in a more descriptive way.  Take the following snippet for example:

image
In the first case, I’d agree that using a var called “l” to store the return value of that method would lead to a loss in clarity.  But if you had string l = RetrieveTextLabel(); and then, say, 20 lines down attempted to use a variable called “l” you’d probably deserve a swift kicking for naming something so poorly.  By contrast, var textLabel is exceptionally descriptive.  People also occasionally say that using var in foreach loops causes this ambiguity, but again, if you name your collection appropriately and your yeilded value correctly, it really is never an issue.

Even more importantly, if you get your naming right, var actually helps you quickly refactor your code.  As long as you understand the “meaning” of your variables, the IDE can fill in the blanks with regard to data types, because for the most part, it really doesn’t matter what type of data is actually in that variable when you’re reading the code as long as it’s meaning is a known quantity.  I actually feel that the dynamic language crowd learnt this lesson long ago, and people that work predominantly in strongly typed languages actually tend to rely on the type system like a crutch to excuse terrible naming conventions.  Time to learn from PHP…

    In conclusion…

    To make your code readable you should stick to conventions for naming, always strive to add meaning in variable names and be as brief as possible.  Don’t litter your code with crap and you’ll be thankful for it later.

    Obviously, this is all my opinion, but I swear by it.

    I’ll be following up this post in the next few days with some continued patterns for readable code.

    Reusable Editable Fields for ASP.net MVC Using jQuery

    October 8th, 2009

    A friend recently asked me about editing items inline using ASP.net MVC, the kind of thing that was auto magically wired up with post backs in “old fashioned” asp.net so I’ve whipped up a small example showing how you can use jQuery to declaratively set up interactive field editing with a sprinkling of Ajax and JSON.

    I’m basing this example on the default ASP.net MVC starter project for brevity (download attached) but here’s an overview:

    First you need to set up an Action method (or multiple action methods) on your controller to accept the modification of data.  In my example I’ve added an unimaginative method called “SetField” to the HomeController that looks like this:

    public ActionResult SetField(string fieldName, string fieldValue)
    {
        var response = Json(fieldValue);
        return response;
    }

    As you can see, it doesn’t do very much (useful implementation left to the reader) but it accepts the parameters of a field name, and a field value.  You’ll need to roll your own validation and sanity checking here.  It then returns the fieldValue using the MVC Json helper object, as a Json object.  In a real world example, you’d want to call and update in this method.

    Now, in the view, jQuery does most of the hard work.

    First I added a few CSS classes to the header on the master page (for the sake of example):

    <style type="text/css">
        .editableItem { display: block; }
        .fieldViewer { display: block; }
        .fieldEditor { display: none; }
        .editableItemCancel { display: block; }
        .editableItemBox { display: block; }
    </style>

    I then added an example to the view that looked like this:

    <div class="editableItem" id="editable_FieldName">
        <div class="fieldViewer">Click me to edit me!</div>
        <div class="fieldEditor"><input class="editableItemBox" type="text"/><span class="editableItemCancel">cancel</span></div>
    </div>

    With this HTML I set up some conventions that I’ll rely on when using jQuery.  Firstly, every editable item should use the class “editableItem” and have the id “editable_FieldName”.  I use the class in a jQuery selector and the Id to establish which field is being edited.  Inside the editableItem should be a fieldViewer, containing the current data, and a fieldEditor, which is hidden by default, and contains some kind of editable controller and a cancel button.  You could insert these elements at runtime if you wished, but in order to keep the example simple I’ve declared them in the HTML.

    Next I added some jQuery… The jQuery defines some Javascript behaviour associated with the classes used in the HTML, this way, the mark-up can be reused to edit multiple fields rather than being keyed to the Id of a specific field.

    <script src="/Scripts/jquery-1.3.2.js" type="text/javascript"></script>
    <script type="text/javascript">
        jQuery(document).ready(function() {

            $(".editableItem .fieldViewer").click(function() {
                var parentId = $(this).parent().attr("id");
                $(’#’ + parentId + " .fieldEditor .editableItemBox").val($(’#’ + parentId + " .fieldViewer").text());
                $(’#’ + parentId + " .fieldViewer").toggle();
                $(’#’ + parentId + " .fieldEditor").toggle();
            });

            $(".editableItem .fieldEditor .editableItemCancel").click(function() {
                var parentId = $(this).parent().parent().attr("id");
                $(’#’ + parentId + " .fieldViewer").toggle();
                $(’#’ + parentId + " .fieldEditor").toggle();
            });

            $(’.editableItem .editableItemBox’).keypress(function(e) {
                if (e.which == 13) {
                    var parentId = $(this).parent().parent().attr("id");
                    var fieldName = parentId.replace(/editable_/, "");

                    $.post(’/Home/SetField’,
                    {
                        fieldName: fieldName, fieldValue: $(’#’ + parentId + " .editableItemBox").val()
                    },
                        function(data) {
                            $(’#’ + parentId + " .fieldViewer").text(eval(’(’ + data + ‘)’));
                            $(’#’ + parentId + " .fieldViewer").toggle();
                            $(’#’ + parentId + " .fieldEditor").toggle();
                        })
                }
            });

        });
    </script>

    Quite simply, if you click the editable field, it toggles into a textbox.  If you hit enter on the textbox, the value is posted to the previously defined Action on the Controller.  If you hit cancel, the display is toggled back.

    I’d not recommend copy and pasting this exact example into a production system, but hopefully it’ll guide you through a simple scenario.  You can use a similar technique to add all sorts of little Ajax tricks (auto-suggest, lookups, dynamic menus) to your ASP.net MVC site using jQuery and Json (both of which are included in the core asp.net MVC framework).

    Download the example solution here

    Creating a WCF Proxy to talk to Magento

    October 5th, 2009

    I got a message from a friend who was struggling to do an integration piece with the Magento eCommerce Platform using the SOAP endpoint available at http://yourserver.co.uk/api/v2_soap?wsdl.

    He brought an interesting problem to me, namely that the WCF svcutil executable (and built in Visual Studio 2008) was failing to generate any proxy code when supplied with a seemingly valid wsdl.

    I did a quick test and managed to instantly reproduce the error.

    Weirder still, when using the “old” .Net 2.0 add web reference method rather than the .Net 3.0+ “Add Service Reference”, the framework managed to create a non-WCF reference just fine.

    Dropping down to the command line I saw some unusual messages being displayed by svcutil.exe:

    c:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin>SvcUtil.exe http://yourserver.co.uk/api/v2_soap?wsdl
    Attempting to download metadata from ‘http://yourserver.co.uk/api/v2_soap?wsdl’ using WS-Metadata Exchange or DISCO.

    (Lots of error messages here…)

    Error: Cannot import wsdl:portType
    Detail: An exception was thrown while running a WSDL import extension: System.Se
    rviceModel.Description.XmlSerializerMessageContractImporter
    Error: The ‘ ‘ character, hexadecimal value 0×20, cannot be included in a name.
    Parameter name: name
    XPath to Error Source: //wsdl:definitions[@targetNamespace='urn:Magento']/wsdl:p
    ortType[@name='Mage_Api_Model_Server_V2_HandlerPortType']

    Error: Cannot import wsdl:binding
    Detail: There was an error importing a wsdl:portType that the wsdl:binding is de
    pendent on.
    XPath to wsdl:portType: //wsdl:definitions[@targetNamespace='urn:Magento']/wsdl:
    portType[@name='Mage_Api_Model_Server_V2_HandlerPortType']
    XPath to Error Source: //wsdl:definitions[@targetNamespace='urn:Magento']/wsdl:b
    inding[@name='Mage_Api_Model_Server_V2_HandlerBinding']

    Error: Cannot import wsdl:port
    Detail: There was an error importing a wsdl:binding that the wsdl:port is depend
    ent on.
    XPath to wsdl:binding: //wsdl:definitions[@targetNamespace='urn:Magento']/wsdl:b
    inding[@name='Mage_Api_Model_Server_V2_HandlerBinding']
    XPath to Error Source: //wsdl:definitions[@targetNamespace='urn:Magento']/wsdl:s
    ervice[@name='MagentoService']/wsdl:port[@name='Mage_Api_Model_Server_V2_Handler
    Port']

    Generating files…
    Warning: No code was generated.
    If you were trying to generate a client, this could be because the metadata docu
    ments did not contain any valid contracts or services
    or because all contracts/services were discovered to exist in /reference assembl
    ies. Verify that you passed all the metadata documents to the tool.

    Warning: If you would like to generate data contracts from schemas make sure to
    use the /dataContractOnly option.

    c:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin>

    So I did a little digging through the WSDL and found an undocumented bug in Magneto’s schema.

    First I saved a local copy of the WSDL and used visual studio to reformat the document into some sort of readable state, then I had to make a few corrections to the WSDL to allow SvcUtil to correctly parse the malformed document.

    Change 1:  Replace a badly encoded apostrophe – I removed the “’s” from the following operation definition…

    <operation name="customerGroupList">
    <documentation>Retrieve customer’s groups</documentation>
    <input message="typens:customerGroupListRequest"/>
    <output message="typens:customerGroupListResponse"/>
    </operation>

    Change 2: Replace a trailing space in an operation name

    <message name="catalogProductGetSpecialPriceRequest">
      <part name="sessionId" type="xsd:string"></part>
      <part name="product" type="xsd:string"></part>
      <part name="storeView " type="xsd:string"></part>
    </message>

    If you look carefully at the above message definition, you’ll notice that name=”storeView “ contains a space, making the wsdl invalid.  Remove the space so it reads “storeView”.

    With these two errors corrected, SvcUtil had no problem generating an appropriate WCF proxy from the corrected wsdl file.

    Magneto will hopefully fix this error in the WSDL, but until this time, it’s probably quite safe to follow these steps to generate your own proxy.

    To reproduce:

    • Go to http://yourserver.co.uk/api/v2_soap?wsdl and save the contents of your file to the local disk (c:\test\main.wsdl)
    • Open the file in visual studio, and reformat the document for readability (CTRL+K, CTRL+D).
    • Remove the apostrophe from the documentation tag for the customerGroupList operation.
    • Remove the space after the name=”storeView “ in the catalogProductGetSpecialPriceRequest message definition.
    • Open a command prompt and enter
    • c:\test>c:\Program Files\Microsoft SDKs\Windows\v6.0A\Bin\svcutil.exe main.wsdl
    • SvcUtil will produce two files, Magento.cs (your WCF proxy) and output.config, your endpoint configuration.

    Designing Client Facing APIs – Best Practices

    September 30th, 2009

    With the popularity of service oriented architectures and other buzz phrases related to software as service, good API design has become a significant selling point for any software platform in the past 5-10 years.  People make purchasing decisions based on how easy it is to interoperate with your applications and code and as such the number of client / public facing APIs attached to software has skyrocketed.  I’d like to believe the days of dropping strategic text files in directories to trigger some action or another in an application are behind us.

    In this article I’m going to talk about the following things

    • Why you should choose your method names carefully, and what to call
    • Why pretending to be a data access layer is a terrible thing for an API to do
    • Talk about the dangers of leaky abstractions in an API
    • Explain the benefits of creating a data contract between you and the calling code
    • Explain why it’s vital to support standards
    • Make sure that your users can retrieve values they’re going to want to modify
    • Suggest supplying compiled libraries alongside your API documentation
    • Explain why it’s important to keep your API implementation clean
    • Talk about the benefits of dogfooding your API
    • Consider supporting atomic operations including rollbacks on failure
    • Discuss bulk operations
    • Try and convince you that both logging and security should be first class citizens
    • Beg you to maintain integration tests and most of all to keep it simple!

    Your API Sucks

    You’ve probably used an API and there’s a good chance you’ve had to write one.  This probably won’t surprise you; most APIs suck.  They’re horrible to use and built around illogical leaky abstractions that leave you flicking through huge wads of documentation just to make the most rudimentary feature work.

    About 18 months ago, after a year of struggling with a broken third party API that almost brought a business to it’s knees by placing significant roadblocks in front of in house development, I was part of a team tasked with designing our own client facing API.  With no desire to expose other developers to the cruel and unusual punishments of software design we’d had to endure, we came to the conclusion that it was really important that we god this piece of the system right.  People say first impressions are everything, and your API design can make or break the faith other developers have in your ability to produce software.  Show somebody a shitty API and they’ll perhaps correctly assume the rest of your code sucks too.

    The Best Man For The Job

    There’s a bit of a trend that I’ve noticed with some of the worst APIs I’ve worked with: they seem to be designed by the wrong people.  The wrong people to design an API are 1) the guy that wrote the internal code to do the job the API is providing access to and 2) the consumer of the API. 

    The guy that wrote the code that the API is calling under the hood will be inherently slanted to implement an API which exposes this functionality and will have a predisposition to creating a leaky abstraction.  This is especially bad for the consumer APIs designed by the internal implementer tend to assume the consumer knows far more than he really does, or has access to internal data that in reality, he doesn’t.

    Conversely, an API designed by the consumer of the API will have a tendency towards solving problems that are not the concern of the API itself.  The consumer will, either accidently or by intention, attempt to offload some of the work that should be the responsibility of the calling code into the API.

    Ideally, the person that’s writing the API will have knowledge of the system internals, but not be the guy that wrote them. A fellow team member with passive experience to the code would be a good person, or ideally, a pair design exercise between the person that originally wrote the code and an API designer, with the consumer as a consultant.

    Speaking The Same Language

    Like a lot of software development, you make good progress when you get your terminology right and understand exactly what you’re trying to produce.  I’ve consistently found that the best way to think of a client facing API is as a orchestrating thin wrapper that summarises, in code, a set of business processes that you wish to expose to the public.

    In order to get your API design right, you need to clearly define and agree on the boundaries of the system with both your internal team, and your consumers.  It’s important that you have a clear understanding of the following:

    • The responsibility of the calling code
    • The responsibility of the API layer
    • The responsibility of the internal code the API makes calls to

    This might sound like a really simple suggestion but I’ve taken part in countless discussions where people on both sides of the API just “presumed” that either the calling code or the API would perform specific functions (data cleansing, logging etc) when in fact, this confusion had lead to none of the implementers bothering to write the required functionality.  Make sure you know for certain what your API is responsible for doing.

    Defining Your API – Tips and Tricks

    Defining your API methods (or the “contract” of the API) is the most important thing to get right and there are several vital things to remember.

    • Choose Your Names Wisely Using the language of the business

      It’s vital that your API methods speak in terms that the caller is going to understand.  Your API should be readable.  If your users go hunting for the documentation every time they want to use a method, then you’re probably doing it wrong.

      Clarity in naming is exceptionally important.  The names of your API methods should succinctly state what action that method call is going to perform.  Don’t fear using long method names, embrace them for clarity.  As a general rule, your pmethods should probably always be in the form DoSomething(object withThis);

      Ensure that when naming methods you reflect business operations in the method names, not the underlying implementation.

      Bad example:     void InsertToTblCustomer(string[] custDataValues);
      Good example:   void AddCustomer(Customer customer);
      Good example:   void DisableAccount(string accountId); 

    • Don’t pretend to be a data access layer

      APIs should summarise business operations in a logical and meaningful fashion.  You are not a public facing data access layer and you should never pretend to be.  If your users want raw database access give them read only permissions on some tables and a copy of SQL Management Studio.  So don’t write methods for CRUD operations in your API (unless you’re writing some kind of online file management utility).

      Bad example:     void InsertToTblCustomer(string[] custDataValues);
      Bad example:     void UpdateTblCustomer(string[] custDataValues);
      There are no good examples!

    • Avoid leaky abstractions

      This is a fundamental and simple rule – don’t expose your callers to anything that they’re not interested in or won’t understand.  If it’s not important, don’t show it.  Don’t code for things nobody will ever need and don’t require your callers to have intimate knowledge of data types or internal categories in your system.

    • Create a data contract between you and the calling code

      I’m going to borrow some of the terminology from WCF here because I’ve found it an appropriate label.  Create a Data Contract library for use in your API.  This library should summarise the business process and the outward facing view of your software.  It might contain terminology that doesn’t actually exist in the software itself, but in the business processes that the software models.  Either way, this, and only this, should be the language that the API talks to your callers.

      Where possible, create this data contract in a separate assembly that’s entirely decoupled from your core system and distribute it to people that want to use your API.  This is especially beneficial when using WCF as your clients can generate a service proxy and deal in the same data types that you are in your API code.

      It should be the responsibility of the API layer to marshal the data from your data contract into the domain model of your internal components.

      You data contract should contain every type used to communicate with your API and the object model should be named in a way which is meaningful for the consumers.

      Because your data contract is NOT the object model of your internal components, you’re able to add properties and objects that don’t logically exist in your internal components.  This means that you can perform an operation using some internal component, gather the output in your API layer and then compose the output data in a meaningful way using classes written specifically for the data contract.  This way, by the time the user has access to the output data, it’s in a format and language which they understand.

    • Support standards!  Don’t reinvent the wheel!

      Here’s a true story; while working with an API, my team was faced with the following API method:
      object Run(string request);

      It was the only method on the API, and “covered up” for around 30 methods all made available through one giant black hole in the side of the system.  Underneath that there was an XML format that the request had to be in in order to call the appropriate method.

      If you’re writing an API, stick to some kind of standards.  Ideally, expose a web service endpoint with an accurate WSDL that people can call or use a simple and obvious REST endpoint.  

      Please, please, please, do not make other developer suffer by rolling your own delivery mechanism.  We have enough of them, don’t confuse people by adding some more.  If you’re going to use a raw sockets connection, supply a calling library and stick to some standard middleware like WCF rather than rolling your own. 

      Thousands of people have spent thousands of man years writing code based on existing techniques, you’re not better than all of them combined.

      Reinventing the wheel is never good for anyone.

    • Ensure that the user can retrieve values they’re going to want to modify

      The number of times I’ve used APIs that let me set or update objects without returning the current state of the object is mind blowing.  So always remember: If you’re going to let them set it, let them get it.  Providing an update or “upsert” method without allowing your consumers to query the current state of data in the system is a complete waste of time.

    • Supply compiled libraries to work with your API documentation

      This may not always be possible, but it’s a really good idea to supply a sample implementation and compiled binaries with your API that covers the most common scenarios of usage.  Not only does this prevent the consumer from struggling to get to grips with you API, but it allows you to outline and illustrate a set of best practices for usage.  In an ideal world, the user could just use your sample code in their application, so ensure you license the code appropriately.

      This is an exceptionally good way to deal with any authentication your API may require as you have the ability to provide additional helper classes to perform some common tasks (authenticate –> perform action –> logout, for example).

    • Keep your implementation clean

      Delegate the API logic to your middleware components / reusable libraries.  Do your best to ensure the API layer doesn’t actually contain the logic required to perform operations, just the logic required to marshal the data from the API format into your internal data structures.  The API should simply orchestrate calls to one or more internal methods because your API should simply be exposing existing functionality.

      If the API is exposing some new, API specific functionality, consider splitting this behaviour into a separate assembly or binary to aid testability.

    • Consider dogfooding

      Dogfooding is the act of using the software you’re creating.  I worked on a project where we were developing an order placement system in ASP.net MVC, and as part of the design process we decided that we wanted to have an API that was a first class citizen.  It then dawned on us that in order to produce the API in a way that accurately mirrored the functionality of the website, we should have the website consume the API like any other client would.  The website had it’s own concept of user authentication, and when a user logged in, the web application logged in to the API as the current user.

      Doing this not only ensured that our security model was watertight, but that any additional web functionality would immediately be available to API users because they were actually the same thing.  On top of that, you gain confidence in your own API because you know that it’s called often by your own code, reducing the likelihood of users discovering bugs in your API because it’s not a product you actually use.

    • Support atomic operations including rollbacks on failure

      When implementing your API methods, ensure that if an exception occurs or an operation doesn’t complete, the all the changes made by your API call are reversed.  Consider explicitly supporting transaction scopes in your API to let your consumers compose their own “set” of operations.

    • Support bulk operations where appropriate

      Building support for bulk operations into your API can often prevent performance issues occurring later when a user tries to, for example, insert 10,000 customers sequentially.  Consider pluralising your methods, so instead of providing an AddCustomer(Customer customer) method, provide only a AddCustomers(List<Customer> customers); method.  Doing this prevents callers from overloading your system by bulking data through your API in unintended ways, allowing you to properly cache required data and cater for these bulk operations.

      This isn’t always appropriate, however I’d always strongly suggest offering pluralised versions of methods that you suspect may be used in bulk, in order to help optimise your API calls and reduce the amount of data being transferred over the wire.

    • Logging as a first class citizen

      Don’t wait until somebody asks about API usage to decide to log it.  Build logging into your API wrapper, from the start, at the point of every method call.  It doesn’t need to be fancy, and you can use a number of freely available components to handle these logs and log rotation (consider using log4net or log4j for simple log rotation).

      Log each method call and some summary or identifiable element of the data passed to it.  This’ll help you profile API usage, and identify how data changed in your previously closed system.

    • Security as a first class citizen

      Consider the security of your API from the start of the project.  Understand who will have access to your API, which organisations and which individuals.  Do you require roll based security?  Do you need a way to disable API support for specific customers?  Are you transferring data that needs to be encrypted over the wire?

      Beware of over baking your security.  WS-* offers some very robust packet level security features, but if your API doesn’t need them, or is restricted to an internal network, then don’t bog down your implementation in unneeded security.  Beware of making security choices that tie you down to a specific protocol or technology stack – you want to keep your API usable for the consumers.  Do the simplest thing that works.

    • Have integration tests!

      Make sure you have integration tests with mocking at the business logic layer. These tests are for your API wrappers, NOT your logic. The logic should be tested independently, you’re just ensuring your API layer, marshalling and method calls operate correctly at this level.

      With any luck, your business logic should already be tested as part of your existing test suite (which you have right?) but if not, ensure the business logic is tested separate from the API code.

      Consider using a TDD or BDD approach to designing your API calls, designing the specification first in the form of some calling code, then write the code required to make your usage examples compile.  This will help you understand exactly what calls the client will have to make for to your API to achieve specific functionality.  These tests can happily double up as regression tests when you make changes to the API.

    • Keep it simple!  If all else fails, do what the big boys do.

      Always strive to keep your API simple.  Pretend your the consumer at all times.  If you’re unsure of how to proceed, I’ve always found inspiration, both for what to do and what not to do, from reading the API documentation of some large companies that have widely used APIs.  It’s safe to say that the likes of Amazon, Google and Microsoft have had to put some thought into their API designs.  Beware of trusting their decisions blindly, but liberally borrow anything you, as a consumer, would find pleasing in your API.

    I’m not going to try and convince you that by following my advice that your API design will be flawless.  I’m really hoping for a little discussion on this topic as it seems like something that is rarely covered and often “felt out” by the people left to implement APIs for the public.  These are just some lessons I’ve learnt on the way while implementing several public facing APIs.

    Want to talk about APIs?  Send me an email!

    Localizing ASP.Net MVC Pages without the need to RunAt=”server”

    August 20th, 2009

    A common complaint when faced with localizing ASP.net MVC pages is that littering your code with tonnes of runat=”server” tags breaks the “purity” of the MVC model.  Regardless of how meaningful that debate is, there is a way to achieve globalisation without server controls.

    I’m going to walk you through a sample implementation which should hopefully make this clearer.  As a standard disclaimer, none of this code has been tested in a production environment and I wouldn’t advise implementing it blindly.

    I’m going to attempt to play this out mostly in screenshots…

    The Idea

    • The required language is stored in a database / session / extrapolated from the Url route information
    • Your view pages derive from the type TranslatableViewPage
    • This page adds support for a LanguageCode property that you can make use of inside the view along with adding a class implementing ITranslator, a class that provides hooks into a translation database.
  1. Your controller derives from the type TranslatableController.
    • This controller add a method called ViewInLanguage(string languageCode) that you use instead of View() or View(model) to return your Asp.net MVC view.
  2. At application start up in the Global.asmx file, you register a default language code for failure conditions, and specify the implementation of ITranslator you wish to use to acquire localized strings.
  3. If your TranslatableViewPage when rendering your output, you simple need to use the embedded <%=Translator.Translate(propertyName) %> method call to load a translated string while the page output is rendering.
  4. Class Layout

    The following is built upon the standard Asp.net MVC starter project for the sake of illustration.

    image

    Implementation

    First, configure the translation settings and register your translator…

    image

    You need to configure a fail-safe default language code and a type that implements ITranslator.  This translator will be responsible for doing the heavy lifting.  Ideally we’d add some inversion of control here to allow you to define the translator implementation at configuration time, but that’s outside of the scope of this example.  I’ve implemented a very crude resource .resx translator for the example.

    Next, make your controllers inherit from TranslatableController

    image

    Once inherited, switch from using the View(); method to ViewInLanguage() passing in your desired language code (gathered from the user session / database / Url route).

    Then set your view type (or derive your view from) TranslatableViewPage

    image

    Once your view is inheriting from TranslatableViewPage, you’ll have access to an instance of your specified Translator and the LanguageCode inside the view which you can use in a manner similar to the built in HtmlHelper class to access your translated strings.

    How It Works

    The TranslatableController provides you with ViewInLanguage and when called generates the standard MVC ActionResult.  This ActionResult will be a ViewResult, which is then wrapped in a LocalizedViewResult wrapper class adding a LanguageCode.

    When ExecuteResult is called on the LocalizedViewResult to render the view, the LanguageCode is placed in the TempData array in the TranslatableViewPage.  Then, when the OnInit(EventArgs e) method is called on the TranslatableViewPage, this LanguageCode is extracted and placed in the LanguageCode property on the page.  In addition to this the page provides a constructed instance of ITranslator which you can use in your views to source translated data as the page is rendered.

    Source Code

    Download Here

    C# Extension Methods To Get Enum DescriptionAttributes And Other Custom Attributes

    April 23rd, 2009

    A quick code snippet.  These two extension methods (C# 3.0+) enables you to return custom attributes from types, both on a specific type and any data type.  They both return null if the attribute is not present.  

    The first extension is useful for extending a type of your choice.  It’s especially useful when considering Enums and the DescriptionAttribute, or other enumeration attributes (especially custom attributes).  The usage examples below should make the use more obvious.

    The second extension allows you to return an Attribute from ANY type.  Use with caution, but I find it interesting that it’s actually possible to write an extension method that works that way.

        public static class ElementExtensions
        {    

            public static T GetAttributeValue<T>(this SomeConcreteType val)
            {
                var attributes = val.GetType().GetField(val.ToString()).GetCustomAttributes(typeof(T), false);

                T response = default(T);
                if(attributes.Length > 0)
                {
                    response = (T)attributes[0];
                }

                return response;
            }

            public static TReturnType GetAttributeValueFromType<TInstanceType, TReturnType>(this TInstanceType val)
            {
                var attributes = val.GetType().GetField(val.ToString()).GetCustomAttributes(typeof(TReturnType), false);

                TReturnType response = default(TReturnType);
                if(attributes.Length > 0)
                {
                    response = (TReturnType)attributes[0];
                }

                return response;
            }       
        }   

    Some usage examples….

        public enum RegexEnum
        {
            [RandomAttribute("^(([a-zA-Z]{1}[0-9]{3,4})|([a-zA-Z]{2}[0-9]{2,3})|[0-9]{4})$")]
            SomeEnumValue,
        }   

        public class RandomAttribute: Attribute
        {
            public string Expression { get; set; }

            public RandomAttribute(string expression)
            {
                Expression = expression;
            }
        }

        private static void Example()
        {
            // Both of these are equivalent
            foreach(var enumMember in Enum.GetValues(typeof(RegexEnum)))
            {
                var value = enumMember.GetAttributeValue();   
                var valueFromAnyType = enumMember.GetAttributeValueFromType<RegexEnum, RandomAttribute>();
            }       
        }

    Some nice syntactic sugar for use with enumerations.