Я знаю, что мой ответ немного запоздал (почти четыре года) к игре, но я наткнулся на этот вопрос и хотел поделиться разработанным мною решением, которое позволяет мне делать в значительной степени то, что хотел сделать первоначальный вопрос, в если это поможет кому-то еще в будущем.
Решение включает в себя небольшой гем под названием AttributeUsage
, который позволяет нам указать атрибут на контроллере (и даже на любых базовых контроллерах!), А затем при необходимости переопределить (игнорировать / удалить) отдельные действия или субконтроллеры. Они будут «каскадно» идти туда, где на самом деле срабатывает только самый гранулированный атрибут: то есть они переходят от наименее специфичных (базовые контроллеры) к более специфичным (производные контроллеры) и наиболее специфичным (методы действия).
Вот как:
[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method, Inherited=true, AllowMultiple=false)]
public class MyCustomFilterAttribute : ActionFilterAttribute
{
private MyCustomFilterMode _Mode = MyCustomFilterMode.Respect; // this is the default, so don't always have to specify
public MyCustomFilterAttribute()
{
}
public MyCustomFilterAttribute(MyCustomFilterMode mode)
{
_Mode = mode;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (_Mode == MyCustomFilterMode.Ignore)
{
return;
}
// Otherwise, respect the attribute and work your magic here!
//
//
//
}
}
public enum MyCustomFilterMode
{
Ignore = 0,
Respect = 1
}
(Я слышал, что вы любите атрибуты, поэтому я поместил некоторые атрибуты в атрибут! Это действительно то, что заставляет магию работать здесь на самом верху: разрешать им наследовать / каскадировать, но разрешать выполнять только одному из них.)
Вот как это используется сейчас:
[MyCustomFilter]
public class MyBaseController : Controller
{
// I am the application's base controller with the filter,
// so any derived controllers will ALSO get the filter (unless they override/Ignore)
}
public class HomeController : MyBaseController
{
// Since I derive from MyBaseController,
// all of my action methods will also get the filter,
// unless they specify otherwise!
public ActionResult FilteredAction1...
public ActionResult FilteredAction2...
[MyCustomFilter(Ignore)]
public ActionResult MyIgnoredAction... // I am ignoring the filter!
}
[MyCustomFilter(Ignore)]
public class SomeSpecialCaseController : MyBaseController
{
// Even though I also derive from MyBaseController, I can choose
// to "opt out" and indicate for everything to be ignored
public ActionResult IgnoredAction1...
public ActionResult IgnoredAction2...
// Whoops! I guess I do need the filter on just one little method here:
[MyCustomFilter]
public ActionResult FilteredAction1...
}
Я надеюсь, что это скомпилировано, я вытащил его из какого-то похожего кода и сделал небольшой поиск и замену, чтобы он не был идеальным.