【问题标题】:ASP.Net MVC Routing - using same pattern for different controllersASP.Net MVC 路由 - 对不同的控制器使用相同的模式
【发布时间】:2009-07-24 00:19:43
【问题描述】:

假设我有一个包含产品和类别的 ASP.Net MVC 站点,我想要这些 url...

产品:

  • Fruitshop.com/super-tasty-apple
  • Fruitshop.com/squishy-orange
  • Fruitshop.com/worm-infested-apple
  • Fruitshop.com/megaorange

分类:

  • Fruitshop.com/apples
  • Fruitshop.com/oranges

对于数据库中的每个产品/类别,我都会保存 slug(或任何您称之为的名称),例如“super-delicious-apple”或“apples”。

没有模式或正则表达式(无论如何我都可以看到),这让我可以仅通过查看 url 来确定它是产品还是类别。我需要查看数据库才能知道。

解决这个问题的好方法是什么?

  1. 在应用启动时,注册每个产品和类别的路由
  2. 创建一些处理请求的代码,并在数据库中查找 slug
  3. ??

暂时不要介意缓存、刷新路由表等。 :)

如果您认为这个问题有更合适的标题,请随时编辑我的问题标题 - 这是我能想到的最好的标题。

【问题讨论】:

  • 尽管我已经提供了答案,但我必须诚实地说,这种 url 结构可能会让用户感到困惑,您甚至可能会发现 Google 无法正确抓取您的网站.如果此结构是由于将旧站点迁移到 .NET MVC 造成的,您应该考虑创建一个更易于阅读的新 url 结构(例如fruitshop.com/categories/apples 和fruitshop.com/products/megaorange )。然后我会在旧网址上设置 301 以指向新网址。

标签: asp.net-mvc routing


【解决方案1】:

比起#1,我更喜欢你的方法#2。我认为您可以通过创建一个转到 SlugController 中的 SlugHandler 操作的单个路由(或您想要调用的任何其他内容)而侥幸成功。为此,您只需要一条路线。

然后,您的 SlugHandler 操作将接受一个 slug 字符串,然后调用一个方法来确定该 slug 是一个类别还是一个产品。 (您确实说过这些是独一无二的,是吗?也就是说,不可能对产品和类别都有相同的 slug。)从那里,您可以调用适当的 Product 或 Category 操作方法,传递 slug 字符串。

一些代码片段如下:

internal enum SlugType
{
    Category,
    Product
}

private SlugType DetermineSlugTypeFromSlugName(string slug)
{
    // some database magic happens here to return appropriate SlugType
}

public ActionResult SlugHandler(string slug)
{
    SlugType slugType = DetermineSlugTypeFromSlugName(slug);
    switch (slugType)
    {
        case SlugType.Category:
            return Category(slug);
        case SlugType.Product:
            return Product(slug);
        default:
            return SomeErrorAction();
    }
}

祝你好运!
-迈克

【讨论】:

  • 此外,如果时间允许,您可以重新访问此代码并重写DetermineSlugTypeFromSlugName 以实现一些缓存,这样您就不需要一直访问数据库...
【解决方案2】:

以下是您可能希望执行选项 1 的方式:

在应用程序启动时,您可以转到数据库并返回所有类别。

从这里,您可以使用正则表达式构建路由...

//This has a route constraint in the form of the regex returned from GetMyCategories
routes.MapRoute("Categories", 
  "{category}",
  new { controller = "Product", action = "Category" },
  new { category = GetMyCategories() }
);

routes.MapRoute("Product", 
  "{product}",
  new { controller = "Product", action = "Product" }
);


string GetMyCategories()
{
  StringBuilder categoriesRegex = new StringBuilder("(");

  var categories = GetAllCategoriesFromDb();
  categories.ForEach(x=>categoriesRegex.AppendFormat("{0}|", x));
  categoriesRegex.Append(")");

  return categoriesRegex.ToString();
}

此解决方案的一个主要问题是,如果您向数据库添加新类别,您将需要重新启动应用程序以将正则表达式刷新到路由约束。

关于选项2,我认为Funka的回答已经足够好了。

【讨论】:

    【解决方案3】:
    1. 除非您有(比如少于 100 个)页面,否则不太可能。注册路由可能不是一个昂贵的操作,但考虑到你必须检查这些东西每次你有请求时,我是在浪费 cpu 时间。
    2. 是的,如果这样做,制作一个 HttpModule 来处理和重写 Url 将是最简单的。说,(例如,请求是fruitshop.com/oranges),您检查数据库中的橙子以查看它是类别还是产品(我认为存储过程可能有帮助),如果它们都不是,返回 404。如果是这样,请将 url 重写为对控制器友好的内容:

    /product/id/5 或 /category/id/3

    id也可以和存储过程一起返回,省去往返

    【讨论】:

      【解决方案4】:

      大约一个月前,我试图解决同样的问题。我确定的解决方案是使用UrlRewriter HttpModule 将url 重写为MVC url。这种映射的一个例子是

      <rewrite url="/super-tasty-apple" to="/apple/details/3" />
      

      我将这些网址保存在数据库中。当应用程序启动时,我从数据库中读取所有 url,并将映射写出到我的 web.config。我不是特别喜欢这样做,但是它解决了必须为每个请求查询数据库的问题。

      如果您的应用程序经常添加/编辑 url,那么这种方法可能不适合您。

      如果您决定尝试这种方法,那么 HttpModules 的顺序就变得很重要。 UrlRewriter 模块必须在 UrlRoutingModule 之前添加。

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-06-11
        • 1970-01-01
        • 2013-09-24
        • 2016-03-29
        • 2012-05-29
        • 2017-04-05
        • 2016-10-03
        • 2011-07-15
        相关资源
        最近更新 更多