重构 WebAPI 控制器中的错误处理
本文关键字:错误 处理 WebAPI 控制器 重构 | 更新日期: 2023-09-27 18:33:46
我在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
方法的签名应该是什么。
我认为你可以用这样的方法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的一个很好的参考。
我将创建一个自定义错误处理程序过滤器,并以集中式形式处理所有可能的错误。这样,您只需从操作方法中抛出任何异常,然后它们将被过滤器捕获,您可以在其中处理它们并相应地更改响应。
public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
}
}
}
该示例取自本文,您可以在其中更详细地找到该概念。
这是一个类似于 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();
}
}