控制器和操作上的 MVC 属性

问题描述 投票:0回答:5

有没有办法在控制器级别添加属性,而不是在特定操作上添加属性。例如,如果我的控制器中有 10 个操作,而其中只有 1 个操作不需要我创建的特定属性。

[我的属性]
公共类 MyController :控制器
{
    公共 ActionResult Action1() {}
    公共 ActionResult Action2() {}

    [删除_我的属性]
    公共 ActionResult Action3() {}
}

我可能会将此操作移至另一个控制器(但不喜欢那样),或者我可以将 MyAttribute 应用于除 Action3 之外的所有操作,但只是想是否有更简单的方法?

c# asp.net-mvc
5个回答
9
投票

我知道我的答案有点晚了(几乎四年了),但我遇到了这个问题,并想分享我设计的一个解决方案,它允许我做几乎最初的问题想做的事情,以防万一将来可以帮助其他人。

该解决方案涉及一个名为

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...

}

我希望这个可以编译,我从一些类似的代码中提取了它,并对它做了一些搜索和替换,所以它可能并不完美。


4
投票

您必须覆盖/扩展默认属性并添加自定义构造函数以允许排除。或者您可以创建排除的自定义属性(在您的示例中是

[Remove_MyAttribute]
)。


3
投票

Johannes 给出了正确的解决方案,这是我的编码方式......希望它对其他人有帮助。

[我的过滤器(“我的操作”)]
公共类 HomeController :控制器
{
    公共操作结果操作1...
    公共 ActionResult Action2...
    公共 ActionResult 我的操作...
}

公共类压缩过滤器:ActionFilterAttribute
{
    私有 IList _ExcludeActions = null;

    公共压缩过滤器()
    {
        _ExcludeActions = 新列表();
    }

    公共压缩过滤器(字符串排除动作)
    {
        _ExcludeActions = new List(excludeActions.Split(','));
    }

    公共覆盖无效OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpRequestBase 请求 = filterContext.HttpContext.Request;

        字符串 currentActionName = (string)filterContext.RouteData.Values["action"];

        if (_ExcludeActions.Contains(currentActionName))
            返回;

        ...
    }

2
投票

您可以通过将特定操作传递给主属性来排除它:

 [MyAttribute(Exclude="Action3")]

编辑

我的例子是从头开始的(你可以看到下面是VB.NET,也许这就是它出错的地方),这就是我的实现方式:

<Models.MyAttribute(Exclude:="Action3")> _
Public Class MyController
Inherits System.Web.Mvc.Controller

End Class

2
投票

您尝试执行的操作的通常模式是使用布尔参数来指定属性,该参数指示是否应用该属性。

例如:

[ComVisible] which is equivalent with [ComVisible(true)]

or 

[ComVisible(false)]

如果你的情况你会:

[MyAttribute] // defaults to true

and

[MyAttribute(false)] for applying the attribute on excluded members
© www.soinside.com 2019 - 2024. All rights reserved.