如何有选择地禁用ASP.Net MVC中的全局筛选器


76

我为我打开和关闭NHibernate会话的所有控制器操作设置了全局过滤器。这些操作中有95%需要某些数据库访问权限,但5%则不需要。是否有任何简单的方法可以针对这5%禁用此全局过滤器。我可以反过来,只装饰需要数据库的操作,但这将需要更多的工作。


1
怎么样创建另一个动作并以此装饰5%。像NHibernateNotRequiredAttribute()之类的东西?
dreza 2012年

Answers:


150

您可以编写一个标记属性:

public class SkipMyGlobalActionFilterAttribute : Attribute
{
}

然后在全局操作过滤器中测试操作中是否存在此标记:

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

然后如果要从全局过滤器中排除某些操作,只需用marker属性装饰它即可:

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

真的很棒的解决方案。我想知道我自己怎么没想到这一点。谢谢。
zszep 2012年

5
这很有帮助,谢谢。为了帮助将来的人们,您还可以将同一件事放在Controller上,并使用filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes应用于所有操作。
Daryl Teo

4
后API溶液语法任何人是稍有不同:actionContext.ActionDescriptor.GetCustomAttributes <SkipMyGlobalActionFilter>()任何()。
AKD

而且,如果您还想跳过特定的控制器属性,则应添加||。在条件filterContext.ControllerContext.ControllerDescriptor.GetCustomAttributes <SkipMyGlobalActionFilter>()。Any()中
akd

3
如Leniel所写,在ASP.NET Core中,filterContext.ActionDescriptor没有GetCustomAttributes方法。如何在ASP.NET Core中做到这一点?
ashilon's

19

您还可以执行此出色文章中描述的操作:

排除过滤器

只需先实现一个自定义ExcludeFilterAttribute,然后再实现一个自定义即可ExcludeFilterProvider

干净的解决方案,对我来说很棒!


1
有什么类似的解决方案适用于ASPNET Core?
smg

1
@smg,请参见下面的@gt答案
Ali Hasan

链接断开。它应该在此处提供示例代码
diegosasw

10

虽然,达林·迪米特洛夫(Darin Dimitrov)接受的答案很好,而且效果很好,但对我而言,这里建立的最简单,最有效的答案。

您只需要在逻辑开始之前向属性添加一个布尔属性并对其进行检查:

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

然后按5%的操作使用,如下所示:

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

我在这里注意到一个小“陷阱”-如果您在过滤器的全局声明中指定了Order,则还必须在属性上指定相同的顺序。EG[DataAccessAttribute(Disable=true,Order=2)]filters.Add(new DataAccessAttribute(), 2);
乔恩总动员

8

在AspNetCore中,@ darin-dimitrov接受的答案可以进行如下修改:

首先,IFilterMetadata在marker属性上实现:

public class SkipMyGlobalActionFilterAttribute : Attribute, IFilterMetadata
{
}

然后在上搜索Filters此属性的属性ActionExecutingContext

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

        // etc
    }
}

2

创建一个自定义的筛选器提供程序。写一个实现IFilterProvider的类。此IFilterProvider接口具有GetFilters方法,该方法返回需要执行的Filters。

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);
        }
}

=================================================== ===========================
在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

好吧,我认为我可以在ASP.NET Core中使用它。
这是代码:

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);
    }

相关代码在“ IsExcluded”方法中。


2

至少在今天,这很容易:从动作中排除所有动作过滤器,只需添加OverrideActionFiltersAttribute即可

其他过滤器也有类似的属性:OverrideAuthenticationAttributeOverrideAuthorizationAttributeOverrideExceptionAttribute

另请参阅https://www.strathweb.com/2013/06/overriding-filters-in-asp-net-web-api-vnext/


如今是2013年以上?不确定为什么这不是规范的可接受答案。
马丁·卡波迪奇

1

您可以这样更改过滤器代码:

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

并使用它:

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

2
这是一种方法,但是随着时间的推移很难维护。
zszep

1
如果您更改操作名称而忘记在属性用法中进行更改,则编译器不会警告您。这很可能引起维护麻烦。我喜欢Darin的答案,因为您不必手动指定操作。
Nashenas,2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.