1

I have lots of controllers methods in WebAPI similar to the following:

public IHttpActionResult Delete(int id)
{
    var command = new DeleteItemCommand() { Id = id };

    try
    {
        _deleteCommandHandler.Handle(command);
    }
    catch (CommandHandlerResourceNotFoundException)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    catch(CommandHandlerException)
    {
        throw new HttpResponseException(HttpStatusCode.InternalServerError);
    }
    // More catches etc...

    return Ok();
}

The command handlers (in this instance _deleteCommandHandler) is injected earlier in the execution and the commands may be built in the method or using WebApi's automatic method.

What I would like to do is to encapsulate the try/catch error handling in a private method and end up with a controller similar to:

public IHttpActionResult Delete(int id)
{
    var command = new DeleteItemCommand() { Id = id };

    return ExecuteCommand(x => _deleteCommandHandler.Handle(command));
}

I'm not sure what the signature of the private ExecuteCommand method should be though.

shA.t
  • 15,232
  • 5
  • 47
  • 95
Graham
  • 1,387
  • 1
  • 12
  • 33

3 Answers3

1

I think you can Invoke your action in a method like this:

public IHttpActionResult Delete(int id)
{
    return ExecuteCommand(() => {
        var command = new DeleteItemCommand() { Id = id };
        _deleteCommandHandler.Handle(command);
    });
}

private IHttpActionResult ExecuteCommand(Action action)
{
    try
    {
        action.Invoke();
        //or: action();
    }
    catch (CommandHandlerResourceNotFoundException)
    {
        return HttpResponseException(HttpStatusCode.NotFound);
    }
    catch (CommandHandlerException)
    {
        return HttpResponseException(HttpStatusCode.InternalServerError);
    }
    return Ok();
}

A good reference for HttpResponseException.

shA.t
  • 15,232
  • 5
  • 47
  • 95
0

I would create a custom error handler filter, and handle all possible errors there in a centralized form. That way you can just throw whatever exception from the action methods, and then they will be caught at the filter where you can handle them and change the response accordingly.

public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute 
{
    public override void OnException(HttpActionExecutedContext context)
    {
        if (context.Exception is NotImplementedException)
        {
            context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
        }
    }
}

The example is taken from this article where you can find the concept in more detail.

Zoltán Tamási
  • 10,479
  • 3
  • 51
  • 73
0

Here's a solution similar to shA.t's answer, but the exceptions are mapped in a dictionary and the try/catch logic is in an extension method:

    public class TestController:ApiController
    {
        public IHttpActionResult Delete(int id)
        {
            return ExecuteCommand(() => {
                var command = new DeleteItemCommand() { Id = id };
                _deleteCommandHandler.Handle(command);
            });
    }

    private IHttpActionResult ExecuteCommand(Action action)
    {
        return action.SafeInvoke();
    }
}

public static class ActionExtensions
{
    private static readonly Dictionary<Type, HttpStatusCode> _exceptionToStatusCodeLookup = new Dictionary<Type, HttpStatusCode>
    {
        {typeof(CommandHandlerResourceNotFoundException), HttpStatusCode.NotFound },
        {typeof(CommandHandlerException), HttpStatusCode.InternalServerError },
    };

    public static IHttpActionResult SafeInvoke(this Action action)
    {
        try
        {
            action();
        }
        catch (Exception ex)
        {
            var statusCode = _exceptionToStatusCodeLookup.ContainsKey(ex.GetType()) ? _exceptionToStatusCodeLookup[ex.GetType()] : HttpStatusCode.InternalServerError;
            return new HttpResponseException(statusCode);
        }

        return new OkResult();
    }
}
gregsaab
  • 102
  • 8