Что такое метод OnActionExecuted в ASP.NET Core?

Ответ

OnActionExecuted — это метод хука в конвейере MVC/WebAPI ASP.NET Core, который вызывается после выполнения метода действия контроллера, но до выполнения результата (Result). Он является частью интерфейса IActionFilter и используется для постобработки, логирования, модификации ответа или обработки исключений.

Типичные сценарии использования:

  • Логирование времени выполнения действия.
  • Добавление или изменение HTTP-заголовков в ответе.
  • Глобальная обработка исключений на уровне фильтра.
  • Модификация объекта ActionResult или данных в ViewData.

Пример фильтра для логирования:

public class LoggingActionFilter : IActionFilter
{
    private Stopwatch _stopwatch;

    public void OnActionExecuting(ActionExecutingContext context)
    {
        _stopwatch = Stopwatch.StartNew();
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        _stopwatch.Stop();
        var actionName = context.ActionDescriptor.DisplayName;
        var duration = _stopwatch.ElapsedMilliseconds;

        // Логируем завершение действия и его длительность
        Console.WriteLine($"Action '{actionName}' executed in {duration} ms.");

        // Можно проверить, было ли исключение
        if (context.Exception != null && !context.ExceptionHandled)
        {
            // Обработка исключения (например, логирование ошибки)
            Console.WriteLine($"Exception: {context.Exception.Message}");
        }
    }
}

Ключевые моменты:

  • Метод получает ActionExecutedContext, который предоставляет доступ к Result (результат действия), Exception, Controller и другим данным.
  • Фильтр можно зарегистрировать глобально, на уровне контроллера или отдельного действия.
  • Для создания кастомных атрибутов удобнее наследоваться от ActionFilterAttribute, который уже реализует оба метода (OnActionExecuting и OnActionExecuted).

Ответ 18+ 🔞

Давай разберём эту штуку, как будто я тебе на кухне объясняю, с паяльником в одной руке и пивом в другой.

В общем, представь себе конвейер в ASP.NET Core — это как заводская линия. Твой запрос идёт по ней, и на разных этапах к нему могут прикручивать разные модули. Так вот, OnActionExecuted — это такой момент, когда твой метод в контроллере уже отработал, но результат (то, что он вернул) ещё не ушёл обратно пользователю. Прямо как на проверке качества перед упаковкой.

Зачем это, спросишь? Ну, например, ты хочешь засечь, сколько времени выполняется действие, чтобы потом не удивляться, почему всё тормозит. Или, допустим, тебе надо ко всем ответам автоматом прилепить какой-нибудь HTTP-заголовок, типа X-Processed-By-My-Awesome-Filter. А ещё тут можно перехватить исключения, которые вылезли в методе, и как-то их обработать, чтобы пользователю не светилась голая ошибка.

Смотри, вот тебе живой пример, как это выглядит в коде. Я тут даже Stopwatch приплел, чтобы время замерять — классика жанра:

public class LoggingActionFilter : IActionFilter
{
    private Stopwatch _stopwatch;

    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Это вызывается ДО действия. Запускаем секундомер.
        _stopwatch = Stopwatch.StartNew();
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // А это — ПОСЛЕ. Секундомер останавливаем.
        _stopwatch.Stop();
        var actionName = context.ActionDescriptor.DisplayName;
        var duration = _stopwatch.ElapsedMilliseconds;

        // Логируем, сколько времени всё заняло
        Console.WriteLine($"Action '{actionName}' executed in {duration} ms.");

        // А тут смотрим, не вылезло ли случайно исключение
        if (context.Exception != null && !context.ExceptionHandled)
        {
            // Если вылезло и его ещё не обработали — пишем в лог
            Console.WriteLine($"Exception: {context.Exception.Message}");
            // Можно, кстати, тут же его "захавать", чтобы система не упала
            // context.ExceptionHandled = true;
        }
    }
}

Что важно запомнить:

  • В OnActionExecuted тебе доступен контекст (ActionExecutedContext), а в нём — куча полезного: Result (результат работы метода), Exception (если что-то пошло по пизде), сам контроллер и прочее.
  • Вешать такой фильтр можно по-разному: глобально на все контроллеры, на конкретный контроллер или на отдельный метод — как удобнее.
  • Если лень реализовывать интерфейс IActionFilter руками, можно просто отнаследоваться от ActionFilterAttribute. Это такой готовый класс-заготовка, в котором уже есть оба метода (OnActionExecuting и OnActionExecuted), и его можно использовать как атрибут. Очень удобно, ёпта.

Вот и вся магия. По сути, это твой шанс поковыряться в ответе или в ошибке, пока они ещё не улетели в сеть. Главное — не накосячить там, а то можно так модифицировать результат, что клиент вообще офигеет.