Работал ли с Exception Filter в ASP.NET Core?

Ответ

Да, работал. В контексте ASP.NET Core Exception Filter — это специальный фильтр, предназначенный для глобальной или локальной обработки необработанных исключений, возникающих в конвейере обработки HTTP-запроса (в контроллерах, действиях, других фильтрах).

Основное назначение:

  • Централизованная обработка ошибок: Логирование исключений, преобразование технических исключений в пользовательские HTTP-ответы.
  • Контроль над ответом: Возможность вернуть клиенту специфичный формат (JSON, HTML) с нужным статус-кодом.

Пример реализации кастомного Exception Filter:

public class CustomExceptionFilter : IExceptionFilter
{
    private readonly ILogger<CustomExceptionFilter> _logger;

    public CustomExceptionFilter(ILogger<CustomExceptionFilter> logger)
    {
        _logger = logger;
    }

    public void OnException(ExceptionContext context)
    {
        // 1. Логируем исключение
        _logger.LogError(context.Exception, "Произошло необработанное исключение");

        // 2. Определяем, какой ответ вернуть
        var problemDetails = new ProblemDetails
        {
            Title = "Внутренняя ошибка сервера",
            Status = StatusCodes.Status500InternalServerError,
            Detail = "В процессе обработки запроса произошла ошибка.",
            Instance = context.HttpContext.Request.Path
        };

        // 3. Устанавливаем результат и помечаем исключение как обработанное
        context.Result = new ObjectResult(problemDetails)
        {
            StatusCode = problemDetails.Status
        };
        context.ExceptionHandled = true; // Важно: предотвращает дальнейшую обработку исключения
    }
}

// Регистрация фильтра глобально в Program.cs
builder.Services.AddControllers(options =>
{
    options.Filters.Add<CustomExceptionFilter>();
});

Альтернативы и best practices:

  • Middleware UseExceptionHandler: Часто является более предпочтительным способом для глобальной обработки исключений, так как перехватывает ошибки на более раннем этапе конвейера.
  • Атрибут [TypeFilter]: Для применения фильтра к конкретному контроллеру или действию.
  • Фильтры исключений полезны, когда нужна точечная обработка ошибок для определенной области приложения, в дополнение к глобальному обработчику.

Ответ 18+ 🔞

Да ты что, блядь, реально работал с этим? Ну ладно, слушай сюда, сейчас разжую как для дебила, только не ори потом, что непонятно.

Вот смотри, в этом ASP.NET Core есть такая штука — Exception Filter. Это типа такой мужик на стройке, который стоит и ловит все кирпичи, которые с крыши летят, пока другие работяги (твои контроллеры) косячат. Его задача — не дать этим кирпичам долбануть клиента по башке, а красиво подобрать, обернуть в бумажку и сказать: «Извините, у нас тут небольшие технические шоколадки».

Зачем он вообще нужен, этот фильтр?

  • Чтобы не бегать с тряпкой по всему приложению. Вместо того чтобы в каждом методе писать try-catch и одно и то же логирование, ты один раз настраиваешь этого ловца исключений, и он за всеми прибирает. Красота, а не жизнь.
  • Чтобы клиенту не светить голую ошибку с кучей стека. Представь, у тебя в базе данных кончилось место, а пользователь получает в ответе гигабайтный трейс с названиями таблиц и connection string. Это пиздец как небезопасно и непрофессионально. Фильтр позволяет сделать красивую, вменяемую ошибку.

Смотри, как это выглядит в коде, на простом примере:

public class MySuperExceptionFilter : IExceptionFilter
{
    private readonly ILogger<MySuperExceptionFilter> _logger;

    // Подтягиваем логгер, чтобы всё записывать. Без этого как без рук.
    public MySuperExceptionFilter(ILogger<MySuperExceptionFilter> logger)
    {
        _logger = logger;
    }

    public void OnException(ExceptionContext context)
    {
        // 1. Первым делом — логируем в черный ящик. Что упало, где и почему.
        _logger.LogError(context.Exception, "Ой, всё! Исключение в {Path}", context.HttpContext.Request.Path);

        // 2. Готовим красивый ответ для пользователя, а не эту дичь из стека.
        var problemDetails = new ProblemDetails
        {
            Title = "Чёт пошло не так",
            Status = StatusCodes.Status500InternalServerError,
            Detail = "На сервере произошла какая-то хуйня. Мы уже в курсе.",
            Instance = context.HttpContext.Request.Path
        };

        // 3. Говорим фреймворку: "Всё, я сам справился, исключение обработано, дальше не прёт".
        context.Result = new ObjectResult(problemDetails)
        {
            StatusCode = problemDetails.Status
        };
        context.ExceptionHandled = true; // Вот эта хуйня — самый важный флаг! Без него всё бесполезно.
    }
}

// А вот так его, уродца, встраиваем в приложение (в Program.cs):
builder.Services.AddControllers(options =>
{
    options.Filters.Add<MySuperExceptionFilter>(); // Кинули его на весь проект
});

Но есть нюансы, блядь! Не бросайся сразу делать фильтр на всё.

  • Middleware UseExceptionHandler — часто круче. Этот парень ловит ошибки ещё раньше, до того как они до фильтров вообще долетят. Для глобальной поимки всех пиздюлей — это часто лучший выбор.
  • Фильтр — для точечной работы. Допустим, у тебя есть один особый контроллер для платёжек, где ошибки нужно логировать в отдельное место и возвращать особый формат. Вот тут фильтр, прицепленный только к нему (через [TypeFilter]), будет в самый раз.
  • Не забывай про ExceptionHandled = true. А то будешь потом сидеть и думать: «Ну я же всё написал, а ошибка всё равно прёт на клиента как ни в чём не бывало!». Это классическая ловушка для новичков.

Короче, инструмент нужный, но применять его надо с мозгом, а не просто потому что модно. Иногда проще и правильнее сделать один жирный UseExceptionHandler на всё приложение и не париться.