Бекенд на C# Web Api
Глобальная обработка исключений
В Action'ах контроллеров могут возникать непредвиденные ошибки. Эти ошибки можно обрабатывать в блоках try-catch, однако если в приложении много контроллеров, то будет неудобно каждый раз писать один и тот же код для обработки ошибок.
Вместо этого можно создать глобальный обработчик исключений, который будет срабатывать при возникновении исключения в любом action'е из любого контроллера.
Для глобальной обработки исключений используется компонент Middleware. Таких компонентов может быть много, и каждый из них может выполнять свою роль. Эти компоненты обрабатывают HTTP-запросы и ответы на определенных этапах жизненного цикла в ASP.NET Core приложения. Они формируют конвейер обработки запросов, через который проходит каждый запрос к приложению.

С помощью метода UseExceptionHandler мы можем обработать исключения как в примере ниже:
public static class ExceptionMiddlewareExtensions
{
public class ErrorDetails
{
public int StatusCode { get; set; }
public string Message { get; set; }
public override string ToString()
{
return JsonSerializer.Serialize(this);
}
}
public static void ConfigureExceptionHandler(this IApplicationBuilder app)
{
app.UseExceptionHandler(appError =>
{
appError.Run(async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "application/json";
var contextFeature = context.Features.Get<IExceptionHandlerFeature>();
if (contextFeature != null)
{
Log.Error($"Something went wrong: {contextFeature.Error}");
await context.Response.WriteAsync(new ErrorDetails()
{
StatusCode = context.Response.StatusCode,
Message = "Internal Server Error."
}.ToString());
}
});
});
}
}В данном случае мы записываем в лог что произошла ошибка. Вместо этого, можно было бы, например, отправлять уведомления в какой-нибудь мессенджер. И все это делается из одного места в приложении.
Не забудьте в Program вызвать этот метод:
var app = builder.Build();
...
app.ConfigureExceptionHandler();Вместо встроенного Middleware можно создать собственный. В примере ниже продемонстрирован такой класс:
public class ExceptionMiddleware
{
private readonly RequestDelegate _next;
public ExceptionMiddleware(RequestDelegate next)
{
_logger = logger;
_next = next;
}
public async Task InvokeAsync(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
Log.Error($"Something went wrong: {ex}");
await HandleExceptionAsync(httpContext, ex);
}
}
private async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
await context.Response.WriteAsync(new ErrorDetails()
{
StatusCode = context.Response.StatusCode,
Message = "Internal Server Error from the custom middleware."
}.ToString());
}
}В блоке try мы пытаемся вызвать action контроллера, и в случае ошибки записываем лог. Концептуально, разницы между встроенным и кастомным Middleware нет. Однако кастомный вариант предоставляет больше возможностей для модификации логики.
Также чтобы этот класс заработал нужно зарегистрировать его в Program:
var app = builder.Build();
...
app.UseMiddleware<ExceptionMiddleware>();Code Maze — Global Error Handling in ASP.NET Core Web API
AleksandrKonst — Middleware. Встроенные в ASP.NET Core
Автор документа: Артём Ветик