Skip to content

Instantly share code, notes, and snippets.

@darrelmiller
Created January 21, 2014 20:54
How to tell Web API 2.1 to allow errors to propagate up the MessageHandler pipeline so all exceptions can be converted to HttpResponseMessages in one place.
class Program
{
static void Main(string[] args)
{
var server = WebApp.Start("http://localhost:1002/", (app) =>
{
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Services.Replace(typeof(IExceptionHandler), new RethrowExceptionHandler());
config.MessageHandlers.Add(new ErrorTrapHandler());
app.UseWebApi(config);
});
Console.ReadLine();
server.Dispose();
}
}
public class RethrowExceptionHandler : IExceptionHandler {
public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
return Task.FromResult(0);
}
}
public class ErrorTrapHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
try
{
return await base.SendAsync(request, cancellationToken);
}
catch (Exception ex)
{
return new HttpResponseMessage
{
ReasonPhrase = ex.Message,
StatusCode = HttpStatusCode.InternalServerError
};
}
}
}
@filipw
Copy link

filipw commented Jan 22, 2014

here is an example where your error handling would fail:

public class MyFormatter : MediaTypeFormatter
{
    public override bool CanReadType(Type type)
    {
        return true;
    }

    public override bool CanWriteType(Type type)
    {
        return true;
    }

    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content,
        TransportContext transportContext)
    {
        throw new Exception("cannot write to stream");
    }
}

        config.Formatters.Clear();
        config.Formatters.Add(new MyFormatter());

In your example the error stays unhandled and a Framework-generated 500 comes down.
If you use a proper exception handler it's handled correctly, and a custom HttpResponseMessage can be set:

public class ProperExceptionHandler : IExceptionHandler
{
    public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
    {
        context.Result = new ResponseMessageResult(new HttpResponseMessage
        {
            ReasonPhrase = context.Exception.Message,
            StatusCode = HttpStatusCode.InternalServerError
        });
        return Task.FromResult(0);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment