Я пытаюсь понять, как работает Web API Http-конвейер!
В моем проекте веб-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)
Хорошо, поэтому я нашел решение здесь
ExceptionHandler
код 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
?Может ли кто-нибудь пролить свет на это?
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 предполагает, что вы, вероятно, хотите обрабатывать исключения на верхнем уровне стека выполнения. Я видел случаи, когда другие обработчики, такие как CORS, мешают этому, и блок catch никогда не заканчивается на верхнем уровне.
Если это то, что вы видите, вы все равно можете расширить ExceptionHandler и переопределить метод ShouldHandle, чтобы просто вернуть true. Или вы можете быть более хирургическим и конкретно определить, может ли CORS, вероятно, попасть на пути проверки верхнего уровня, как это предлагается в этом комментарии.