C# 控制器和动作上的 MVC 属性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/857142/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 04:25:15  来源:igfitidea点击:

MVC Attributes on Controllers and Actions

c#asp.net-mvc

提问by David

Is there a way to add an Attribute on the Controller level but not on a specific action. For example say if i had 10 Actions in my Controller and just 1 of those Actions does not require a specific attribute I created.

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

[MyAttribute]
public class MyController : Controller
{
    public ActionResult Action1() {}
    public ActionResult Action2() {}

    [Remove_MyAttribute]
    public ActionResult Action3() {}
}

I could potentially move this Action into another controller (but dont like that) or I could apply the MyAttribute to all actions except from Action3 but just thought if there is an easier way?

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

采纳答案by David

Johannes gave the correct solution and here is how I coded it... hope it helps other people.

约翰内斯给出了正确的解决方案,这是我编码它的方式......希望它可以帮助其他人。

[MyFilter("MyAction")]
public class HomeController : Controller
{
    public ActionResult Action1...
    public ActionResult Action2...
    public ActionResult MyAction...
}

public class CompressFilter : ActionFilterAttribute
{
    private IList _ExcludeActions = null;

    public CompressFilter()
    {
        _ExcludeActions = new List();
    }

    public CompressFilter(string excludeActions)
    {
        _ExcludeActions = new List(excludeActions.Split(','));
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        HttpRequestBase request = filterContext.HttpContext.Request;

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

        if (_ExcludeActions.Contains(currentActionName))
            return;

        ...
    }

回答by Ropstah

You could exclude a specific action by passing it to the main attribute:

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

 [MyAttribute(Exclude="Action3")]

EDIT

编辑

My example was from the head (as you can see the following is VB.NET, maybe that's where it went wrong), this is how I implemented:

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

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

End Class

回答by Johannes Setiabudi

You have to override/extend the default attribute and add a custom constructor to allow exclusion. Or you can create your custom attribute for exclusion (in your example is the [Remove_MyAttribute]).

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

回答by Pop Catalin

The usual pattern for what you are trying to do is to have and attribute with a boolean parameter that indicates if the attribute is applied or not.

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

Ex:

前任:

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

or 

[ComVisible(false)]

inf your case you would have:

在您的情况下,您将拥有:

[MyAttribute] // defaults to true

and

[MyAttribute(false)] for applying the attribute on excluded members

回答by Funka

I know my answer is a little late (almost four years) to the game, but I came across this question and wanted to share a solution I devised that allows me to do pretty much what the original question wanted to do, in case it helps anyone else in the future.

我知道我的回答有点晚(将近四年),但我遇到了这个问题并想分享我设计的解决方案,该解决方案允许我做几乎原始问题想做的事情,以防万一未来的任何其他人。

The solution involves a little gem called AttributeUsage, which allows us to specify an attribute on the controller (and even any base controllers!) and then override (ignore/remove) on individual actions or sub-controllers as needed. They will "cascade" down to where only the most granular attribute actually fires: i.e., they go from least-specific (base controllers), to more-specific (derived controllers), to most-specific (action methods).

该解决方案涉及一个名为 的小宝石AttributeUsage,它允许我们在控制器(甚至任何基本控制器!)上指定一个属性,然后根据需要覆盖(忽略/删除)单个操作或子控制器。它们将“级联”到只有最细粒度的属性实际触发的地方:即,它们从最不具体(基本控制器)到更具体(派生控制器),再到最具体(操作方法)。

Here's how:

就是这样:

[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
}

(I heard you like attributes, so I put some attributes on the attribute! That's really what makes the magic work here at the very top: Allowing them to inherit/cascade, but only allowing one of them to execute.)

(听说你喜欢属性,所以我在属性上加了一些属性!这就是让魔法在最顶层起作用的真正原因:允许它们继承/级联,但只允许其中之一执行。)

Here's how it is used now:

这是它现在的使用方式:

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

}

I hope this compiles, I yanked it from some similar code and did a little search-and-replace on it so it may not be perfect.

我希望它可以编译,我从一些类似的代码中提取了它并对其进行了一些搜索和替换,因此它可能并不完美。