ASP.Net MVC路由 - 对不同的控制器使用相同的模式

时间:2009-07-24 00:19:44

标签: asp.net-mvc routing

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

产品:

  • 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-delicous-apple”或“apples”。

没有模式或正则表达式(我可以看到,无论如何),只允许我通过查看网址来确定它是否是产品或类别。我需要查看数据库才能知道。

有什么好方法可以解决这个问题?

  1. 在应用程序启动时,注册每个产品和类别的路径
  2. 创建一些处理请求的代码,并在数据库中查找slug
  3. ...
  4. 暂时不要使用缓存,刷新路由表等。 :)

    如果您觉得这个问题有更合适的标题,请随意编辑我的问题标题 - 这是我能想到的最佳标题。

4 个答案:

答案 0 :(得分:2)

我比#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();
    }
}
祝你好运!
-Mike

答案 1 :(得分: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的答案已经足够好了。

答案 2 :(得分:0)

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

    / product / id / 5或   /类别/ ID / 3

    也可以使用存储过程返回id以保存一次往返

答案 3 :(得分:0)

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

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

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

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

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

希望这有帮助。