如何在任何级别的网址上使用属性路由定义可选参数?

时间:2015-08-26 19:42:52

标签: asp.net-mvc-routing

我再次提到我的愚蠢的MVC路由问题。 我正在创建一个电子商务项目,并坚持在路由的一个点。到目前为止,属性路由与以下URL一起正常工作 abc.com/Electronics/Audio/Portable Audio / iPods

的形式

Category / Subcategory / Subsubcategory / Types / productname {stuck here}

但是现在我需要显示产品名称,在这里我被卡住了。产品可以在任何级别。像

abc.com/Electronics/Apple iPod Nano
abc.com/Electronics/Audio/Apple iPod Nano
abc.com/Electronics/Audio/Portable Audio / Apple iPod Nano
abc.com/Electronics/Audio/Portable Audio / iPods / Apple iPod Nano

问题是如果我定义类别控制器如下:

 [Route("{category}/{productname?}")]
        public ActionResult Category(string category,string productname)
          {
                //code
           }

和子类别控制器如下

 [Route("{category}/{subcategory}/{productname?}")]
        public ActionResult Subcategory(string category,string subcategory,string productname)
          {
                //code
           }

等等...... 我收到模糊路由的错误,因为在单击子类别的链接后(如果没有产品名称),属性路由再次作为两个参数的条件路由到类别控制器。

那么如何区分这两个控制器呢?或者任何更好的想法总是受欢迎的,因为我几乎是路由和MVC的新手。

另外请告诉我们是否有任何想法可以严格定义要映射的控制器,无论参数是否匹配,但保持URL形式如上所述。

谢谢。

1 个答案:

答案 0 :(得分:0)

由于您的所有路段都是可选的,因此您的路线会重叠。

// This will match any URL with 1 or 2 segments
[Route("{category}/{productname?}")]

// This will match any URL with 2 or 3 segments
[Route("{category}/{subcategory}/{productname?}")]

无论您如何申报路线,路线顺序都很重要。但是,由于它们都会匹配一个包含2个网段的网址,因此第一次匹配总是获胜并且当您拥有2段网址时,其中一条路线将始终取消另一条路线并不重要

这种情况有6种方法:

  1. 确保所有路径都有不同数量的占位符细分。例如,{category}/{productname}{category}/{subcategory}/{productname}不会发生冲突。
  2. 将至少一个段声明为文字值而不是占位符。例如,Audio/{?productname}代替{category}/{?productname}
  3. 使用RegEx route constraint
  4. 使用custom route constraint
  5. 创建自定义RouteBase子类。见this example
  6. 使用诸如{*slug}之类的全能路由,然后在控制器或其中一个服务中处理您的URL逻辑。我认为这个选项是一个黑客,因为你基本上是抛弃窗口并管理控制器内部的URL逻辑而不是它所属的路由框架。
  7. 如果您事先知道您将拥有的子类别的最大数量,您可以使用单独的操作方法来处理每个段长度。

    [Route("{category}")]
    public ActionResult Category(string category)
    {
    
    }
    
    [Route("{category}/{subcategory1orProductName}")]
    public ActionResult CategorySubcategory1(string category, string subcategory1orProductName)
    {
        // Figure out here whether the last parameter is a subcategory or product name.
    }
    
    [Route("{category}/{subcategory1}/{subcategory2orProductName}")]
    public ActionResult CategorySubcategory1(string category, string subcategory1, string subcategory2orProductName)
    {
        // Figure out here whether the last parameter is a subcategory or product name.
    }
    

    但我们再一次将路由逻辑放入它不属于的控制器中。

    内置路由工具功能强大,可以处理各种场景。但是,他们特别擅长的一件事是将类别/子类别/ contentItem路由构建到未知数量的级别,您需要做一些额外的工作才能到达那里。

    在这种情况下,您最好的选择是

    1. 创建一组自定义路径约束(每个类别段,子类别段和产品段一个)作为过滤器来确定要匹配的路径。管理起来可能非常复杂。
    2. 为产品创建自定义RouteBase覆盖,为类别创建另一个覆盖。将URL段放入数据库表中。使用自联接表构建类别/子类别部件,并将其与类别控制器匹配。使用相同的自联接表来构建类别/子类别/产品,并将其与产品路径中的匹配。确保缓存这些网址,以便每个请求都不会访问数据库,因此当您要将其用于ActionLinks时,您的路由可以匹配传入的网址并重建网址。