解决此问题的最简单方法是为 5 ,4,3 和 2 参数注册路由。按此顺序注册它们。
{controller}/{one}/{two}/{three}/{four}/{five}/{productdetail}
{controller}/{one}/{two}/{three}/{four}/{productdetail}
{controller}/{one}/{two}/{three}/{productdetail}
{controller}/{one}/{two}/{productdetail}
如果不创建路由约束以确保 {one} 不是 {controller} 的操作,则无法为 {controller}/{one}/{productdetail} 注册路由。
我强烈建议,如果您有选项 1 - 5 的列表,您可以创建一个自定义路线约束来验证它们,这样您就不会意外匹配您不打算但您应该的路线我已经布置的上述路线是安全的。
创建 IRouteConstraint 并不困难。下面是我之前为路由约束编写的一些代码,它允许从特定控制器调用操作而无需指定控制器。一个例子是一个名为 Home 的控制器,它有一个“关于”的动作,这个约束将允许你调用 /about 而不是 /home/about。
它与您想要做的事情相关,因为它向您展示了如何在需要时进行一些验证以区分 {one} 和 {action}。
路由约束:
public class IsRootActionConstraint : IRouteConstraint
{
private List<string> _actions;
public IsRootActionConstraint(): this( "homecontroller")
{
}
public IsRootActionConstraint(string ControllerName)
{
Type _type = Assembly
.GetCallingAssembly()
.GetTypes()
.Where(type => type.IsSubclassOf(typeof(Controller)) && type.Name.ToLower() == ControllerName.ToLower())
.SingleOrDefault();
if (_type != null)
{
_actions = (from methods in _type.GetMethods() where typeof(ActionResult).IsAssignableFrom(methods.ReturnType) select methods.Name.ToLower()).ToList();
}
}
#region IRouteConstraint Members
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return _actions.Contains((values["action"] as string).ToLower());
}
#endregion
}
当您在 global.asax 中注册您的路线时:
routes.MapRoute(
"Home",
"{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { IsRootAction = new CAA.Utility.Constraints.IsRootActionConstraint() } // Route Constraint
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
在您的情况下,验证 {one} 与 {controller} 中的路由不匹配应该不会太难。您可以将反射代码移动到 Match 方法中,并使用控制器路由值中的名称来查找操作。