Как выборочно отключить глобальный фильтр в ASP.Net MVC - PullRequest
68 голосов
/ 31 марта 2012

Я установил глобальный фильтр для всех своих действий контроллера, в котором я открываю и закрываю сеансы NHibernate. 95% этих действий требуют доступа к базе данных, а 5% - нет. Есть ли простой способ отключить этот глобальный фильтр на эти 5%. Я мог бы пойти другим путем и украсить только те действия, для которых нужна база данных, но это было бы гораздо больше работы.

Ответы [ 8 ]

134 голосов
/ 01 апреля 2012

Вы можете написать атрибут маркера:

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();
}
18 голосов
/ 24 мая 2012

Вы также можете сделать то, что описано в этом удивительном сообщении:

Исключить фильтр

Просто реализуйте пользовательский ExcludeFilterAttribute, а затем пользовательский ExcludeFilterProvider.

Чистое решение и отлично сработало для меня!

8 голосов
/ 16 мая 2018

Хотя принятый ответ Дарина Димитрова хорош и работает хорошо, но для меня самый простой и эффективный ответ основан на здесь .

Вам просто нужно добавить логическое свойствок вашему атрибуту и ​​проверьте его перед тем, как начнется ваша логика:

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();
}
2 голосов
/ 07 июня 2013

Создание собственного поставщика фильтров. Напишите класс, который будет реализовывать 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);
        }
}

=============================================== ==============================
В 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);
}
1 голос
/ 22 ноября 2018

В AspNetCore принятый ответ @ darin-dimitrov может быть адаптирован для работы следующим образом:

Сначала добавьте IFilterMetadata в атрибут маркера:

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
    }
}
1 голос
/ 20 февраля 2018

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

Существуют аналогичные атрибуты для других фильтров: OverrideAuthenticationAttribute , OverrideAuthorizationAttribute и OverrideExceptionAttribute .

См. Также https://www.strathweb.com/2013/06/overriding-filters-in-asp-net-web-api-vnext/

1 голос
/ 01 апреля 2012

Вы можете изменить код фильтра следующим образом:

 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"})]
0 голосов
/ 12 сентября 2017

Ну, я думаю, что он работает на 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.

...