我试图了解Web API Http管道的工作原理!
在我的Web API项目中,我正在使用以下技术记录/处理异常:
每个实现的示例代码:
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);
}
}
问题:
IExceptionHandler
和ExceptionHandler
有什么区别?有人能对此有所启发吗?
答案 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。