В преддверии старта курса «C# ASP.NET Core разработчик» подготовили традиционный перевод полезного материала.
Также рекомендуем посмотреть вебинар на тему «Отличия структурных шаблонов проектирования на примерах». На этом открытом уроке участники вместе с преподавателем-экспертом познакомятся с тремя структурными шаблонами проектирования: Заместитель, Адаптер и Декоратор.
Введение
Сегодня в этой статье мы обсудим концепцию обработки исключений в приложениях ASP.NET Core. Обработка исключений (exception handling) — одна из наиболее важных импортируемых функций или частей любого типа приложений, которой всегда следует уделять внимание и правильно реализовывать. Исключения — это в основном средства ориентированные на обработку рантайм ошибок, которые возникают во время выполнения приложения. Если этот тип ошибок не обрабатывать должным образом, то приложение будет остановлено в результате их появления.
В ASP.NET Core концепция обработки исключений подверглась некоторым изменениям, и теперь она, если можно так сказать, находится в гораздо лучшей форме для внедрения обработки исключений. Для любых API-проектов реализация обработки исключений для каждого действия будет отнимать довольно много времени и дополнительных усилий. Но мы можем реализовать глобальный обработчик исключений (Global Exception handler), который будет перехватывать все типы необработанных исключений. Преимущество реализации глобального обработчика исключений состоит в том, что нам нужно определить его всего лишь в одном месте. Через этот обработчик будет обрабатываться любое исключение, возникающее в нашем приложении, даже если мы объявляем новые методы или контроллеры. Итак, в этой статье мы обсудим, как реализовать глобальную обработку исключений в ASP.NET Core Web API.
Создание проекта ASP.NET Core Web API в Visual Studio 2019
Итак, прежде чем переходить к обсуждению глобального обработчика исключений, сначала нам нужно создать проект ASP.NET Web API. Для этого выполните шаги, указанные ниже.
Откройте Microsoft Visual Studio и нажмите «Create a New Project» (Создать новый проект).
В диалоговом окне «Create New Project» выберите «ASP.NET Core Web Application for C#» (Веб-приложение ASP.NET Core на C#) и нажмите кнопку «Next» (Далее).
В окне «Configure your new project» (Настроить новый проект) укажите имя проекта и нажмите кнопку «Create» (Создать).
В диалоговом окне «Create a New ASP.NET Core Web Application» (Создание нового веб-приложения ASP.NET Core) выберите «API» и нажмите кнопку «Create».
Убедитесь, что флажки «Enable Docker Support» (Включить поддержку Docker) и «Configure for HTTPS» (Настроить под HTTPS) сняты. Мы не будем использовать эти функции.
Убедитесь, что выбрано «No Authentication» (Без аутентификации), поскольку мы также не будем использовать аутентификацию.
Нажмите ОК.
Используем UseExceptionHandler middleware в ASP.NET Core.
Чтобы реализовать глобальный обработчик исключений, мы можем воспользоваться преимуществами встроенного Middleware ASP.NET Core. Middleware представляет из себя программный компонент, внедренный в конвейер обработки запросов, который каким-либо образом обрабатывает запросы и ответы. Мы можем использовать встроенное middleware ASP.NET Core UseExceptionHandler в качестве глобального обработчика исключений. Конвейер обработки запросов ASP.NET Core включает в себя цепочку middleware-компонентов. Эти компоненты, в свою очередь, содержат серию делегатов запросов, которые вызываются один за другим. В то время как входящие запросы проходят через каждый из middleware-компонентов в конвейере, каждый из этих компонентов может либо обработать запрос, либо передать запрос следующему компоненту в конвейере.
С помощью этого middleware мы можем получить всю детализированную информацию об объекте исключения, такую как стектрейс, вложенное исключение, сообщение и т. д., а также вернуть эту информацию через API в качестве вывода. Нам нужно поместить middleware обработки исключений в configure()
файла startup.cs
. Если мы используем какое-либо приложение на основе MVC, мы можем использовать middleware обработки исключений, как это показано ниже. Этот фрагмент кода демонстрирует, как мы можем настроить middleware UseExceptionHandler
для перенаправления пользователя на страницу с ошибкой при возникновении любого типа исключения.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseExceptionHandler("/Home/Error");
app.UseMvc();
}
Теперь нам нужно проверить сообщение об исключении. Для этого откройте файл WeatherForecastController.cs
и добавьте следующий экшн-метод, чтобы пробросить исключение:
[Route("GetExceptionInfo")]
[HttpGet]
public IEnumerable<string> GetExceptionInfo()
{
string[] arrRetValues = null;
if (arrRetValues.Length > 0)
{ }
return arrRetValues;
}
Если мы хотим получить подробную информацию об объектах исключения, например, стектрейс, сообщение и т. д., мы можем использовать приведенный ниже код в качестве middleware исключения —
app.UseExceptionHandler(
options =>
{
options.Run(
async context =>
{
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/html";
var exceptionObject = context.Features.Get<IExceptionHandlerFeature>();
if (null != exceptionObject)
{
var errorMessage = $"<b>Exception Error: {exceptionObject.Error.Message} </b> {exceptionObject.Error.StackTrace}";
await context.Response.WriteAsync(errorMessage).ConfigureAwait(false);
}
});
}
);
Для проверки вывода просто запустите эндпоинт API в любом браузере:
Определение пользовательского Middleware для обработки исключений в API ASP.NET Core
Кроме того, мы можем написать собственное middleware
для обработки любых типов исключений. В этом разделе мы продемонстрируем, как создать типичный пользовательский класс middleware
. Пользовательское middleware
также обеспечивает гораздо большую гибкость для обработки исключений. Мы можем добавить стекатрейс, имя типа исключения, код ошибки или что-нибудь еще, что мы захотим включить как часть сообщения об ошибке. В приведенном ниже фрагменте кода показан типичный пользовательский класс middleware
:
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
namespace API.DemoSample.Exceptions
{
public class ExceptionHandlerMiddleware
{
private readonly RequestDelegate _next;
public ExceptionHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
}
}
}
}
В приведенном выше классе делегат запроса передается любому middleware
. Middleware
либо обрабатывает его, либо передает его следующему middleware
в цепочке. Если запрос не успешен, будет выброшено исключение, а затем будет выполнен метод HandleExceptionMessageAsync
в блоке catch
. Итак, давайте обновим код метода Invoke
, как показано ниже:
public async Task Invoke(HttpContext context)
{
try
{
await _next.Invoke(context);
}
catch (Exception ex)
{
await HandleExceptionMessageAsync(context, ex).ConfigureAwait(false);
}
}
Теперь нам нужно реализовать метод HandleExceptionMessageAsync
, как показано ниже:
private static Task HandleExceptionMessageAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
int statusCode = (int)HttpStatusCode.InternalServerError;
var result = JsonConvert.SerializeObject(new
{
StatusCode = statusCode,
ErrorMessage = exception.Message
});
context.Response.ContentType = "application/json";
context.Response.StatusCode = statusCode;
return context.Response.WriteAsync(result);
}
Теперь, на следующем шаге, нам нужно создать статический класс с именем ExceptionHandlerMiddlewareExtensions
и добавить приведенный ниже код в этот класс,
using Microsoft.AspNetCore.Builder;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace API.DemoSample.Exceptions
{
public static class ExceptionHandlerMiddlewareExtensions
{
public static void UseExceptionHandlerMiddleware(this IApplicationBuilder app)
{
app.UseMiddleware<ExceptionHandlerMiddleware>();
}
}
}
На последнем этапе, нам нужно включить наше пользовательское middleware в методе Configure класса startup, как показано ниже:
app.UseExceptionHandlerMiddleware();
Заключение
Обработка исключений — это по сути сквозная функциональность для любого типа приложений. В этой статье мы обсудили процесс реализации концепции глобальной обработки исключений. Мы можем воспользоваться преимуществами глобальной обработки исключений в любом приложении ASP.NET Core, чтобы гарантировать, что каждое исключение будет перехвачено и вернет правильные сведения, связанные с этим исключением. С глобальной обработкой исключений нам достаточно в одном месте написать код, связанный с обработкой исключений, для всего нашего приложения. Любые предложения, отзывы или запросы, связанные с этой статьей, приветствуются.
Узнать подробнее о курсе «C# ASP.NET Core разработчик».
Посмотреть вебинар на тему «Отличия структурных шаблонов проектирования на примерах».