如何使用ASP.NET路由路由树形结构的URL?

时间:2010-05-22 23:10:04

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

我希望通过一些增强功能实现与this question非常相似的功能。

有一个ASP.NET MVC Web应用程序。

我有一棵实体树 例如,Page类具有名为Children的属性,类型为IList<Page>。 (Page类的实例对应于数据库中的一行。)

请注意,网站所有者可以随时添加新网页,或删除现有网页,网址也应反映这些更改。

我想为数据库中的每个Page分配一个唯一的网址 我使用名为Page的控制器处理PageController个对象。

示例网址

http://mysite.com/Page1/
http://mysite.com/Page1/SubPage/
http://mysite.com/Page/ChildPage/GrandChildPage/

你得到了照片 所以,我希望每个Page个对象都有自己的URL,这个URL等于其父URL和自己的名字。
除此之外,我还希望能够将单个Page映射到/(根)网址。

我想应用这些规则:

  1. 如果可以使用任何其他路由处理URL,或者指定URL中的文件系统中存在文件,请使用默认URL映射
  2. 如果虚拟路径提供程序可以处理URL,那就让它处理它
  3. 如果没有其他网址,请将其他网址映射到PageController
  4. 我还找到this questionalso this onethis one,但他们没有多大帮助,因为他们没有提供我前两点的解释。

    我看到以下可能的消息:

    • 为每个页面映射一个路线 这要求我在应用程序启动时遍历整个树,并在路由表的末尾添加完全匹配路由。
    • 我可以添加一个{*path}的路由并编写一个处理它的自定义IRouteHandler,但我看不出如何处理前两个规则,因为这个处理程序会到达处理一切。

    到目前为止,第一个解决方案似乎是正确的解决方案,因为它也是最简单的解决方案。但即使在这种情况下,我也不确定如何让PageController来处理请求。

    我真的很感激你对此的看法。

    提前谢谢!

    编辑: 我现在有时间检查我收到的每个答案的每个方面。我接受了尼尔的回答,因为他是一个提供关于事情如何运作的最佳解释的人。我也提出了所有其他答案,因为它们提供了很好的想法。

4 个答案:

答案 0 :(得分:3)

路线按照添加到集合的顺序进行处理。您可以在现有路由之后添加自定义路由,以确保它是最后一个有机会处理请求的路由。这将允许您在其之前添加现有文件(虚拟或其他)的路由,因此符合条件1和2。

默认情况下,MVC路由将在应用路由集合中存储的任何路由之前路由到现有文件;见http://msdn.microsoft.com/en-us/library/system.web.routing.routecollection.routeexistingfiles.aspx。 (对保罗的讽刺 - 见评论)。

要将请求路由到页面控制器,只需创建一个检查虚拟路径的自定义路由,如果它与数据库中页面的模式匹配,则返回RouteData。使用从虚拟路径中提取的适当值设置RouteData(例如,将Path键设置为/ Parent / Child / Grandchild),将控制器键设置为页面控制器名称(例如Page),并将操作设置为要执行的操作的名称(例如,显示)。应使用RouteData创建MvcRouteHandler(不确定这是否是正确的类名)。

要确保正确返回数据库驱动页面的URL,请覆盖GetVirtualPath( RequestContext, RouteValueDictionary )的{​​{1}}方法,并使用传入的路由值来确定这是否是数据库驱动的页面,如果是创建所需的虚拟路径数据(否则返回null)。

有关覆盖RouteBaseGetRouteData的帮助,请查看GetVirtualPathSystem.Web.Routing.RouteBase的反映源代码;之后谷歌就是你的朋友。

反向使用路由来确定给定控制器,操作和任何其他路由值的URL。您应该能够利用它来在请求它的上下文中构建页面的URL。

答案 1 :(得分:1)

一个不同的想法是使用T4(文本模板转换工具包)来读取您的孩子一次并生成Global.asax文件的内容。

编辑:基本上使用T4,您可以自动生成文本文件。例如,不是手动复制某些大型集合的项目并将其与某些特定上下文粘贴到文本文件(如INSERT INTO [MyTable] (Text) VALUES (@ItemText))中,而是可以让T4引擎读取集合并为您生成这些插入语句。它是静态的,不适用于运行时。

我发现Pro Entity Framework 4.0一书中提供了很好的介绍。

但如果你说你需要动态地进行,那么这可能不适合你。

答案 2 :(得分:1)

保存页面时,您知道自己的页面结构。因此,您可以为每个页面生成URL并将其保存到数据库记录中。然后,您可以使用{*path}规则并在数据库中找到完全匹配。此规则应该在您的规则定义中排在最后,因此您可以匹配其他路由。

例如,您的Page1没有父网页,网址为Page1。您的SubPage知道它是父母,所以它可以加强网址Page1/SubPage等。

答案 3 :(得分:1)

您可以使用"Page/{*path}"模式。然后,您可以通过在'/'上拆分字符串来分解路径并然后走,或者您可以使用Rarouš建议将[生成的]路径存储在数据库中并进行直接查找。

如果您使用Rarouš'方法,则必须在父路径更改时更新表中所有子项的路径条目。只需一次更新查询即可完成此操作。

我假设您要将您希望用于主页的页面映射到配置文件或表条目中的某个位置。您可以让主页控制器执行查找并返回要呈现的主页视图的内容(您可以使用共享视图,部分视图或调用页面控制器,以便不重复行为),或者你可以让它重定向到那个页面。

使用此技术,您可以拥有一个页面控制器和视图,以相同的方式处理所有这些页面。您的其他要求似乎由MVC框架自动处理。

您的路径如下:

http://mysite.com/Page/Page1/ 
http://mysite.com/Page/Page1/SubPage/ 
http://mysite.com/Page/Page/ChildPage/GrandChildPage/ 

您当然可以使用“Page”以外的前缀。