Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RedirectToRoute causes redirect loop

public ActionResult Logout()
{
    FormsAuthentication.SignOut();
    return RedirectToRoute("Home");
}

I expect this action to redirect the user to the homepage but instead, a redirect loop occurs (according to Chrome).

The aforementioned action belongs to a controller in the "admin" area as where the "Home" route is defined for the default area - I suspect this to be relevant.

Here is the route for good measure:

routes.MapRoute(
    "Home",
    "{controller}/{action}/{slug}",
    new { controller = "Posts", action = "Index", slug = UrlParameter.Optional },
    new[] { "GoBlog.Controllers" }
);

Update

Replacing the return statement with the following will cause the action to work as expected:

return RedirectToRoute("Home", (RouteTable.Routes["Home"] as Route).Defaults);

I want to know why this is the case. Ideally I can omit the (cumbersome) second argument.

like image 301
Caster Troy Avatar asked Jul 25 '14 05:07

Caster Troy


2 Answers

This issue is particular to the call RedirectToRoute(string) and your particular route:

routes.MapRoute(
    "Home",
    "{controller}/{action}/{slug}",
    new { controller = "Posts", action = "Index", slug = UrlParameter.Optional },
    new[] { "GoBlog.Controllers" }
);

What you expected was RedirectToRoute would populate your arbitrary route definition of {controller}/{action}/ with the route's defined defaults:

controller = "Posts", action = "Index"

But RedirectToRoute like all redirect methods, is a part of your controller, and uses your current Controller and Action as Default Values where ever possible. This is a "feature" of the ASP.NET MVC framework -- re-using routes to create new routes. This approach is valuable because your current Controller and Action are strong hints as to your intention.

A great example of this is RedirectToAction(string) which assumes your current instantiated Controller is the default.

Contrast this with:

return RedirectToRoute("Home", (RouteTable.Routes["Home"] as Route).Defaults);

Rather than directing the framework to use it's best guess about how to populate the ambiguous wild card route, you have specifically instructed the framework to use the Defaults from the RouteTable for "Home" route to construct a route and return it as a RouteObject.

like image 146
Dave Alperovich Avatar answered Sep 20 '22 14:09

Dave Alperovich


When you call RedirectToRoute(string)

This method converts the route name that is passed in routeName to a URL by using the RouteCollection.GetVirtualPath method.

where pass null as parameter RouteValueDictionary. So in this case this parameters was getting from current RequestContext with values for controller, action and etc, i.e. you get url like this

"{controller}/{action}/{slug}"
"Login/Logout/"

and got redirecting loop.

when you call

return RedirectToRoute("Home", (RouteTable.Routes["Home"] as Route).Defaults);

instead RedirectToRoute(string) used RedirectToRoute(String, RouteValueDictionary) and in RouteCollection.GetVirtualPath method you pass defaults values for that route.

like image 43
Grundy Avatar answered Sep 20 '22 14:09

Grundy