Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@darrelmiller
Created January 21, 2014 20:54
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save darrelmiller/8548166 to your computer and use it in GitHub Desktop.
Save darrelmiller/8548166 to your computer and use it in GitHub Desktop.
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