ASP.NET MVC ActionFilter не препятствует работе других фильтров


Я везде читаю этот установочный контекст.Результат к ненулевому значению предотвратит запуск других фильтров в том же классе, но это не работает таким образом для меня. В результате возникает цикл перенаправления между двумя фильтрами:

Глобальный.asax, in Application_Start():

GlobalFilters.Filters.Add(new FilterA(), 1);
GlobalFilters.Filters.Add(new FilterB(), 2);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

FilterA:

public class FilterA : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (long thing that evaluates to true)
        {
            context.Result = new RedirectResult("~/Foo/Bar");
        }
    }
}

FilterB:

public class FilterB : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (...also true, but shouldn't run...)
        {
            context.Result = new RedirectResult("~/Foo/Baz");
        }
    }
}
Должно быть, я что-то упустил... Я пробовал запускать base.OnActionExecuting(context) как до, так и после того, как я установил результат, но это, кажется, не имеет значения.
1 3

1 ответ:

Это приводит к циклу перенаправления, вероятно, потому, что ваша логика в фильтрах не исключает запросов для "Foo/Bar" и "Foo/Baz". В основном установка результата на FilterA предотвращает запуск другого фильтра в этом запросе и возвращает перенаправление, но FilterB выполняется на следующем запросе после перенаправления.

Следующее работает для меня в новом приложении MVC5:

public class FilterA : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.RouteData.GetRequiredString("controller").Equals("account", StringComparison.CurrentCultureIgnoreCase) //long condition evaluating to true
            //logic controlling these filters dont apply to Foo/Bar and Foo/Baz
            && (!context.RouteData.GetRequiredString("controller").Equals("Foo", StringComparison.CurrentCultureIgnoreCase)
                || (!context.RouteData.GetRequiredString("action").Equals("Bar", StringComparison.CurrentCultureIgnoreCase)
                    && !context.RouteData.GetRequiredString("action").Equals("Baz", StringComparison.CurrentCultureIgnoreCase))
                )
            )
        {
            context.Result = new RedirectResult("~/Foo/Bar");
        }
    }
}

public class FilterB : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (true /*long condition evaluating to true*/
            //logic controlling these filters dont apply to Foo/Bar and Foo/Baz
            && (!context.RouteData.GetRequiredString("controller").Equals("Foo", StringComparison.CurrentCultureIgnoreCase)
                || (!context.RouteData.GetRequiredString("action").Equals("Bar", StringComparison.CurrentCultureIgnoreCase)
                    && !context.RouteData.GetRequiredString("action").Equals("Baz", StringComparison.CurrentCultureIgnoreCase))
                )
            )
        {
            context.Result = new RedirectResult("~/Foo/Baz");
        }
    }
}

Я добавил некоторую логику (возможно, вы захотите ее рефакторировать) для обоих фильтров, которые удостоверяются, что текущий контроллер не является контроллером Foo, или в случае, если текущий контроллер является Foo, то действия могут отличаться от Bar и Baz.

Это должно предотвратить цикл, в котором фильтр FilterA перенаправляет на ~/Foo/Bar, затем новый запрос перехватывается FilterB, который перенаправляет на ~/Foo/Baz, который будет снова перехвачен FilterA и так далее.

В качестве примера, если вы создадите новое приложение MVC5 с этими фильтрами, если вы перейдете к ~/, вы перенаправлены на ~/Foo/Bar через FilterA. Однако если вы перейдете к ~/Account/Login, вы будете перенаправлены на ~/Foo/Baz по FilterB.

Надеюсь, это поможет!