سؤال

I read everywhere that setting context.Result to a non-null value will prevent other filters in the same class from running, but it doesn't work this way for me. The following results in a redirect loop between the two filters:

Global.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");
        }
    }
}

I must be missing something... I've tried running base.OnActionExecuting(context) both before and after I set Result, but it doesn't seem to matter.

هل كانت مفيدة؟

المحلول

This results in a redirect loop probably because your logic in the filters is not excluding requests for "Foo/Bar" and "Foo/Baz". Basically setting the result on FilterA is preventing the other filter from running in that request and returning a redirect, but FilterB is getting executed on the next request after the redirect.

The following works for me in a new MVC5 application:

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

I have added some logic (you may probably want to refactor it) to both filters that makes sure that the current controller is not the Foo controller, or in case the current controller is Foo then the actions may be different from Bar and Baz.

This should prevent a loop where the filter FilterA redirects to ~/Foo/Bar, then the new request is intercepted by FilterB that redirects to ~/Foo/Baz which will be intercepted again by FilterA and so on.

As an example, if you create a new MVC5 application with those filters, if you go to ~/, you are redirected to ~/Foo/Bar by FilterA. However if you go to ~/Account/Login, you are redirected to ~/Foo/Baz by FilterB.

Hope it helps!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top