ASP.NET MVC:忽略基本控制器类中的自定义属性

发布于 2024-10-06 20:29:15 字数 192 浏览 9 评论 0原文

我的项目中有许多控制器,它们都继承自我命名为 BaseController 的控制器。我编写了一个应用于整个 BaseController 类的自定义属性,以便每次在任何控制器中运行操作时,该属性都会首先运行。

问题是我有几个控制器操作我想忽略该属性,但我不知道该怎么做。

有人可以帮忙吗?我正在使用 MVC 1。

谢谢。

I have a number of Controllers in my project that all inherit from a controller I've named BaseController. I wrote a custom attribute that I applied to the entire BaseController class, so that each time an action runs in any of my controllers, that attribute will run first.

The problem is that I have a couple of controller actions that I'd like to ignore that attribute, but I don't know how to do it.

Can anyone help? I'm using MVC 1.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

久伴你 2024-10-13 20:29:15

我对类似的东西有类似的需求,并发现通过创建授权过滤器(实现/派生自 FilterAttribute, IAuthorizationFilter)而不是常规操作过滤器(派生自 ActionFilterAttribute ),并在属性上设置 Inherited=trueAllowMultiple=false,使其仅在适当的位置运行一次。

这意味着我能够将我的过滤器从基本控制器(站点范围的默认值)向下“级联”到派生控制器(例如 AdminController 或其他控制器),甚至进一步向下到单个操作方法。

例如,

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method, Inherited=true, AllowMultiple=false)]
public class MyCustomAttribute : FilterAttribute, IAuthorizationFilter
{
    private MyCustomMode _Mode;
    public MyCustomAttribute(MyCustomMode mode)
    {
        _Mode = mode;
    }
    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }
        // run my own logic here.
        // set the filterContext.Result to anything non-null (such as
        // a RedirectResult?) to skip the action method's execution.
        //
        //
    }
}

public enum MyCustomMode
{
    Enforce,
    Ignore
}

然后要使用它,我可以将其应用到我的超级控制器,

[MyCustomAttribute(Ignore)]
public class BaseController : Controller
{
}

并且我可以更改/覆盖特定控制器,甚至特定操作!

[MyCustomAttribute(Enforce)]
public class AdministrationController : BaseController
{
    public ActionResult Index()
    {
    }

    [MyCustomAttribute(Ignore)] 
    public ActionResult SomeBasicPageSuchAsAHelpDocument()
    {
    }
}

这使我能够针对特定情况“关闭”过滤器,同时仍然能够将其作为默认值应用于整个控制器或整个应用程序。

祝你好运!

I had a similar need for something like this and found that by creating an authorization filter (implementing/deriving from FilterAttribute, IAuthorizationFilter) rather than a regular action filter (deriving from ActionFilterAttribute), and setting Inherited=true and AllowMultiple=false on the attribute, that it would only run once at the appropriate spot.

This means I am able to "cascade" my filter down from a base controller (the site-wide default), to a derived controller (for example the AdminController or whatever), or even further down to an individual action method.

For example,

[AttributeUsage(AttributeTargets.Class|AttributeTargets.Method, Inherited=true, AllowMultiple=false)]
public class MyCustomAttribute : FilterAttribute, IAuthorizationFilter
{
    private MyCustomMode _Mode;
    public MyCustomAttribute(MyCustomMode mode)
    {
        _Mode = mode;
    }
    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }
        // run my own logic here.
        // set the filterContext.Result to anything non-null (such as
        // a RedirectResult?) to skip the action method's execution.
        //
        //
    }
}

public enum MyCustomMode
{
    Enforce,
    Ignore
}

And then to use it, I can apply it to my super-controller,

[MyCustomAttribute(Ignore)]
public class BaseController : Controller
{
}

And I can change/override it for specific controllers, or even for specific actions!

[MyCustomAttribute(Enforce)]
public class AdministrationController : BaseController
{
    public ActionResult Index()
    {
    }

    [MyCustomAttribute(Ignore)] 
    public ActionResult SomeBasicPageSuchAsAHelpDocument()
    {
    }
}

This allowed me to "turn off" the filter for specific cases, while still being able to apply it as a default on either the whole controller or whole application.

Good luck!

伴随着你 2024-10-13 20:29:15

在您的自定义属性中,您可以添加此 ShouldRun() 检查,如下所示:

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (ShouldRun(filterContext))
        {
            // proceed with your code
        }
    }

    private bool ShouldRun(ActionExecutingContext filterContext)
    {
        var ignoreAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof(IgnoreMyCustomAttribute), false);
        if (ignoreAttributes.Length > 0)
            return false;

        return true;
    }

ShouldRun() 只是检查您的操作中是否有“IgnoreMyCustomAttribute”。如果存在,那么您的自定义属性将不会执行任何操作。

您现在需要创建一个简单的 IgnoreMyCustomAttribute,它不执行任何操作:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class IgnoreMyCustomAttribute: ActionFilterAttribute
{
}

每当您使用 [IgnoreMyCustom] 装饰控制器操作时,MyCustomAttribute 将不会执行任何操作。例如:

[IgnoreMyCustom]
public ViewResult MyAction() {
}

In your custom attribute, you can add this ShouldRun() check like this:

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (ShouldRun(filterContext))
        {
            // proceed with your code
        }
    }

    private bool ShouldRun(ActionExecutingContext filterContext)
    {
        var ignoreAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof(IgnoreMyCustomAttribute), false);
        if (ignoreAttributes.Length > 0)
            return false;

        return true;
    }

ShouldRun() simply checks whether there's a "IgnoreMyCustomAttribute" on your action. If it's there, then your custom attribute won't do anything.

You'll now want to create a simple IgnoreMyCustomAttribute, which doesn't do anything:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
public class IgnoreMyCustomAttribute: ActionFilterAttribute
{
}

Whenever you decorate your controller action with [IgnoreMyCustom], then MyCustomAttribute won't do anything. e.g.:

[IgnoreMyCustom]
public ViewResult MyAction() {
}
浅暮の光 2024-10-13 20:29:15

我不确定在这种情况下是否有简单的方法来删除属性。但我已经为一个项目做了类似的事情,我所做的就是创建两个属性,因为只有在少数情况下我不希望我的属性运行。

正如您所做的那样,我的第一个属性已应用于我的基本控制器,但它知道第二个属性的存在,并且通过实现第二个属性,我可以禁用基类上的属性运行。

不确定这是否是最好的解决方案,但它对我有用。

这被应用于基本控制器:

/// <summary>
/// This is used to force the schema to HTTP is it is HTTPS.
/// RequireHttpsAttribute or OptionalHttpsAttribute takes precedence if used.
/// </summary>
public class RequireHttpAttribute : FilterAttribute, IAuthorizationFilter
{
    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
            throw new ArgumentNullException("filterContext");

        if (filterContext.HttpContext.Request.IsSecureConnection)
        {
            object[] attributes = filterContext.ActionDescriptor.GetCustomAttributes(true);
            if (!attributes.Any(a => a is RequireHttpsAttribute || a is OptionalHttpsAttribute))
            {
                HandleHttpsRequest(filterContext);
            }
        }
    }

    protected virtual void HandleHttpsRequest(AuthorizationContext filterContext)
    {
        //  only redirect for GET method, otherwise browser may not propogate the verb and request body correctly
        if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
            throw new InvalidOperationException(MvcResources.RequireHttpAttribute_MustNotUseSsl);

        //  redirect to HTTP version
        string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
        filterContext.Result = new RedirectResult(url);
    }
}

像这样:

[RequireHttp]
public abstract class Controller : System.Web.Mvc.Controller
{
}

然后我可以使用实际上是虚拟属性的东西来禁用它。

/// <summary>
/// This attribute allows the action to be server on HTTP and HTTPS but neither is enforce.
/// RequireHttpsAttribute takes precedence if used.
/// </summary>
public class OptionalHttpsAttribute : FilterAttribute
{
    // This is deliberately empty, the attribute is used by RequireHttpAttribute to stop it changing schema to HTTP
}

就像这样:

    [OptionalHttps]
    public ActionResult OptionalHttps()
    {
        return View();
    }

I'm not sure there is an easy way to remove attributes in this situation. But I have done something similar for a project and what I did, as it was only in a few instances I didn't want my attribute to run, was to create two attributes.

My first attribute was applied to my base controller as you've done but it was aware of the existance of a second attribute and by implementing that second attribute I could disable the attribute on the base class from running.

Not sure if it was the best solution but it worked for me.

This was applied to the base controller:

/// <summary>
/// This is used to force the schema to HTTP is it is HTTPS.
/// RequireHttpsAttribute or OptionalHttpsAttribute takes precedence if used.
/// </summary>
public class RequireHttpAttribute : FilterAttribute, IAuthorizationFilter
{
    public virtual void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
            throw new ArgumentNullException("filterContext");

        if (filterContext.HttpContext.Request.IsSecureConnection)
        {
            object[] attributes = filterContext.ActionDescriptor.GetCustomAttributes(true);
            if (!attributes.Any(a => a is RequireHttpsAttribute || a is OptionalHttpsAttribute))
            {
                HandleHttpsRequest(filterContext);
            }
        }
    }

    protected virtual void HandleHttpsRequest(AuthorizationContext filterContext)
    {
        //  only redirect for GET method, otherwise browser may not propogate the verb and request body correctly
        if (!string.Equals(filterContext.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
            throw new InvalidOperationException(MvcResources.RequireHttpAttribute_MustNotUseSsl);

        //  redirect to HTTP version
        string url = "http://" + filterContext.HttpContext.Request.Url.Host + filterContext.HttpContext.Request.RawUrl;
        filterContext.Result = new RedirectResult(url);
    }
}

Like so:

[RequireHttp]
public abstract class Controller : System.Web.Mvc.Controller
{
}

I could then use what is effectively a dummy attribute to disable it.

/// <summary>
/// This attribute allows the action to be server on HTTP and HTTPS but neither is enforce.
/// RequireHttpsAttribute takes precedence if used.
/// </summary>
public class OptionalHttpsAttribute : FilterAttribute
{
    // This is deliberately empty, the attribute is used by RequireHttpAttribute to stop it changing schema to HTTP
}

Like so:

    [OptionalHttps]
    public ActionResult OptionalHttps()
    {
        return View();
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文