MVC3 Route约束参数之间的区别

时间:2012-02-16 11:00:04

标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-routing

对于我的网站,我正在从xml(-nodes)动态构建链接。它发生在大多数情况下,产品详细信息的链接是这样构建的:

me.com/one/two/three/four/productdetail

在某些情况下,虽然第四个节点之后有第五个节点,但链接是:

me.com/one/two/three/four/five/productdetail

在我的行动方法中,如果它们都是字符串,我怎么能将这第五个'段'与productdetail区分开来?

public ActionResult Products(string one,string two,string 3,string four,string productdetail,string five = null) { }

我现在有这样定义的路线:

{controller} / {action} / {one} / {two} / {three} / {four} / {productdetail}

{控制器} / {行动} / {一个} / {2} / {3} / {4} / {5} / {产品详情}

(其中{one}到{five}是UrlParameter.Optional)

使用正则表达式的路由约束似乎没有帮助,因为它们都是字符串(并且它们都可以是非常相似的字符串)。

这甚至可能吗?

4 个答案:

答案 0 :(得分:1)

解决此问题的最简单方法是为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}

您无法为{controller} / {one} / {productdetail}注册路由,而无需创建路由约束以确保{one}不是{controller}的操作。

我强烈建议,如果你有哪些选项列表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方法中,并使用控制器的路径值中的名称来查找操作。

答案 1 :(得分:0)

通过两条独立的路线,一条有五个元素,另一条有四个元素,这些路线可以到达同一个地方。一个通过{五}而另一个没通过。

编辑:如果两种模式相同,那么唯一的方法是使用约束来区分不同的值。

答案 2 :(得分:0)

我认为您可以对路线声明进行一些更改以满足您的期望。

  1. 不要将一到五作为可选参数。
  2. MapRoot {controller} / {action} / {one} / {two} / {three} / {four} / {five} / {productdetail} 应该出现在 {controller } / {行动} / {一个} / {2} / {3} / {4} / {产品详情}
  3. 默认为maproute。 {controller} / {action} / {id} id为可选
  4. 现在

    1. me.com/one/two/three/four/five/productdetail 的请求将匹配 仅限第一条路线。
    2. me.com/one/two/three/four/productdetail 的请求将匹配 仅限第二条路线。

答案 3 :(得分:0)

如果在您的情况下,您无法设置路由约束,那么您最好的选择是更改您的路由,以便ASP.NET MVC可以确切知道哪个是您的产品详细信息参数,以避免任何混淆使用可选的{five}。

让您的产品详细信息前面有一些特定的字符串,这些字符串绝不会发生在一到五个值中,例如:

{controller}/{action}/{one}/{two}/{three}/{four}/p/{productdetail}

{controller}/{action}/{one}/{two}/{three}/{four}/{five}/p/{productdetail}

这将解决您的问题。