asp.net-mvc 如何有选择地禁用 ASP.Net MVC 中的全局过滤器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9953760/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to disable a global filter in ASP.Net MVC selectively
提问by zszep
I have set up a global filter for all my controller actions in which I open and close NHibernate sessions. 95% of these action need some database access, but 5% don't. Is there any easy way to disable this global filter for those 5%. I could go the other way round and decorate only the actions that need the database, but that would be far more work.
我已经为我打开和关闭 NHibernate 会话的所有控制器操作设置了一个全局过滤器。这些操作中有 95% 需要一些数据库访问权限,但 5% 不需要。有没有什么简单的方法可以为那 5% 禁用这个全局过滤器。我可以反过来,只装饰需要数据库的操作,但这会做更多的工作。
回答by Darin Dimitrov
You could write a marker attribute:
您可以编写一个标记属性:
public class SkipMyGlobalActionFilterAttribute : Attribute
{
}
and then in your global action filter test for the presence of this marker on the 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
}
}
and then if you want to exclude some action from the global filter simply decorate it with the marker attribute:
然后如果你想从全局过滤器中排除一些动作,只需用标记属性装饰它:
[SkipMyGlobalActionFilter]
public ActionResult Index()
{
return View();
}
回答by Leniel Maccaferri
You can also do what's described in this awesome post:
您还可以执行这篇精彩文章中描述的操作:
Just implement a custom ExcludeFilterAttributeand then a custom ExcludeFilterProvider.
只需实现一个 custom ExcludeFilterAttribute,然后一个 custom ExcludeFilterProvider。
Clean solution and worked great for me!
干净的解决方案,对我很有用!
回答by Dr. MAF
Though, the accepted answer by Darin Dimitrov is fine and working well but, for me, the simplest and most efficient answer founded here.
虽然,Darin Dimitrov 接受的答案很好并且运行良好,但对我来说,最简单和最有效的答案在这里建立。
You just need to add a boolean property to your attribute and check against it, just before your logic begins:
您只需要在您的逻辑开始之前向您的属性添加一个布尔属性并检查它:
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.
}
}
Then at your 5% actions just use it like this:
然后在您的 5% 操作中,只需像这样使用它:
[DataAccessAttribute(Disable=true)]
public ActionResult Index()
{
return View();
}
回答by g t
In AspNetCore, the accepted answer by @darin-dimitrov can be adapted to work as follows:
在 AspNetCore 中,@darin-dimitrov 接受的答案可以调整为如下工作:
First, implement IFilterMetadataon the marker attribute:
首先,IFilterMetadata在标记属性上实现:
public class SkipMyGlobalActionFilterAttribute : Attribute, IFilterMetadata
{
}
Then search the Filtersproperty for this attribute on the ActionExecutingContext:
然后在Filters该属性上搜索该属性ActionExecutingContext:
public class MyGlobalActionFilter : IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (context.Filters.OfType<SkipMyGlobalActionFilterAttribute>().Any())
{
return;
}
// etc
}
}
回答by Swapnil
Create a custom Filter Provider. Write a class which will implement IFilterProvider. This IFilterProvider interface has a method GetFilters which returns Filters which needs to be executed.
创建自定义过滤器提供程序。编写一个将实现 IFilterProvider 的类。这个 IFilterProvider 接口有一个 GetFilters 方法,它返回需要执行的过滤器。
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);
}
}
=============================================================================
In Global.asax.cs
================================================== ============================
在 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);
}
回答by Natalya
You can change your filter code like this:
您可以像这样更改过滤器代码:
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
}
}
And use it:
并使用它:
[NHibernateActionFilter(new[] { "SkipFilterAction1 ", "Action2"})]
回答by Markus Wagner
At least nowadays, this is quite easy: to exclude all action filters from an action, just add the OverrideActionFiltersAttribute.
至少现在,这很容易:要从操作中排除所有操作过滤器,只需添加OverrideActionFiltersAttribute。
There are similar attributes for other filters: OverrideAuthenticationAttribute, OverrideAuthorizationAttributeand OverrideExceptionAttribute.
其他过滤器也有类似的属性:OverrideAuthenticationAttribute、OverrideAuthorizationAttribute和OverrideExceptionAttribute。
See also https://www.strathweb.com/2013/06/overriding-filters-in-asp-net-web-api-vnext/
另见https://www.strathweb.com/2013/06/overriding-filters-in-asp-net-web-api-vnext/
回答by ashilon
Well, I think I got it working for ASP.NET Core.
Here's the code:
好吧,我想我让它适用于 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);
}
The relevant code is in the 'IsExcluded' method.
相关代码位于“IsExcluded”方法中。

