How to redirect from OnActionExecuting in Base Controller?
Asked Answered
D

4

205

I have tried two ways: Response.Redirect() which does nothing, as well as calling a new method inside of the Base Controller that returns an ActionResult and have it return RedirectToAction()... neither of these work.

How can I do a redirect from the OnActionExecuting method?

Dendro answered 9/7, 2010 at 16:47 Comment(0)
K
385
 public override void OnActionExecuting(ActionExecutingContext filterContext)
 {
    ...
    if (needToRedirect)
    {
       ...
       filterContext.Result = new RedirectResult(url);
       return;
    }
    ...
 }
Kennithkennon answered 9/7, 2010 at 16:51 Comment(13)
Instead of new RedirectResult(url) you could also use new RedirectToAction(string action, string controller). This may have been added to MVC after you posted your answer. Your solution put me on the right track anyway.Hobie
Wont this execute what is in your current action? Wouldn't this be a security flaw? Let's say there is a action that deletes a user routed by /Admin/Delete/4. If your condition is to check weither you are an admin, and redirect if not. The user 4 will be deleted, even if you end up redirected, correct?Grecism
@Grecism - OnActionExecuting happens first. If you set the context.Result, then the redirect happens before the action executes. (Verified by personal testing/debugging.)Starlastarlene
@Starlastarlene I never said it did. What I wasn't sure is if the action would still execute if the ActionExecutingContext result wasn't changed to a RedirectResult since you never actually tell him to avoid running it. You only fill the context's result. But I've tested and confirmed that setting this result WILL bypass running the action. So my previous comment was indeed wrong.Grecism
@Hobie Note, the assignment should be done to the method (without new) RedirectToAction: filterContext.Result = RedirectToAction(string action, string controller);Lucania
@Hobie I just wanted to add that you wouldn't new up the RedirectToAction. It's just filterContext.Result = RedirectToAction(..)Nahum
Thanks @Lucania for your comment. I agree. 'new' is not required.Hobie
The name 'RedirectToAction' does not exist in the current context??Dinger
@Grecism I tried this recently on MVC 5 and the action was being executed, even with the filterContext.Result set to redirect to some action. I blocked the action from being executed by following the action with a call to Dispose(). Both redirection occurred and the action was prevented. e.g filterContext.Result = RedirectToAction("Index", "Home"); Dispose(); //ImportantSugarcoat
@ReuelRamosRibeiro I would not suggest messing around with ASP.NET's life cycle by calling dispose. It may be work but definitely a code smell.Grecism
@Hobie won't RedirectToAction just re-call OnActionExecuting again? In other words, one redirect will cause two calls to OnActionExecuting which seems bad to me.Collenecollet
@KolobCanyon That may be true but I think that it's not necessarily a code smell. I can see scenarios where you'd consider encapuslating the call to RedirectToAction() in a different method which in turn is used in multiple places. This may help avoid code duplication in some scenarios. I've see this at several of our clients.Hobie
@Lucania Yes, you are quite right. new shouldn't be used. I don't intend to remove my comment, though, as it would destroy the flow of the conversation in the comments. I'm hoping this is the right thing to do.Hobie
I
62

It can be done this way as well:

filterContext.Result = new RedirectToRouteResult(
    new RouteValueDictionary
    {
        {"controller", "Home"},
        {"action", "Index"}
    }
);
Insalubrious answered 22/8, 2011 at 21:0 Comment(0)
P
41

Create a separate class,

    public class RedirectingAction : ActionFilterAttribute
    {
      public override void OnActionExecuting(ActionExecutingContext context)
      {
        base.OnActionExecuting(context);

        if (CheckUrCondition)
        {
            context.Result = new RedirectToRouteResult(new RouteValueDictionary(new
            {
                controller = "Home",
                action = "Index"
            }));
        }
      }
   }

Then, When you create a controller, call this annotation as

[RedirectingAction]
public class TestController : Controller
{
    public ActionResult Index()
    {
        return View();
    }
}
Pondweed answered 13/12, 2011 at 10:31 Comment(1)
I prefer this anonymous object for the RouteValueDictionary constructor as it mirrors the routing elsewhere in MVC. +1Relic
R
5

If the redirected controller inherit from the same baseController where we override the OnActionExecuting method cause recursive loop. Suppose we redirect it to login action of account controller, then the login action will call OnActionExecuting method and redirected to the same login action again and again

... So we should apply a check in OnActionExecuting method to check weather the request is from the same controller if so then do not redirect it login action again. here is the code:

protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
   try
   {
      // some condition ...
   }
   catch
   {
      if (filterContext.Controller.GetType() != typeof(AccountController))
      {
         filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary {
              { "controller", "Account" }, 
              { "action", "Login" } 
         });
      }
   }
}
Resplendent answered 1/7, 2016 at 6:36 Comment(1)
try { int CompanyId = UserContext.Company.CompanyId; } catch { if (filterContext.Controller.GetType() != typeof(AccountController)) { filterContext.Result = new RedirectToRouteResult( new RouteValueDictionary { { "controller", "Account" }, { "action", "Login" } }); } }Resplendent

© 2022 - 2024 — McMap. All rights reserved.