Глобальные фильтры в ASP.NET MVC 3

m-r Tarakanoff 2011 M06 12
2119
0
0
0

Среди множества возможностей в ASP.NET MVC 3, есть и глобальные фильтры действий (actions). Это значит, что при выполнении какого-либо действия, выполняются все фильтры, которые мы регистрируем в...

Среди множества возможностей в ASP.NET MVC 3, есть и глобальные фильтры действий (actions).

Это значит, что при выполнении какого-либо действия, выполняются все фильтры, которые мы регистрируем в глобальной коллекции (GlobalFilters).

Сразу отмеченная ложка дегтя, всплывает в бочке меда, для всех, кто знает такие механизмы фильтров действий, как FluentFilters или как в OXITE CMS (см. пост "FluentFilters для ASP.NET MVC и OXITE"). Эта ложка — невозможность указать конкретный контроллер и/или действие для которого выполнится фильтр.Это значит, например, что фильтр, который достает из БД различные рекламные баннеры и выдает их с определенной последовательной логикой для отображения на главной странице, будет выполнятся не только на главной странице, но и всех страницах сайта.

Это в принципе хреново, т.к. влияет на производительность. Пусть даже сайт небольшой, фильтров максимум 10-ть, но всё равно это "дело нечисто".

Итак, выход есть, при использовании того же FluentFilters или механизма, как в OXITE CMS (он намного лучше, если читали пост по ссылке выше).

Но, можно использовать логику отбора фильтров, если вставлять условие выполнения фильтра в сам фильтр, например так:

 
// рекламное сообщение на главной странице
public class AdActionFilter : FilterAttribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
// проверяем значения из RouteData, если текущий контроллер - "Home" и действие "Index", что
// у нас соответствует главной странице, то выдаем рекламную строку.
// Кстати, здесь, имя действия можно проверять через filterContext.ActionDescriptor.ActionName :)
if ((string)filterContext.RouteData.Values["controller"] == "Home" &&
(string)filterContext.RouteData.Values["action"] == "Index")
{
// ...здесь обращение к БД и пр.
filterContext.Controller.ViewData["Ad"] = "THis is advertising for Homepage!";
}
}
public void OnActionExecuting(ActionExecutingContext filterContext){}
}
 

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

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

 
public class AdActionFilter : FilterAttribute, IActionFilter
{
public void OnActionExecuted(ActionExecutedContext filterContext)
{
Expression<Func<HomeController, object>> method =
homeController => homeController.Index();
MethodCallExpression methodCall = method.Body as MethodCallExpression;

ReflectedActionDescriptor actionDescriptor = filterContext.ActionDescriptor as ReflectedActionDescriptor;

if (actionDescriptor.MethodInfo == methodCall.Method)
{
filterContext.Controller.ViewData["Ad"] = "THis is advertising!";
}
}
public void OnActionExecuting(ActionExecutingContext filterContext){}
}
 

Здесь, всё прозрачно для компилятора, поэтому если контроллеры или действия будут переименованы, то он сообщит об этом факте. Но, лично я, недолюбливаю лямбда-выражения в C#, постоянно в них путаюсь, короче, не понимаю, как так можно извращаться над языком программирования.

Оцените пост

-4
Дальше