Чтобы обработка исключений была простой и последовательной, старайтесь не создавать исключения в тех случаях, когда вы можете определить ошибку самостоятельно.
Я рекомендую вернуть подходящую ошибку, как в приведенном ниже коде.
Не используйте ошибки для управления потоком приложения.[HttpGet("{id:int}")] public async Task<ActionResult<Order>> Get(int id, CancellationToken cancellationToken) { var order = await _ordersService.Get(id, cancellationToken); if (order == null) { return NotFound(); } return Ok(order); }
Использование исключений снижает производительность, отрицательно влияет на читаемость кода, нарушает поток прерываний и требует дополнительных действий для правильной обработки исключений.
Также избегайте пребывания в состоянии API, где выдача исключения и отправка ошибки 500 — единственный способ ответить на запрос.
Такие ситуации должны стать поводом для рефакторинга вашего API и вариантов использования.
Отправляйте ошибку 500 только в исключительных необработанных случаях, таких как проблемы с базой данных, системные ошибки и т. д. Существует несколько способов добавить обработку исключений в ASP.NET Core. Этот Фильтры исключений , Лямбда-обработчик исключений И Промежуточное ПО .
Я рекомендую последнее.
Промежуточное программное обеспечение улавливает ошибки конструкторов контроллеров, фильтров и обработчиков, ошибки маршрутизации и т. д. Реализуйте интерфейс IMiddleware и зарегистрируйте этот класс в Startup.cs, как показано в коде ниже.
Обработчик ошибок должен первым в конвейере перехватывать любые исключения при обработке запроса.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Middlewares
services.AddTransient<ErrorHandlerMiddleware>();
services.AddTransient<YourCustomMiddleware>();
services.AddControllers();
}
public void Configure(IApplicationBuilder app)
{
app.UseMiddleware<ErrorHandlerMiddleware>(); // Should be always in the first place
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<YourCustomMiddleware>();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
}
Если исключение не будет обработано, клиенты API получат неизвестную ошибку.
Самый простой обработчик ошибок должен перехватить исключение, зарегистрировать его и отправить статус «Внутренняя ошибка сервера».
В приведенном ниже коде добавляется класс C#, который выполняет все вышеперечисленное.
public class ErrorHandlerMiddleware : IMiddleware
{
private readonly ILogger<ErrorHandlerMiddleware> _logger;
public ErrorHandlerMiddleware(ILogger<ErrorHandlerMiddleware> logger)
{
_logger = logger;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (Exception exception)
{
const string message = "An unhandled exception has occurred while executing the request.";
_logger.LogError(exception, message);
context.Response.Clear();
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
}
}
}
Я уверен, что нет необходимости проверять свойство context.Response.HasStarted. .
NET сам справляется с этим довольно хорошо, выдавая исключение InvalidOperationException с подробным сообщением.
Как это выглядит в консоли в нашем случае:
Этого достаточно? В моих проектах обычно немного больше требований к обработке ошибок.
Вот они:
- Запишите более подробную информацию об исключении.
Не добавляйте эту информацию в сообщение об исключении.
(Вы можете прочитать о том, как использовать свойство Exception.Data для регистрации дополнительной информации об исключениях.
в моей предыдущей статье .
)
- Не отправляйте клиентам веб-API конфиденциальную внутреннюю информацию, такую как трассировка стека, данные исключений и т. д.
- Не рассматривайте TaskCanceledException как внутреннюю ошибку сервера, если исключение вызвано отменой запроса клиентом, поэтому наиболее подходящим ответом HTTP в этом случае будет 499.
- Используйте JSON как наиболее подходящий веб-формат для обработки ошибок на стороне клиента.
- Текст ошибки переведен на другие языки, поэтому лучше не показывать пользователю сообщение об исключении.
Это должно быть что-то, что можно легко перевести, например: «О! Что-то пошло не так».
Также сообщение должно содержать какой-то уникальный код, с помощью которого пользователь сможет обратиться в службу поддержки вашего приложения.
- Используйте систему мониторинга для хранения, анализа журналов, поиска и агрегирования проблем на основе данных об ошибках, включая коды ошибок.
Это создаст возможности для дальнейшей автоматизации поддержки вашего приложения.
public class ErrorHandlerMiddleware : IMiddleware
{
private static readonly JsonSerializerOptions SerializerOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) },
WriteIndented = true
};
private readonly IWebHostEnvironment _env;
private readonly ILogger<ErrorHandlerMiddleware> _logger;
public ErrorHandlerMiddleware(IWebHostEnvironment env, ILogger<ErrorHandlerMiddleware> logger)
{
_env = env;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
try
{
await next(context);
}
catch (Exception exception) when (context.RequestAborted.IsCancellationRequested)
{
const string message = "Request was cancelled";
_logger.LogInformation(message);
_logger.LogDebug(exception, message);
context.Response.Clear();
context.Response.StatusCode = 499; //Client Closed Request
}
catch (Exception exception)
{
exception.AddErrorCode();
const string message = "An unhandled exception has occurred while executing the request.";
_logger.LogError(exception, exception is YourAppException ? exception.Message : message);
const string contentType = "application/json";
context.Response.Clear();
context.Response.StatusCode = StatusCodes.Status500InternalServerError;
context.Response.ContentType = contentType;
var json = ToJson(exception);
await context.Response.WriteAsync(json);
}
}
private string ToJson(in Exception exception)
{
var message = exception.Message;
var code = exception.GetErrorCode();
if (!_env.IsDevelopmentOrQA())
{
return JsonSerializer.Serialize(new { message, code }, SerializerOptions);
}
try
{
var info = exception.ToString();
var data = exception.Data;
var error = new { message, code, info, data };
return JsonSerializer.Serialize(error, SerializerOptions);
}
catch (Exception ex)
{
const string mes = "An exception has occurred while serializing error to JSON";
_logger.LogError(ex, mes);
}
return string.Empty;
}
}
Я предлагаю использовать хэш-код исключения в качестве кода ошибки, чтобы отправлять пользователям тот же код для решения аналогичных проблем.
Для создания шорткода подойдет любой алгоритм хеширования.
Я применяю наиболее доступный SHA-1, а затем усекаю результат до длины, достаточной для сохранения уникальности кода ошибки.
Расширение класса Exception, которое выдает короткий код ошибки, добавляется с использованием приведенного ниже кода.
private const string ErrorCodeKey = "errorCode";
public static Exception AddErrorCode(this Exception exception)
{
using var sha1 = SHA1.Create();
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(exception.ToString()));
var errorCode = string.Concat(hash[.
5].
Select(b => b.ToString("x")));
exception.Data[ErrorCodeKey] = errorCode;
return exception;
}
public static string GetErrorCode(this Exception exception)
{
return (string)exception.Data[ErrorCodeKey];
}
Простой пример всплывающего окна с ошибкой на стороне клиента.
Я надеюсь, что этот подход поможет вам с поддержкой приложений.
Буду благодарен за ваши вопросы и комментарии к статье :) Теги: #программирование #C++ #.
NET #asp.net core #ASP.NET #ASP #ASP #error #Exception #middleware #webapi #handling
-
Цукерберг «Позвонит» Ищет Редактора Новостей
19 Oct, 24 -
Millenium Bsa – Бесплатная Erp В России?
19 Oct, 24 -
Cackle - Индексация Комментариев
19 Oct, 24 -
Несколько Ошибок
19 Oct, 24 -
Как Мы Выгоняли Наркоторговцев Из Рунета
19 Oct, 24 -
Организованный Хаос – Путь Roomba
19 Oct, 24 -
Простое Сжатие Звука В Audacity
19 Oct, 24 -
Создание Модуля Для Drupal 7. Часть 1
19 Oct, 24