Фильтры результатов действий выполняться после всех остальных фильтров. Такие фильтры могут реализовывать сразу четыре интерфейса IResultFilter
, IAsyncResultFilter
, IAlwaysRunResultFilter
или 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
, IAsyncResultFilter
, IAlwaysRunResultFilter
или IAsyncAlwaysRunResultFilter
. Чтобы фильтр результатов действий выполнялся в любом случае (даже, в случае, обработки исключения фильтром исключений) он должен реализовывать один из двух интерфейсов — IAlwaysRunResultFilter
или IAsyncAlwaysRunResultFilter
.