WebAPI控制器中的重构错误处理

时间:2016-02-09 11:01:34

标签: c# .net asp.net-web-api

我在WebAPI中有很多控制器方法,类似于以下内容:

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();
}

命令处理程序(在本例中为_deleteCommandHandler)在执行的早期注入,命令可以在方法中构建,也可以使用WebApi的自动方法构建。

我想要做的是在私有方法中封装try / catch错误处理,最后得到类似于的控制器:

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

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

我不确定私有ExecuteCommand方法的签名应该是什么。

3 个答案:

答案 0 :(得分:1)

我认为您可以通过以下方式Invoke采取行动:

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();
}

HttpResponseException的一个很好的参考。

答案 1 :(得分:0)

我会创建一个自定义错误处理程序过滤器,并以集中形式处理所有可能的错误。这样你就可以从动作方法中抛出任何异常,然后它们将被捕获到你可以处理它们的过滤器并相应地改变响应。

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

该示例取自this article,您可以在其中更详细地找到该概念。

答案 2 :(得分:0)

这是一个类似于shA.t的答案的解决方案,但异常映射在字典中,而try / catch逻辑在扩展方法中:

    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();
    }
}