DelegatingHandler не вызывается, если исключение перехватывается ExceptionHandler - PullRequest
0 голосов
/ 09 октября 2018

Я пытаюсь понять, как работает Http-конвейер Web API!

В своем проекте 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)

Хорошо, поэтому я нашел решение здесь

Путем изменения кода 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 Ответ

0 голосов
/ 09 октября 2018

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 помешать проверке верхнего уровня , как предлагается в этом комментарии .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...