如果 ExceptionHandler 捕获到异常,则不会调用 DelegatingHandler
Posted
技术标签:
【中文标题】如果 ExceptionHandler 捕获到异常,则不会调用 DelegatingHandler【英文标题】:DelegatingHandler not getting invoked if exception caught by ExceptionHandler 【发布时间】:2019-03-13 17:25:54 【问题描述】:我正在尝试了解 Web API Http 管道的工作原理!
在我的 Web API 项目中,我使用以下技术来记录/处理异常:
ExceptionHandler -> 在全局级别处理异常 ExceptionFilterAttribute -> 处理用户抛出的自定义异常 DelegatingHandler -> 记录请求和响应数据每个实现的示例代码:
异常过滤器:
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);
委托处理程序:
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
中的响应?
解决方案:(2018 年 10 月 9 日更新)
好的,所以我找到了解决方案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);
问题:
我仍然无法理解它是如何工作的?IExceptionHandler
和 ExceptionHandler
有什么区别?
有人能解释一下吗?
【问题讨论】:
【参考方案1】: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。
【讨论】:
以上是关于如果 ExceptionHandler 捕获到异常,则不会调用 DelegatingHandler的主要内容,如果未能解决你的问题,请参考以下文章
如何使用@ExceptionHandler 捕获 HTTP 405“不允许的方法”异常?