2010-06-23 69 views
5

我想创建看起来有点像这样的URI: http://hostname/mobile/en/controller/action手机或http://hostname/en/controller/action桌面(非手机)。路由总是去第一个maproute

我的路由表目前看起来像这样(的Global.asax.cs),当我尝试做一个 return RedirectToAction("Add", "User"); 它时,我想从/en/User/List桌面浏览器总是重定向到/mobile/en/User/Add发生

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

问题它要去/en/User/Add。 移动版本可以正常工作,但我相信这是因为第一个“移动”路线始终被视为匹配的路线,即使它在开始时没有/ mobile /。

我试图使用相同的控制器两个版本,但我坚持它总是重定向到移动路线。这意味着RedirectToRoute不是完美的,因为我想要动态路线。

感谢您的帮助。

回答

2

主要问题是您提供的路由值与两个路由匹配,这意味着它将采用第一个路由(即移动路由)。

您可以通过重定向到路由而不是操作来手动选择要使用的路由。

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

移动或

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

您的默认路由。

但是,这会给您带来一个新问题:获取当前路线的名称。如示例所示,提及的命名路线非常有可能。 然而,获得当前使用路线的名称似乎是不可能的。显然不希望使用像查看当前URI那样的黑客攻击。除了丑陋(黑客)之外,它还可能导致大量代码重复。

然而,有添加值,其可以从控制器(或视图)可以容易地获得的路由的可能性:

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

现在从你的代码可以通过使用值重定向到当前路线从路由本身提供:

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

现在,如果你想这完全看中了,你甚至可以提出延期方法出这一点:

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

希望这能为您的问题提供一个很好的解决方案!

+0

非常感谢René,看起来就像我希望做的一样。 你能告诉我哪里最好的地方是把扩展方法? – Adrian 2010-06-28 09:08:04

+1

将静态类ControllerExtensions放置在您想要的任何位置。在控制器中,您想要使用重定向,请确保包含扩展类所在的名称空间。然后,在控制器中的任何位置,可以使用this.CusomRedirectToRoute(“Home”,“Index”,routeValues); 如果需要,还可以添加另一个将null作为routeValues值的扩展方法。 – 2010-06-30 12:32:49

+0

如果你想整理它,我的评论的后半部分可以用整洁干净的系统来取代这个帖子中描述的路线名称:http://stackoverflow.com/questions/363211/how - 可以-I-GET-的路线名称,在控制器功能于ASP净MVC – 2010-06-30 20:44:38