Session-per-request with Nancy

Session-per-request is a common model for session management (although there are some good arguments against using it!).

There are many ways of implementing it, from Ayende’s base controller to (N)Hibernate’s contextual sessions.

Recently I’ve got into the habit of leaning on the container, and registering a session per-web-request. By default, Nancy uses TinyIoC, which doesn’t support per-web-request registrations (there is an extension available, but it won’t be required).

What Nancy offers instead, is a chance to customise the child container that will be used for the request:

public class Bootstrapper : DefaultNancyBootstrapper
{
    private readonly ISessionFactory sessionFactory;

    public Bootstrapper()
    {
        this.sessionFactory = SessionFactoryFactory.BuildFor("ConnStringName");
    }

    protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
    {
        base.ConfigureRequestContainer(container, context);

        container.Register((c, o) => this.sessionFactory.OpenSession());
    }
}

Which means your module can happily take a dependency on ISession.

Logging unhandled exceptions with Nancy

Normally when developing an ASP.NET application I add fall back logging for any unhandled exceptions in Global.asax.cs:

public class Global : HttpApplication
{
    private ILog _logger;
    
    protected void Application_Start(object sender, EventArgs e)
    {
        XmlConfigurator.Configure();
        _logger = LogManager.GetLogger(typeof(Global));
    }

    protected void Application_Error(object sender, EventArgs e)
    {
        var error = Server.GetLastError();
        _logger.Error("Unhandled error", error);
    }
}

This means any YSODs are logged.

When developing applications with Nancy this no longer works, as Nancy has it’s own error handling pipeline.

The solution is to implement a handler to log any unhandled errors:

public class LoggingErrorHandler : IErrorHandler
{
    private readonly ILog _logger = LogManager.GetLogger(typeof(LoggingErrorHandler));

    public bool HandlesStatusCode(HttpStatusCode statusCode)
    {
        return statusCode == HttpStatusCode.InternalServerError;
    }

    public void Handle(HttpStatusCode statusCode, NancyContext context)
    {
        object errorObject;
        context.Items.TryGetValue(NancyEngine.ERROR_EXCEPTION, out errorObject);
        var error = errorObject as Exception;

        _logger.Error("Unhandled error", error);
    }
}

And, as of 0.10.0, there’s no longer any need to register it. Any IErrorHandler implementations will be picked up, auto-magically.

I want my YSOD back!

I’ve recently been using Nancy to build an API, and have found it a pleasure to work with.

I do have one minor complaint though: it’s cutesy default error page…

Nancy default error page

I understand the motivation, and I can see how it helps with the “super-duper-happy-path”. But, when developing an API in a corporate environment, it’s frankly a bit embarrassing.

I want my YSOD back! The good news is, you can, with a little bit of work.

public class YsodErrorHandler : IErrorHandler
{
    public bool HandlesStatusCode(HttpStatusCode statusCode)
    {
        return statusCode == HttpStatusCode.InternalServerError;
    }

    public void Handle(HttpStatusCode statusCode, NancyContext context)
    {
        object errorObject;
        context.Items.TryGetValue(NancyEngine.ERROR_EXCEPTION, out errorObject);
        var exception = errorObject as Exception;

        if (exception != null)
        {
            throw exception;
        }
    }
}

Et voila!

YSOD

(Caveat: this will only work with 0.10.0, previous versions don’t provide the exception object). The best bit is, you don’t even have to register the error handler, Nancy will scan for it!