Фильтры в ASP.NET Core MVC. Фильтры результатов действий

Фильтры результатов действий выполняться после всех остальных фильтров. Такие фильтры могут реализовывать сразу четыре интерфейса IResultFilter, IAsyncResultFilterIAlwaysRunResultFilter или IAsyncAlwaysRunResultFilter.  Фильтры результатов, реализующие интерфейсы IResultFilter или IAsyncResultFilter выполняются только тогда, когда выполнение метода завершилось успешно. Также, эти фильтры не вызываются, если фильтры исключений обрабатывают исключение, но не устанавливают свойство Exception = null. При этом, фильтры, реализующие IAlwaysRunResultFilter или IAsyncAlwaysRunResultFilter включают результаты действия фильтров исключений. Как правило, фильтры результатов действия применяются в тех случаях, когда необходимо выполнить какую-либо постобработку результата метода.

Пример фильтра результатов действий в ASP.NET Core MVC

Чтобы продемонстрировать работу различных фильтров результатов, воспользуемся кодом приложения, разработанного при рассмотрении темы про фильтры исключений. Там мы разработали следующий фильтр:

public class MyExceptionFilter : IExceptionFilter
{
    ILogger<MyExceptionFilter> _logger;  
    public MyExceptionFilter(ILogger<MyExceptionFilter> logger) 
    { 
        _logger = logger;
    }

    public void OnException(ExceptionContext context)
    {
        _logger.LogCritical(context.Exception.Message);
        context.ExceptionHandled = true;
        context.Result = new ViewResult();
    }
}

и использовали его в контроллере HomeController:

[ServiceFilter(typeof(MyExceptionFilter))]
public IActionResult Privacy(int value)
{
    double result = 10 / value;
    return View();
}

Теперь добавим к этому же действию следующий фильтр результатов:

public class HeaderResultFilter : Attribute, IResultFilter
{
    public void OnResultExecuted(ResultExecutedContext context)
    {
        //throw new NotImplementedException();
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add(typeof(HeaderResultFilter).Name, DateTime.Now.ToString());
    }
}

и, пока закомментируем в действии контроллера строку с ошибкой:

[HeaderResultFilter]
[ServiceFilter(typeof(MyExceptionFilter))]
public IActionResult Privacy(int value)
{
   // double result = 10 / value;
    return View();
}

Наш фильтр должен добавлять в заголовки ответа заголовок со своим именем и датой. Запустим приложение и убедимся, что фильтр работает:

Теперь раскомментируем в действии контроллера строку с ошибкой и снова запустим приложение — фильтр результатов, реализующий IResultFilter не будет работать:

Чтобы наш фильтр результатов действий продолжал работать, даже, если в контроллере возникает исключение, реализуем вместо интерфейса IResultFilter интерфейс IAlwaysRunResultFilter:

public class HeaderResultFilter : Attribute, IAlwaysRunResultFilter
{
    public void OnResultExecuted(ResultExecutedContext context)
    {
        //throw new NotImplementedException();
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        context.HttpContext.Response.Headers.Add(typeof(HeaderResultFilter).Name, DateTime.Now.ToString());
    }
}

Теперь запустим приложение и убедимся, что фильтр результатов действий выполняется даже в случае, если в методе контроллера возникает исключение обрабатываемое фильтром исключений:

Контекст фильтра результатов представлен объектом типа ResultExecutingContext. С использованием свойства Cancel этого объекта мы можем прервать выполнение запроса, например:

public class HeaderResultFilter : Attribute, IAlwaysRunResultFilter
{
    public void OnResultExecuted(ResultExecutedContext context)
    {
        //throw new NotImplementedException();
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.Result is not ViewResult)
            context.Cancel = true; //прерываем выполнение
        else
           context.HttpContext.Response.Headers.Add(typeof(HeaderResultFilter).Name, DateTime.Now.ToString());

    }
}

Теперь изменим метод Privacy() контроллера следующим образом:

[HeaderResultFilter]
[ServiceFilter(typeof(MyExceptionFilter))]
public IActionResult Privacy(int value)
{
   // double result = 10 / value;
    return Ok("Успешный запрос");
}

Вопреки ожиданию, что мы увидим в браузере строку «Успешный запрос», фильтр результатов прекратит обработку запроса и мы увидим просто белый экран:

Итого

Фильтры результатов действий выполняться после всех остальных фильтров. Такие фильтры могут реализовывать сразу четыре интерфейса IResultFilter, IAsyncResultFilterIAlwaysRunResultFilter или IAsyncAlwaysRunResultFilter. Чтобы фильтр результатов действий выполнялся в любом случае (даже, в случае, обработки исключения фильтром исключений) он должен реализовывать один из двух интерфейсов — IAlwaysRunResultFilter или IAsyncAlwaysRunResultFilter.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии