Главная страница   /   16.5. Использование фильтров для методов действий (ASP.NET MVC 4

ASP.NET MVC 4

ASP.NET MVC 4

Адам Фриман

16.5. Использование фильтров для методов действий

Фильтры действий можно использовать для различных целей. Встроенный класс для создания таких фильтров, IActionFilter, показан в листинге 16-21.

Листинг 16-21: Интерфейс IActionFilter
namespace System.Web.Mvc
{
	public interface IActionFilter
	{
		void OnActionExecuting(ActionExecutingContext filterContext);
		void OnActionExecuted(ActionExecutedContext filterContext);
	}
}

Этот интерфейс определяет два метода. MVC Framework вызывает метод OnActionExecuting перед тем, как вызвать метод действия, и OnActionExecuted после вызова метода действия.

Реализуем метод OnActionExecuting

Метод OnActionExecuting вызывается до метода действия. Вы можете использовать его для того, чтобы изучить запрос и принять решение о его отмене, изменении или задержке его выполнения. Параметром этого метода является объект ActionExecutingContext, который создает подкласс класса ControllerContext и определяет два дополнительных свойства, описанных в таблице 16-7.

Таблица 16-7: Свойства ActionExecutingContext
Название Тип Описание
ActionDescriptor ActionDescriptor Предоставляет информацию о методе действия
Result ActionResult Результат для метода действия; фильтр может отменить запрос, установив данному свойству иное значение, кроме null

Вы можете использовать фильтр, чтобы отменить запрос, определив в качестве значения для свойства Result результат действия. Чтобы это продемонстрировать, мы создали свой собственный класс фильтра действий под названием CustomActionAttribute в папке Infrastructure, как показано в листинге 16-22.

Листинг 16-22: Отмена запроса в методе OnActionExecuting
using System.Web.Mvc;
namespace Filters.Infrastructure
{
	public class CustomActionAttribute : FilterAttribute, IActionFilter
	{
		public void OnActionExecuting(ActionExecutingContext filterContext)
		{
			if (filterContext.HttpContext.Request.IsLocal)
			{
				filterContext.Result = new HttpNotFoundResult();
			}
		}
		public void OnActionExecuted(ActionExecutedContext filterContext)
		{
			// not yet implemented
		}
	}
}

В этом примере мы используем метод OnActionExecuting, чтобы проверить, отправлен ли запрос с локальной машины. Если это так, то возвращаем пользователю ответ 404 — Not Found.

Примечание

Как вы видите из листинга 16-22, необязательно реализовывать оба метода, определенные в интерфейсе IActionFilter, чтобы создать рабочий фильтр. Будьте осторожны, чтобы не вызвать NotImplementedException, которое Visual Studio добавляет к классу при реализации данного интерфейса. В фильтре действий MVC Framework вызывает оба метода, и если возникает исключение, то будут инициированы фильтры исключений. Если вам не нужно добавлять к методу какую-либо логику, просто оставьте его пустым.

Фильтр действий применяется так же, как и любой другой атрибут. Чтобы продемонстрировать фильтр, который мы создали в листинге 16-22, мы добавили новый метод действия в контроллер Home, как показано в листинге 16-23.

Листинг 16-23: Добавляем новое действие в контроллер Home
[CustomAction]
public string FilterTest()
{
	return "This is the FilterTest action";
}

Вы можете протестировать фильтр, запустив приложение и перейдя по ссылке /Home/FilterTest. Если вы отправили запрос с локальной машины, то вы увидите результат, показанный на рисунке 16-7, хотя, как мы знаем, и контроллер, и действие существуют.

Рисунок 16-7: Эффект от использования фильтра действий

Реализуем метод OnActionExecuted

Фильтр также можно использовать для выполнения каких-либо задач, которые измеряют время выполнения метода действия. В качестве простого примера мы создали новый класс ProfileActionAttribute в папке Infrastructure, который измеряет количество времени, которое занимает выполнение метода действия. Код этого фильтра показан в листинге 16-24.

Листинг 16-24: Более сложный фильтр действий
using System.Diagnostics;
using System.Web.Mvc;
namespace Filters.Infrastructure
{
	public class ProfileActionAttribute : FilterAttribute, IActionFilter
	{
		private Stopwatch timer;
		public void OnActionExecuting(ActionExecutingContext filterContext)
		{
			timer = Stopwatch.StartNew();
		}
		public void OnActionExecuted(ActionExecutedContext filterContext)
		{
			timer.Stop();
			if (filterContext.Exception == null)
			{
				filterContext.HttpContext.Response.Write(
					string.Format("<div>Action method elapsed time: {0}</div>",
						timer.Elapsed.TotalSeconds));
			}
		}
	}
}

В этом примере мы запускаем таймер с помощью метода OnActionExecuting (используется класс таймера Stopwatch из пространства имен System.Diagnostics). Метод OnActionExecuted вызывается по завершении метода действия. В листинге 16-25 показано, как мы применили атрибут к контроллеру Home (ранее созданный фильтр был удален, чтобы локальные запросы не перенаправлялись).

Листинг 16-25: Применяем фильтр действий к контроллеру Home
[ProfileAction]
public string FilterTest()
{
	return "This is the ActionFilterTest action";
}

Если вы запустите приложение и перейдете по ссылке /Home/FilterTest, то увидите те же результаты, что и на рисунке 16-8.

Рисунок 16-8: Используем фильтр действий для измерения производительности

Подсказка

Обратите внимание, что информация о производительности отображается в браузере перед результатом метода действия. Так происходит потому, что фильтр действий выполняется после завершения метода действия, но до обработки результата.

В качестве параметра в метод OnActionExecuted передается объект ActionExecutedContext. Этот класс определяет дополнительные свойства, которые показаны в таблице 16-8. Свойство Exception возвращает любое исключение, выброшенное методом действия, а свойство ExceptionHandled указывает, было ли оно обработано другим фильтром.

Таблица 16-8: Свойства ActionExecutedContext
Название Тип Описание
ActionDescriptor ActionDescriptor Предоставляет информацию о методе действия
Canceled bool Возвращает true, если действие было отменено другим фильтром
Exception Exception Возвращает исключение, выброшенное другим фильтром или методом действия
ExceptionHandled bool Возвращает true, если исключение было обработано
Result ActionResult Результат для метода действия; фильтр может отменить запрос, установив для этого свойства иное значение, кроме null

Свойство Canceled возвращает true, если запрос был отменен другим фильтром (т.е. он установил значение для свойства Result) с того момента, когда был запущен метод фильтра OnActionExecuting. Метод OnActionExecuted все равно будет вызван, но только для того, чтобы можно было освободить или очистить ранее используемые ресурсы.