Как отключить глобальный фильтр в ASP.Net MVC выборочно


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

8 59

8 ответов:

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

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

и затем, если вы хотите исключить какое-либо действие из глобального фильтра, просто украсьте его атрибутом маркера:

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

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

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

просто реализовать пользовательский ExcludeFilterAttribute а потом обычай ExcludeFilterProvider.

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

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

=============================================================================
В Глобальном.асакс.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);
}

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

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

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

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

 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"})]

Ну, я думаю, что у меня это работает ASP.NET ядро.
Вот код:

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

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

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

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

лучший ответ на это предоставляется на другой вопрос:

MVC 3 GlobalFilters Exclude