Bubbling exceptions in Nancy up the owin pipeline

11 Feb 2014

In the application I am building I have a requirement to do common exception handling within my OWIN pipeline via custom middleware:

private class CustomExceptionMiddleware : OwinMiddleware
{
    public CustomExceptionMiddleware(OwinMiddleware next) : base(next)
    {}

    public override async Task Invoke(IOwinContext context)
    {
        try
        {
            await Next.Invoke(context);
        }
        catch(Exception ex)
        {
            // Custom stuff here
        }
    }
}

Where the startup looked something like this:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app
            .Use<CustomExceptionMiddleware>()
            .UseNancy()
            .UseOtherStuff();
    }
}

The "problem" is that Nancy is very safe by default - it will always try to capture the exception and set the status code to 500, even if you have cleared all the status code handlers from the bootstrapper. Thus, any exceptions thrown in Nancy will never reach the CustomExceptionMiddleware.

Taking the PassThroughStatusCodeHandler found in Nancy.Testing and tweaking the handle method, we can capture the exception and rethrow it using .NET 4.5's ExceptionDispatchInfo:

public class RethrowStatusCodeHandler : IStatusCodeHandler
{
    public bool HandlesStatusCode(Nancy.HttpStatusCode statusCode, NancyContext context)
    {
                // This is unchanged
    }

    public void Handle(Nancy.HttpStatusCode statusCode, NancyContext context)
    {
        Exception innerException = ((Exception) context.Items[NancyEngine.ERROR_EXCEPTION]).InnerException;
        ExceptionDispatchInfo
            .Capture(innerException)
            .Throw();
    }
}

Finally we need to tell Nancy to use this. In your bootstrapper, override InternalConfiguration property:

protected override NancyInternalConfiguration InternalConfiguration
{
    get
    {
        return NancyInternalConfiguration.WithOverrides(config =>
            config.StatusCodeHandlers = new[] {typeof (RethrowStatusCodeHandler)});
    }
}

Now the exception, with proper stack trace will be thrown and captured by the middleware.

Full example with test.