In Building Tweets from the Vault: Azure, TeamCity and Octopus, I wrote about the hosting and infrastructure choices I made for Tweets from the Vault. This article will cover a bit more about the framework choices, notably NancyFX.

NancyFX

NancyFX may sound like a bit more of an esoteric choice, especially to the Microsoft-or-die crowd. I’ve been having a pretty fair amount of success with Nancy, however. I love the way that it just gets out of the road and provides a close-to-the-metal experience for the common case but makes it simple to extend behaviour.

By all means, it’s not perfect - I’m not a huge fan of “dynamic, dynamic everywhere” - but it’s way better than MVC for my needs. The upgrade path is a whole lot less troublesome, too - the best advice I’ve found for upgrading between major versions of MVC is to create a new project and copy the old content across.

Application structure

The equivalent of an MVC controller in NancyFX is the module. In a typical MVC controller, there are lots (usually far too many) methods (controller actions) that do different things. While this isn’t strictly a feature of the framework, all the sample code tends to guide people down the path of having lots of methods on an average controller, with a correspondingly large number of dependencies.

In MVC, routing to controller actions is taken care of my convention, defaulting to the controller’s type name and method name. For instance, the /Home/About path would (by default) map to the About() method on the HomeController class.

Nancy routes are wired up a little bit differently. Each module gets to register the routes that it can handle in its constructors, so if I were to want to emulate the above behaviour I’d do something like this:

public class HomeModule : NancyModule
{
    public HomeModule()
    {
        Get["/Home/Index"] = args => /* some implementation here */;
        Get["/Home/About"] = args => /* some implementation here */;
        Get["/Home/Contact"] = args => /* some implementation here */;
    }
}

Obviously, if we want the same Nancy module to handle more than one route then we just wire up additional routes in the module’s constructor and we’re good.

This is nice in a way but it’s also a very easy way to cut yourself and I tend to not be a fan. Not only that, but it still leads us down the path of violating the Single Responsibility Principle in our module.

My preference is to have one action per module and to name and namespace each module according to its route. Thus my application’s filesystem structure would look something like this:

app
    Home
        Index.cs
        About.cs
        Contact.cs

This makes it incredibly easy to navigate around the application and I never have to wonder about which controller/module/HTTP handler is serving a request for a particular path.

My About.cs file would therefore look something like this (for now):

public class About : NancyModule
{
    public About()
    {
        Get["/Home/About"] = args => /* some implementation here */;
    }
}

RoutedModule

One problem with the above approach is that it’s not refactoring-friendly. If I were to change the name of the About class then I’d also need to edit the route registration’s magic string. Magic strings are bad, mmmkay?

A simple approach for the common case (remembering that it’s still easy to manually register additional routes) is to just derive the name of the route from the name and namespace of the module. (Hey, I didn’t say that all of MVC was bad.)

public abstract class RoutedModule : NancyModule
{
    protected RoutedModule()
    {
        var route = Route.For(GetType());
        Get[route, true] = (args, ct) => HandleGet(args, ct);
        Post[route, true] = (args, ct) => HandlePost(args, ct);
    }

    protected virtual async Task<dynamic> HandleGet(dynamic args, CancellationToken ct)
    {
        return (dynamic) View[ViewName];
    }

    protected virtual Task<dynamic> HandlePost(dynamic args, CancellationToken ct)
    {
        throw new NotSupportedException();
    }

    protected virtual string ViewName
    {
        get { return this.ViewName(); }
    }
}

This now allows for our About.cs file to look like this:

public class About : RoutedModule
{
}

Routes

We’re not quite there yet. I’m not a fan of magic strings and in the above example you can see a call to a static Route.For method. That method is where the useful behaviour is, and it looks like this:

public static class Route
{
    private static readonly string _baseNamespace = typeof (Index).Namespace;

    public static string For<TModule>() where TModule : RoutedModule
    {
        return For(typeof (TModule));
    }

    public static string For(Type moduleType)
    {
        var route = moduleType.FullName
                              .Replace(_baseNamespace, string.Empty)
                              .Replace(".", "/")
                              .Replace("//", "/")
                              .ToLowerInvariant();
        return route;
    }

    public static string ViewName(this RoutedModule module)
    {
        // Left as an exercise for the reader :)
    }
}

This allows us to have a completely refactor-friendly route to an individual action. There are a couple of similar routing efforts for MVC, notably in MVC.Contrib and MvcNavigationHelpers, but this lightweight approach doesn’t require building and parsing of expression trees. (It’s worth noting that it doesn’t account for a full route value dictionary, either, but you can add that if you like.)

In our views, our URLs can now be generated like this:

<a class="navbar-brand" href="@(Route.For<Index>())">
    Tweets from the Vault
</a>

and in our modules, like this:

return new RedirectResponse(Route.For<Index>());

A quick ^R^R (Refactor, Rename, for all you ReSharper Luddites) of any of our modules and you can see that we haven’t broken any of our links or redirects.

In the next post in this series, we’ll take a quick look at authenticating with Twitter using OAuth.