【问题标题】:MVC3 Route Contraints distinction between parametersMVC3 Route Contraints 参数之间的区别
【发布时间】:2012-03-07 18:44:22
【问题描述】:

对于我的网站,我正在从 xml(-nodes) 动态建立链接。碰巧大多数时候,productdetails 的链接是这样建立的:

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

在某些情况下,第四个节点之后还有第五个节点,所以链接是:

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

如果它们都是字符串,我如何在我的操作方法中将这第五个“段”与 productdetail 区分开来?

public ActionResult Products(字符串一、字符串二、字符串三、字符串四、字符串productdetail、字符串五 = null) { }

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

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

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

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

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

这可能吗?

【问题讨论】:

  • 只有两条路线有什么问题?这应该可以正常工作
  • Aaron,然后它会将 me.com/one/two/three/four/five/ 的链接错误地映射到 me.com/one/two/three/four/productdetail...跨度>
  • 我编辑了我的答案,但基本上,如果两种模式相同,则框架无法区分路线。你需要使用一个约束来区分这个
  • ps,你应该接受一个答案和/或支持那些试图帮助你的人......我认为你的问题已经得到回答:)

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


【解决方案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}

如果不创建路由约束以确保 {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 方法中,并使用控制器路由值中的名称来查找操作。

【讨论】:

  • 我不明白这如何解决 OP 的问题。他有两个相同的模式。您列出的每个模式都有不同的参数计数,这是不正确的。
  • OP 在产品属性的数量不同 (1 - 5) 方面存在问题。他有一些工作可以允许四个属性,但不是第五个。通过按特定顺序设置路线(第 5 条路线,然后是 4 条路线,然后是 3 条路线,然后是 2 条路线),您最多可以允许 5 个参数。虽然我的路线缺少动作(我一定是在查看其他人的路线列表而不是 OP),但这个概念仍然适用。如果路由中存在该操作,则我的某些路由约束不适用,但如何创建路由约束并进行匹配的概念仍然适用。
  • IRouteConstraint 可以对路由集合中的任何参数进行条件检查,以查看 URL 是否匹配。 IRouteConstraint 可以区分 {five} 和 {productdetail},但您必须在 Match 方法中进行一些数据库验证。
  • 阅读他的cmets。他没有在他的问题中阐明问题。他本质上想要两条相同的路线,有和没有不同数量的参数。他也不能使用约束(他声称),因为没有明显的方法可以将两条路线与一个值区分开来。您的回答很好,它解决了部分问题,但实际上并没有解决这个基本问题。没有办法按照他的要求做:)
  • 他没有说他不能使用路由约束。他说“正则表达式的路由约束似乎没有帮助,因为它们都是字符串”,这就是为什么我向他展示了如何使用 IRouteConstraint,它能够在将 URL 中的值与路由进行比较以查看值是否为属性。他想做的事情可以做到,只是在“public bool Match”中创建逻辑来查看XML数据,以确定路由数据是否与XML Source中的数据匹配并返回true/false。
【解决方案2】:

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

让您的产品详细信息前面有一些特定的字符串,这些字符串永远不会出现在 1 到 5 个值中,例如:

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

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

这将解决您的问题。

【讨论】:

    【解决方案3】:

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

    1. 不要将 1 到 5 作为可选参数。
    2. MapRoot {controller}/{action}/{one}/{two}/{three}/{four}/{five}/{productdetail} 应该在 {controller }/{action}/{one}/{two}/{three}/{four}/{productdetail}
    3. 默认遵循 maproute。{controller}/{action}/{id} id 是可选的

    现在

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

    【讨论】:

    • 嗨,玛纳斯,这可行,但我还需要能够访问 me.com/one/two/three/four/five/ 以显示产品详细信息列表。编辑:我会在没有可选参数的情况下尝试它
    • EDIT2:没有可选参数,me.com/one/two/ 不匹配
    【解决方案4】:

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

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

    【讨论】:

    • 亚伦,感谢您的回答。所以说,如果我有一个名为“phone1”的productdetail,还有一个名为“phone1”的第五段,有没有办法区分路线? (正则表达式似乎对此毫无用处)。那我就得另辟蹊径了。这肯定是 MVC3 框架的一个陷阱然后......
    • 不用担心。要回答您的问题,请将自己置于框架之中。框架如何知道将您的请求定向到哪里?如果 url 模式相同,框架只是不知道选择两条路由中的哪一条。可能考虑改组你的 url,或者找到一种约束工作的方法
    猜你喜欢
    • 2018-04-21
    • 2017-07-22
    • 2013-01-04
    • 2011-03-11
    • 1970-01-01
    • 2010-12-12
    • 2013-10-21
    • 2016-11-28
    相关资源
    最近更新 更多