ASP.NET MVC: игнорировать пользовательский атрибут в базовом классе контроллера - PullRequest
4 голосов
/ 08 декабря 2010

У меня есть несколько контроллеров в моем проекте, которые все наследуются от контроллера, который я назвал BaseController. Я написал собственный атрибут, который применил ко всему классу BaseController, чтобы каждый раз при запуске действия на любом из моих контроллеров этот атрибут запускался первым.

Проблема в том, что у меня есть пара действий контроллера, которые я хотел бы игнорировать этот атрибут, но я не знаю, как это сделать.

Кто-нибудь может помочь? Я использую MVC 1.

Спасибо.

Ответы [ 3 ]

11 голосов
/ 08 декабря 2010

В своем пользовательском атрибуте вы можете добавить эту проверку 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() {
}
10 голосов
/ 21 февраля 2011

У меня была похожая потребность в чем-то подобном, и я обнаружил, что путем создания фильтра авторизации (реализующего / получая из FilterAttribute, IAuthorizationFilter) вместо обычного фильтра действий (производного от ActionFilterAttribute) и устанавливая Inherited=true и AllowMultiple=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()
    {
    }
}

Это позволило мне «отключить» фильтр для определенных случаев, но при этом я смог применить его по умолчанию либо для всего контроллера, либо для всего приложения.

Удачи!

3 голосов
/ 08 декабря 2010

Я не уверен, что есть простой способ удалить атрибуты в этой ситуации.Но я сделал нечто подобное для проекта, и то, что я сделал, поскольку только в нескольких случаях я не хотел, чтобы мой атрибут выполнялся, было создание двух атрибутов.

Мой первый атрибут был применен кмой базовый контроллер, как вы сделали, но он знал о существовании второго атрибута и, реализовав этот второй атрибут, я мог отключить запуск атрибута в базовом классе.

Не уверен, что это был лучшийрешение, но оно работало для меня.

Это было применено к базовому контроллеру:

/// <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
{
}

Тогда я мог бы использовать то, что эффективноатрибут dummy для его отключения.

/// <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();
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...