Даже идеально протестированное и отлаженное приложение не избавляется от всех возможных исключительных ситуаций на 100% и приложения ASP.NET Core здесь не исключение. Условно, все возможные ошибки в ASP.NET Core можно разделить на ошибки в приложении (деление на ноль, доступ к несуществующему объекту и т.д.) и ошибки протокола HTTP (ошибки сервера с кодом 5хх, ошибки с кодом 4хх). Для обработки этих ошибок могут использоваться различные средства.
UseDeveloperExceptionPage
Для обработки исключений в приложении, находящимся в процессе разработки, предназначен компонент middleware — DeveloperExceptionPageMiddleware
, который мы можем включить в конвейер обработки запросов, выполнив UseDeveloperExceptionPage()
. Этот компонент включается в конвейер обработки запроса автоматически и при возникновении какой-либо ошибки в приложении генерирует специальную страницу с подробным описанием ошибки. Например, рассмотрим следующее приложение:
public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.Run(async (context) => { int a = 0; await context.Response.WriteAsync($"{10/a}"); }); app.Run(); }
здесь в middleware производится попытка деления на ноль. Если запустить это приложение, то мы увидим действие DeveloperExceptionPageMiddleware
:
Следует отметить, что DeveloperExceptionPageMiddleware
включается в конвейер по умолчанию только для стадии разработки, т.е. когда имя среды окружения «Development» в рабочей версии приложения пользователь увидит следующее:
то есть, по умолчанию, всё, что может знать пользователь — это то, что на сервере произошла ошибка. Что это за ошибка, кто виноват и что делать — об этом ASP.NET Core по умолчанию пользователя не информирует. Однако, мы можем сделать это самостоятельно, используя следующий компонент middleware.
UseExceptionHandler
Метод UseExceptionHandler
добавляет в конвейер обработки запросов компонент middleware ExceptionHandlerMiddleware
, который, в случае возникновения ошибки перенаправляет пользователя на заданную страницу и уже на этой странице мы можем каким-либо образом проинформировать пользователя. Например:
app.Environment.EnvironmentName = "Production"; // меняем имя окружения if (app.Environment.IsDevelopment()==false) { app.UseExceptionHandler("/error"); } //страница обработки ошибки app.MapGet("/error", () => "Error");
Если в рабочем варианте приложения возникнет ошибка, то пользователю будет выдана строка «Error»:
вторая версия метода
UseExceptionHandler
принимает IApplicationBuilder
, что позволяет сделать следующую обработку исключения:
if (app.Environment.IsDevelopment()==false) { app.UseExceptionHandler(application => { application.Run(async (context) => { context.Response.StatusCode = 500; await context.Response.WriteAsync("Error"); }); }); }
Результат работы приложения будет тот же, но, при этом, пользователь уже не сможет перейти на страницу «/error» просто набрав её адрес в браузере.
С выводом информации об ошибке пользователю разобрались, но при этом, возникает следующий вопрос: как детализировать информацию об ошибке? Просто выдавать «Error» не самая хороша идея. В ASP.NET Core мы можем получить доступ к исключению, используя свойство HttpContext.Features
Получение доступа к исключению
Чтобы получить доступ к исключению и к пути исходного запроса в обработчике ошибок ASP.NET Core использует специальный интерфейс IExceptionHandlerPathFeature
. Запросить объект, реализующий интерфейс мы можем, воспользовавшись свойством HttpContext.Features
. Детализируем сообщение об ошибке следующим образом:
if (app.Environment.IsDevelopment()==false) { app.UseExceptionHandler((app) => { app.Run(async(context) => { //пытаемся получить информацию об исключении var exceptionHandlerPathFeature = context.Features.Get<IExceptionHandlerPathFeature>(); if (exceptionHandlerPathFeature != null) await context.Response.WriteAsync($"Error: {exceptionHandlerPathFeature.Error.Message}"); else await context.Response.WriteAsync($"Unknown Error"); }); }); }
Теперь, если мы сможем получить информацию об ошибке — она будет выведена пользователю, иначе — будет выводиться строка «Unknown Error». Например,
Вообще, IExceptionHandlerPathFeature
содержит следующие свойства:
Endpoint |
Возвращает объект , представляющий endpoint для исходного запроса |
Error |
Ошибка, обнаруженная во время исходного запроса |
Path |
Часть пути запроса, которая идентифицирует запрошенный ресурс. |
Route |
Возвращает объект RouteValueDictionary , связанный с исходным запросом |
Используя эти свойства можно максимально детализировать сообщение об ошибке пользователю.
Итого
Обработка ошибок в ASP.NET Core может происходить по-разному, в зависимости от среды окружения. Так, если приложение находится в стадии разработки, то при возникновении ошибки срабатывает DeveloperExceptionPageMiddleware
, который генерирует максимально подробную информацию об ошибке для разработчика. Если же приложение вышло из стадии разработки, то информировать пользователя об ошибке можно, используя компонент middleware ExceptionHandlerMiddleware
, который необходимо подключить как можно ближе к началу конвейера обработки запросов.