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.
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();
}
Vous pouvez également faire ce qui est décrit dans cet article génial:
Implémentez simplement un ExcludeFilterAttribute
personnalisé, puis un ExcludeFilterProvider
personnalisé.
Solution propre et fonctionnait très bien pour moi!
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();
}
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);
}
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
}
}
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/
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"})]
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'.