如果ExceptionHandler

时间:2018-10-09 02:21:33

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

我试图了解Web API Http管道的工作原理!

在我的Web API项目中,我正在使用以下技术记录/处理异常:

  • ExceptionHandler->在全局级别处理异常
  • ExceptionFilterAttribute->处理用户引发的自定义异常
  • DelegatingHandler->记录请求和响应数据

每个实现的示例代码:

ExceptionFilter:

public class CustomExceptionFilter : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext context)
    {
        var request = context.ActionContext.Request;
        if (context.Exception is ItemNotFoundException)
        {
            context.Response = request.CreateResponse(HttpStatusCode.NotFound, context.Exception.Message);
        }
        else if (context.Exception is InvalidRequestException)
        {
            context.Response = request.CreateResponse(HttpStatusCode.BadRequest, context.Exception.Message);
        }
    }
}

异常处理程序:

public class GlobalExceptionHandler : ExceptionHandler
{
    public override void Handle(ExceptionHandlerContext context)
    {
        var result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
        {
            Content = new StringContent(Constant.ErrorMessage.InternalServerError)
        };
        context.Result = new ErrorMessageResult(context.Request, result);
    }
}

public class ErrorMessageResult : IHttpActionResult
{
    private readonly HttpRequestMessage _request;
    private readonly HttpResponseMessage _httpResponseMessage;

    public ErrorMessageResult(HttpRequestMessage request, HttpResponseMessage httpResponseMessage)
    {
        _request = request;
        _httpResponseMessage = httpResponseMessage;
    }

    public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
    {
        return Task.FromResult(_httpResponseMessage);
    }
}

DelegatingHandler:

public class LogRequestAndResponseHandler : DelegatingHandler
{
    private readonly ILoggingService _loggingService;

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        string requestBody = await request.Content.ReadAsStringAsync();
        _loggingService.FirstLevelServiceLog(requestBody);
        var result = await base.SendAsync(request, cancellationToken);
        if (result.Content != null)
        {
            var responseBody = await result.Content.ReadAsStringAsync();
            _loggingService.FirstLevelServiceLog(responseBody);
        }
        return result;
    }
}

观察:

  • 在调用自定义异常CustomExceptionFilter并随后在LogRequestAndResponseHandler中记录响应。
  • 但是,如果未处理该异常,它将进入GlobalExceptionHandler,则响应不会到达LogRequestAndResponseHandler进行记录。

谁能告诉我,为了在CustomExceptionFilter/GlobalExceptionHandler中接收响应,必须在DelegatingHandler中进行哪些代码更改?

  

解决方案:(已更新10/09/2018)

好的,所以我找到了解决方法here

通过修改ExceptionHandler代码,我可以捕获DelegatingHandler中的响应

关键是要继承IExceptionHandler而不是ExceptionHandler

代码:

public class GlobalExceptionHandler : IExceptionHandler
{
    public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
    {
        var httpResponse = context.Request.CreateResponse(HttpStatusCode.InternalServerError, Constant.ErrorMessage.InternalServerError);
        context.Result = new ResponseMessageResult(httpResponse);

        return Task.FromResult(0);
    }
}

问题:

  • 我仍然无法理解它的工作方式? IExceptionHandlerExceptionHandler有什么区别?

有人能对此有所启发吗?

1 个答案:

答案 0 :(得分:2)

ExceptionHandler这样实现IExceptionHandler

Task IExceptionHandler.HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
  if (context == null)
    throw new ArgumentNullException(nameof (context));
  ExceptionContext exceptionContext = context.ExceptionContext;
  if (!this.ShouldHandle(context))
    return TaskHelpers.Completed();
  return this.HandleAsync(context, cancellationToken);
}

我怀疑您看到的区别在于ShouldHandle检查,其实现方式如下:

public virtual bool ShouldHandle(ExceptionHandlerContext context)
{
  if (context == null)
    throw new ArgumentNullException(nameof (context));
  return context.ExceptionContext.CatchBlock.IsTopLevel;
}

我对管道不是很熟悉,但是从我看到的结果来看,似乎可以在各个点上处理异常,并且ExceptionHandler基类假定您可能只想在顶层处理异常。执行堆栈。我见过other handlers like CORS get in the way of this和catch块永远都不会处于顶层的情况。

如果这是您所看到的,您仍然可以扩展ExceptionHandler,并重写ShouldHandle方法以始终返回true。或者,您可能需要更外科手术,并专门检测CORS是否有可能妨碍顶级检查as suggested in this comment