Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Route always goes to the first maproute

I'm trying to create URIs that look a little something like this: http://hostname/mobile/en/controller/action for mobiles OR http://hostname/en/controller/action for desktop (non mobiles).

My Route table currently looks like this (Global.asax.cs)

        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Mobile", // Route name
            "mobile/{language}/{controller}/{action}/{id}", // URL with parameters
            new { language = "en", controller = "Route", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
            new { language = @"en|us" } // validation
        );
        routes.MapRoute(
            "Default", // Route name
            "{language}/{controller}/{action}/{id}", // URL with parameters
            new { language = "en", controller = "Route", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
            new { language = @"en|us" } // validation
        ); 

The problem occurs when I try to do a return RedirectToAction("Add", "User"); It always redirects the desktop browser from /en/User/List to /mobile/en/User/Add when I want it to go to /en/User/Add. The Mobile version works correctly but I believe this is because the first "Mobile" route is always been seen to be the route that matches even if it doesn't have /mobile/ at the start.

I'm trying to use the same Controller for both versions but am stuck at it always redirecting to the Mobile route. This means RedirectToRoute isn't prefect as I want dynamic routes.

Thanks for your help.

like image 797
Adrian Avatar asked Nov 05 '22 11:11

Adrian


1 Answers

The main issue is that the route-values you provide match both routes, which means it will take the first one (which is mobile).

You can manually select which route to use by redirecting to routes in stead of actions.

return RedirectToRoute("Mobile", new {
    language = "en", controller = "User", action = "Get", id = 20
});

for mobile or

return RedirectToRoute("Default", new {
    language = "en", controller = "User", action = "Get", id = 20
});

for your default route.

However, this leaves you with a new problem: obtaining the name of the current route. As seen in the example, referring to named routes is very well possible. Obtaining the name of the currently used route however seems to be impossible. Using a hack like looking at the current URI is obviously not desireable. Besides being ugly (a hack) it could also lead to a lot of code duplication.

There is however a possibility of adding values to the routes which can be easily obtained from your controller (or view):

routes.MapRoute(
    "Mobile", // Route name
    "mobile/{language}/{controller}/{action}/{id}", // URL with parameters
    new { routeName = "Mobile", language = "en", controller = "Route", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
    new { language = @"en|us" } // validation
);
routes.MapRoute(
    "Default", // Route name
    "{language}/{controller}/{action}/{id}", // URL with parameters
    new { routeName = "Default", language = "en", controller = "Route", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
    new { language = @"en|us" } // validation
);

Now from your code you can redirect to the current route by using the value provided from the route itself:

return RedirectToRoute(RouteData.Values["routeName"], new {
    language = "en", controller = "User", action = "Get", id = 20
});

Now if you want to make this completely fancy, you can even make an extension method out of this:

public static class ControllerExtensions {
    public static RedirectToRouteResult CustomRedirectToRoute(this Controller controller, string controllerName, string actionName, object routevalues) {
        return CustomRedirectToRoute(controller, controllerName, actionName, new RouteValueDictionary(routevalues));
    }

    public static RedirectToRouteResult CustomRedirectToRoute(this Controller controller, string controllerName, string actionName, RouteValueDictionary routevalues) {
        routevalues = routevalues ?? new RouteValueDictionary();
        routevalues.Add("controller", controllerName);
        routevalues.Add("action", actionName);
        return new RedirectToRouteResult(controller.RouteData.Values["routeName"] as string, routevalues);
    }
}

Hopefully this provides a nice solution to your problem!

like image 71
René Wolferink Avatar answered Nov 15 '22 00:11

René Wolferink