Middlewares - gro1vy/DeliverServiceAPI GitHub Wiki

ExceptionHandlingMiddleware

В методах сервисов возвращение null или любого другого индикатора неправильных входных данных не всегда говорит о проблеме, так как метод может вернуть один и тот же индикатор в разных случаях, также в контроллере приходиться писать дополнительную логику обработки значений, пришедших из метода сервиса, поэтому решено при выявлении неправильных входных данных создавать исключение и ловить их в middleware. Для этого был создан ExceptionHandlingMiddleware.

Поля класса

Помимо поля тип RequestDelegate с названием _next необходимого для переходя к следующей middleware, определено поле тип ILogger с названием _logger, которое нужно для логгирования ошибок в текстовый файл и БД. Более подробно про логгер NLog, используемый в проекте, смотреть тут.

private readonly RequestDelegate _next;
private readonly ILogger<ExceptionHandlingMiddleware> _logger;

Методы класса

В классе определены два метода InvokeAsync и HandlExceptionAsync.

Первый метод является обязательным для middleware, и в нем проиходит отлов исключений. Переход к следующей middleware в pipline обернут в try-catch, что обеспечивает отлов всех исключений, созданных в конце обработки запроса, то есть в контроллере и всех методов сервисов, которые он вызывает.

public async Task InvokeAsync(HttpContext httpContext)
{
    try
    {
        await _next(httpContext);
    }
    // Отлов остальных исключений, они рассмотрены ниже
    // ...
    catch (Exception ex)
    {
        await HandlExceptionAsync(LogLevel.Critical, httpContext, ex, HttpStatusCode.InternalServerError, "Unknown error!");
    }
}

Второй метод необходим для облегчения обработки исключения. Он одновременно пишет логги, используя _logger, и отправляет пользователю ответ с помощью модели ResponseDTO.

private async Task HandlExceptionAsync(LogLevel logLevel, HttpContext httpContext, Exception ex, HttpStatusCode httpStatusCode, string message)
{
    _logger.Log(logLevel, ex, ex.Message);

    HttpResponse response = httpContext.Response;
    response.ContentType = "application/json";
    response.StatusCode = (int)httpStatusCode;

    var errorDTO = new ResponseDTO()
    {
        Message = message,
        Status = (int)httpStatusCode
    };

    await response.WriteAsJsonAsync(errorDTO);
}

Обрабатываемые исключения В try-cath попадают все исключения, которые сгенерирует приложения благодаря тому, что самый последний блок ловит Exception, который логгируется с уровнем Critical. Помимо него есть и другие исключения, которые выбрасываются методами asp.net и которые выбрасываются сервисами нашего приложения.

Исключения выбрасываемые ASP.NET

Все следующие исключения при отправке клиенту ответа имеют статус код 500:

  • InvalidOperationException логгируется с уровнем Error и отправляет клиенту сообщение "Operation execution error!"
  • OperationCanceledException логгируется с уровнем Error и отправляет клиенту сообщение "The operation was canceled!"
  • EncoderFallbackException логгируется с уровнем Error и отправляет клиенту сообщение "Text encoding error!"
  • ArgumentException логгируется с уровнем Error и отправляет клиенту сообщение "Unknown error!"
  • SaltParseException логгируется с уровнем Error и отправляет клиенту сообщение "Password verification error!"
  • DbUpdateException логгируется с уровнем Error и отправляет клиенту сообщение "An error occurred while saving the data. Please try again later."
  • FormatException логгируется с уровнем Error и отправляет клиенту сообщение "Data format error"
  • SecurityTokenEncryptionFailedException логгируется с уровнем Warning и отправляет клиенту сообщение "Error processing a secure token!"
  • RuntimeBinderException логгируется с уровнем Error и отправляет клиенту сообщение "Unknown error!"

Исключения выбрасываемые приложением:

  • ValidationProblemException логгируется с уровнем Info и отправляет клиенту сообщение из исключения. Имеет статус код 400
  • BadRequestException логгируется с уровнем Info и отправляет клиенту сообщение из исключения. Имеет статус код 400
  • NotFoundException логгируется с уровнем Info и отправляет клиенту сообщение из исключения. Имеет статус код 404