Использование фильтров
Вы уже видели пример фильтра в главе 11, когда мы применили авторизацию к контроллеру администрирования SportsStore. Мы хотели, чтобы данный метод действия использовался только прошедшими аутентификацию пользователями, и это можно было бы реализовать несколькими способами. Например, можно проверять статус авторизированности запроса в каждом методе действия, как показано в листинге 16-1.
Листинг 16-1: Явная проверка авторизации в методах действия
namespace SportsStore.WebUI.Controllers
{
public class AdminController : Controller
{
// ... instance variables and constructor
public ViewResult Index()
{
if (!Request.IsAuthenticated)
{
FormsAuthentication.RedirectToLoginPage();
}
// ...rest of action method
}
public ViewResult Create()
{
if (!Request.IsAuthenticated)
{
FormsAuthentication.RedirectToLoginPage();
}
// ...rest of action method
}
public ViewResult Edit(int productId)
{
if (!Request.IsAuthenticated)
{
FormsAuthentication.RedirectToLoginPage();
}
// ...rest of action method
}
// ... other action methods
}
}
Как видите, при таком подходе много повторов, и вместо этого разумнее использовать фильтр, как показано в листинге 16-2.
Листинг 16-2: Применяем фильтр
namespace SportsStore.WebUI.Controllers
{
[Authorize]
public class AdminController : Controller
{
// ... instance variables and constructor
public ViewResult Index()
{
// ...rest of action method
}
public ViewResult Create()
{
// ...rest of action method
}
public ViewResult Edit(int productId)
{
// ...rest of action method
}
// ... other action methods
}
}
Фильтры – это атрибуты .NET, которые добавляют дополнительные этапы в конвейер обработки запроса. В листинге 16-2 мы использовали фильтр Authorize
, который имеет тот же эффект, как и все дублирующиеся проверки в листинге 16-1.
Памятка по атрибутам .NET
Атрибуты - это специальные классы .NET, наследующие от
System.Attribute
. Вы можете применить их к другим элементам кода, в том числе классам, методам, свойствам и полям. Их цель состоит в том, чтобы внедрить дополнительную информацию в скомпилированный код, которую можно позже прочитать в среде выполнения.В C# для применения атрибутов используются квадратные скобки, а заполнить их общедоступные свойства можно путем присвоения значений параметрам (например,
[MyAttribute(SomeProperty=value)]
). Согласно соглашению по именам компилятора C#, если имя класса атрибута заканчивается наAttribute
, эту часть можно опустить (например, применить фильтрAuthorizeAttribute
можно, записав только[Authorize]
).
Четыре основных типа фильтров
MVC Framework поддерживает четыре типа фильтров, которые позволяют внедрять логику в разное время процесса обработки запроса. Они описаны в таблице 16-1.
Таблица 16-1: Типы фильтров MVC Framework
Тип фильтра | Интерфейс | Реализация по умолчанию | Описание |
Фильтр авторизации | IAuthorizationFilter |
AuthorizeAttribute |
Запускается вначале, перед любым другим фильтром или методом действия |
Фильтр действий | IActionFilter |
ActionFilterAttribute |
Запускается до и после метода действия |
Фильтр результатов | IResultFilter |
ActionFilterAttribute |
Запускается до и после выполнения результата действия |
Фильтр исключений | IExceptionFilter |
HandleErrorAttribute |
Запускается только в том случае, если другой фильтр, метод действия или результат действия генерирует исключение |
Перед тем, как вызвать действие, MVC Framework проверяет определение метода на наличие атрибутов, реализующих перечисленные в таблице 16-1 интерфейсы. Если они есть, то в соответствующий момент обработки запроса вызывается метод, определенный этим интерфейсом. Платформа включает стандартные классы атрибутов, которые реализуют интерфейсы фильтров. Позже в данной главе мы научимся использовать эти классы.
Примечание
Класс
ActionFilterAttribute
реализует и интерфейсIActionFilter
, иIResultFilter
. Этот класс является абстрактным, что подразумевает необходимость его реализовать. Другие классы с полезными функциями, такие какAuthorizeAttribute
иHandleErrorAttribute
, можно использовать, не создавая производный класс.
Применяем фильтры к контроллерам и методам действий
Фильтры можно применить к отдельным методам действий или к целому контроллеру. В листинге 16-2 мы применили фильтр Authorize
к классу AdminController
. Это имеет тот же эффект, как и применение его к каждому методу действия в контроллере, что показано в листинге 16-3.
Листинг 16-3: Применяем фильтр к методам действий индивидуально
namespace SportsStore.WebUI.Controllers
{
public class AdminController : Controller
{
// ... instance variables and constructor
[Authorize]
public ViewResult Index()
{
// ...rest of action method
}
[Authorize]
public ViewResult Create()
{
// ...rest of action method
}
// ... other action methods
}
}
Вы можете одновременно применить несколько фильтров, причем на разных уровнях, то есть и к контроллеру, и отдельному методу действия. В листинге 16-4 показано использование трех различных фильтров.
Листинг 16-4: Применяем несколько фильтров в классе контроллера
[Authorize(Roles = "trader")] // applies to all actions
public class ExampleController : Controller
{
[ShowMessage] // applies to just this action
[OutputCache(Duration = 60)] // applies to just this action
public ActionResult Index()
{
// ... action method body
}
}
Некоторые фильтры из листинга 16-4 принимают параметры. Мы рассмотрим, как они работают, когда будем изучать виды фильтров по отдельности.
Примечание
Если вы определили пользовательский базовый класс для контроллеров, фильтры, примененные к базовому классу, будут использоваться и в производных классах.