web-dev-qa-db-fra.com

Comment désactiver un filtre global dans ASP.Net MVC de manière sélective

J'ai mis en place un filtre global pour toutes mes actions de contrôleur dans lequel j'ouvre et ferme les sessions NHibernate. 95% de ces actions nécessitent un accès à la base de données, mais 5% n'en ont pas. Existe-t-il un moyen simple de désactiver ce filtre global pour ces 5%? Je pourrais aller dans l'autre sens et décorer uniquement les actions qui nécessitent la base de données, mais ce serait beaucoup plus de travail.

70
zszep

Vous pouvez écrire un attribut marqueur:

public class SkipMyGlobalActionFilterAttribute : Attribute
{
}

puis dans votre test de filtre d'action global pour la présence de ce marqueur sur l'action:

public class MyGlobalActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext.ActionDescriptor.GetCustomAttributes(typeof(SkipMyGlobalActionFilterAttribute), false).Any())
        {
            return;
        }

        // here do whatever you were intending to do
    }
}

puis si vous souhaitez exclure une action du filtre global, décorez-la simplement avec l'attribut marker:

[SkipMyGlobalActionFilter]
public ActionResult Index()
{
    return View();
}
135
Darin Dimitrov

Vous pouvez également faire ce qui est décrit dans cet article génial:

Exclure un filtre

Implémentez simplement un ExcludeFilterAttribute personnalisé, puis un ExcludeFilterProvider personnalisé.

Solution propre et fonctionnait très bien pour moi!

18

Cependant, la réponse acceptée par Darin Dimitrov est correcte et fonctionne bien mais, pour moi, la réponse la plus simple et la plus efficace a été fondée ici .

Vous avez juste besoin d'ajouter une propriété booléenne à votre attribut et de le vérifier, juste avant le début de votre logique:

public class DataAccessAttribute: ActionFilterAttribute
{
    public bool Disable { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (Disable) return;

        // Your original logic for your 95% actions goes here.
    }
}

Ensuite, à vos actions de 5%, utilisez-le simplement comme ceci:

[DataAccessAttribute(Disable=true)]
public ActionResult Index()
{            
    return View();
}
8
Dr. MAF

Créez un fournisseur de filtres personnalisé. Écrivez une classe qui implémentera IFilterProvider. Cette interface IFilterProvider possède une méthode GetFilters qui renvoie des filtres qui doivent être exécutés.

public class MyFilterProvider : IFilterProvider
{
        private readonly List<Func<ControllerContext, object>> filterconditions = new List<Func<ControllerContext, object>>();
        public void Add(Func<ControllerContext, object> mycondition)
        {
            filterconditions.Add(mycondition);
        }

        public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            return from filtercondition in filterconditions
                   select filtercondition(controllerContext) into ctrlContext
                   where ctrlContext!= null
                   select new Filter(ctrlContext, FilterScope.Global);
        }
}

================================================== ===========================
Dans Global.asax.cs

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            MyFilterProvider provider = new MyFilterProvider();
            provider.Add(d => d.RouteData.Values["action"].ToString() != "SkipFilterAction1 " ? new NHibernateActionFilter() : null);
            FilterProviders.Providers.Add(provider);
        }


protected void Application_Start()
{
    RegisterGlobalFilters(GlobalFilters.Filters);
}
2
Swapnil

Dans AspNetCore, la réponse acceptée par @ darin-dimitrov peut être adaptée pour fonctionner comme suit:

Tout d'abord, implémentez IFilterMetadata sur l'attribut marqueur:

public class SkipMyGlobalActionFilterAttribute : Attribute, IFilterMetadata
{
}

Recherchez ensuite la propriété Filters pour cet attribut sur le ActionExecutingContext:

public class MyGlobalActionFilter : IActionFilter
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.Filters.OfType<SkipMyGlobalActionFilterAttribute>().Any())
        {
            return;
        }

        // etc
    }
}
1
g t

Au moins de nos jours, c'est assez simple: pour exclure tous les filtres d'action d'une action, il suffit d'ajouter le OverrideActionFiltersAttribute .

Il existe des attributs similaires pour les autres filtres: OverrideAuthenticationAttribute , OverrideAuthorizationAttribute et OverrideExceptionAttribute .

Voir aussi https://www.strathweb.com/2013/06/overriding-filters-in-asp-net-web-api-vnext/

1
Markus Wagner

Vous pouvez changer votre code de filtre comme ceci:

 public class NHibernateActionFilter : ActionFilterAttribute
    {
        public IEnumerable<string> ActionsToSkip { get; set; }

        public NHibernateActionFilter(params string[] actionsToSkip)
        {
            ActionsToSkip = actionsToSkip;
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (null != ActionsToSkip && ActionsToSkip.Any(a => 
String.Compare(a,  filterContext.ActionDescriptor.ActionName, true) == 0))
                {
                    return;
                }
           //here you code
        }
    }

Et utilisez-le:

[NHibernateActionFilter(new[] { "SkipFilterAction1 ", "Action2"})]
1
Natalya

Eh bien, je pense que je l'ai fait fonctionner pour ASP.NET Core.
Voici le code:

public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        // Prepare the audit
        _parameters = context.ActionArguments;

        await next();

        if (IsExcluded(context))
        {
            return;
        }

        var routeData = context.RouteData;

        var controllerName = (string)routeData.Values["controller"];
        var actionName = (string)routeData.Values["action"];

        // Log action data
        var auditEntry = new AuditEntry
        {
            ActionName = actionName,
            EntityType = controllerName,
            EntityID = GetEntityId(),
            PerformedAt = DateTime.Now,
            PersonID = context.HttpContext.Session.GetCurrentUser()?.PersonId.ToString()
        };

        _auditHandler.DbContext.Audits.Add(auditEntry);
        await _auditHandler.DbContext.SaveChangesAsync();
    }

    private bool IsExcluded(ActionContext context)
    {
        var controllerActionDescriptor = (Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)context.ActionDescriptor;

        return controllerActionDescriptor.ControllerTypeInfo.IsDefined(typeof(ExcludeFromAuditing), false) ||
               controllerActionDescriptor.MethodInfo.IsDefined(typeof(ExcludeFromAuditing), false);
    }

Le code correspondant se trouve dans la méthode 'IsExcluded'.

0
ashilon