Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Web API OWIN startup exception handling

In my C# Web API, I'm trying to add a global exception handler. I've been using a custom global ExceptionFilterAttribute to handle the exception and return a HttpResponseMessage:

public override void OnException(HttpActionExecutedContext context)
{
    ...

    const string message = "An unhandled exception was raised by the Web API.";
    var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.InternalServerError)
    {
        Content = new StringContent(message),
        ReasonPhrase = message
    };
    context.Response = httpResponseMessage;
}

This has worked fine for handling exceptions thrown at the controller level.

However, during development we had an error thrown from our OWIN startup file due to a database connection issue, however, a standard IIS exception was returned, instead of going through the global exception handler, and the full HTML was returned to our API consumer.

I've tried a few different approaches to catch exceptions thrown in my OWIN startup:

Custom ApiControllerActionInvoker:

public class CustomActionInvoker : ApiControllerActionInvoker
{
    public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        var result = base.InvokeActionAsync(actionContext, cancellationToken);

        if (result.Exception != null && result.Exception.GetBaseException() != null)
        {
            ...
        }

        return result;
    }
}

Custom ExceptionHandler:

public class CustomExceptionHandler : ExceptionHandler
{
    public override void Handle(ExceptionHandlerContext context)
    {
        ...

        base.Handle(context);
    }

    public override bool ShouldHandle(ExceptionHandlerContext context)
    {
        return true;
    }
}

Custom OwinMiddleware component:

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

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

And finally just using Application_Error:

protected void Application_Error(object sender, EventArgs e)
{
    ...
}

But nothing seems to catch the exception.

Does anyone know of a way to catch the exception and return a HttpResponseMessage? Or if any of the approaches I've already tried should have worked?

Any help much appreciated.

like image 689
Dan Ellis Avatar asked Jul 28 '15 09:07

Dan Ellis


People also ask

How do you handle exceptions in Web API?

You can customize how Web API handles exceptions by writing an exception filter. An exception filter is executed when a controller method throws any unhandled exception that is not an HttpResponseException exception.

How do I return an exception from Web API?

Return InternalServerError for Handled Exceptionscs file and locate the Get(int id) method. Add the same three lines within a try... catch block, as shown in Listing 2, to simulate an error. Create two catch blocks: one to handle a DivideByZeroException and one to handle a generic Exception object.

How do you handle exceptions in .NET core API?

To handle exceptions we can use the try-catch block in our code as well as finally keyword to clean up resources afterward. Even though there is nothing wrong with the try-catch blocks in our Actions in Web API project, we can extract all the exception handling logic into a single centralized place.


1 Answers

I have an application that does this correctly. In my case I wrote a middleware class that always returns a message telling the caller that the service is unavailable because there was an error during startup. This class is called FailedSetupMiddleware in my solution. The outline of it looks like this:

public class FailedSetupMiddleware
{
    private readonly Exception _exception;

    public FailedSetupMiddleware(Exception exception)
    {
        _exception = exception;
    }

    public Task Invoke(IOwinContext context, Func<Task> next)
    {
        var message = ""; // construct your message here
        return context.Response.WriteAsync(message);
    }
}

In my Configuration class I have a try...catch block that configures the OWIN pipeline with only the FailedSetupMiddleware in the case where an exception was thrown during configuration.

My OWIN startup class looks like this:

[assembly: OwinStartup(typeof(Startup))]

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        try
        {
            //
            // various app.Use() statements here to configure
            // OWIN middleware
            //
        }
        catch (Exception ex)
        {
          app.Use(new FailedSetupMiddleware(ex).Invoke);
        }
    }
}
like image 186
bikeman868 Avatar answered Sep 20 '22 20:09

bikeman868