繁体   English   中英

在ASP.NET路由中扩展RouteCollection

[英]Extending the RouteCollection in ASP.NET Routing

我一直在开发纯MVC CMS来娱乐,并且遇到了ASP.NET路由的烦人的bug /功能。

CMS中的每个动态托管页面都与从数据库中提取的特定路由相关联。 这些会在应用启动时加载。 当用户添加新页面或编辑现有页面的网址时,我需要能够编辑RouteTable以相应地插入/编辑路由。

问题在于新路线并不需要简单地添加到RouteCollection的末尾,而是可能需要将其插入特定位置。 除了RouteCollection仅包含从Collection<T>继承的不包含路由名的标准Insert(int idx, RouteBase route)方法外,似乎很合逻辑。 路线的名称很重要,因为在整个过程中都会使用它来生成操作链接。

看着反射器,因为_namedMap字典被标记为私有,所以我看不到扩展此集合的简单方法。 我尝试在插入时将集合切碎,然后再次重新添加每个项目,但是由于没有方法可以从RouteCollection中反向查找路由的名称,因此我无法使用以前可能使用的名称重新添加它们。 太令人沮丧了!!!

为什么路由名称不是路由对象的属性? 如果MS认真对待我们扩展MVC和路由,为什么它们使关键类难以扩展?

关于最佳解决方案,这里有什么建议吗?

编辑:

好的,也许我应该在这里更加清楚。 我不是在批评我的CMS设计。 我感谢您的评论,但这不是我要的。

简化的问题。 如何在运行时将命名路由插入路由集合? 该类上的当前插入方法不足,因为它不包含名称。

干杯,

伊恩

如果您查看ClearItems()方法,则应该提供一种清空路由的方法。 如果您首先将路线集合移动到临时集合中(并在其中插入新路线),请运行ClearItems(),然后使用Add()重新填充。

应该提到的是,还应使用GetReadLock()GetWriteLock()以避免应用程序中潜在的冲突。

查看IRouteConstraint接口。 基本上,您添加一个catch all路由,并在应用程序启动时添加集合的末尾,这将约束对象作为参数。 在这里,如果传入的URL匹配有效页面,您将在CMS中进行查找,然后返回true或false,这将指示路由框架是否应考虑传入请求的路由

public interface IRouteConstraint
{
  bool Match(HttpContextBase httpContext, 
    Route route, 
    string parameterName, 
    RouteValueDictionary values, 
    RouteDirection routeDirection);
}

http://msdn.microsoft.com/zh-CN/library/system.web.routing.irouteconstraint.aspx

定义一个类必须执行的协定,以检查URL参数值对于约束是否有效。

简短的答案:您不会动态插入路由。 当需要更改它们时,需要从头开始重建它们。 造成这种情况的原因有很多,其中大多数与确保路由系统不成为应用程序的瓶颈有关。 本质上,这组路由旨在成为映射大量URL的一小部分静态资源。 关于路由系统的所有设计都考虑到了这一点。

对于许多开发人员而言,这是一个偏离,特别是来自基于文件的框架(如无路由WebForms项目)。 它确实迫使您对URL进行一些不同的思考。


URL路由最近在Ruby on Rails上变得流行,后者又从有关代表性状态转移(REST)的论文中得到了这个想法: http : //en.wikipedia.org/wiki/Representational_State_Transfer 该概念在Rails之前就已存在,但它已被继承到ASP.NET MVC。

RESTful路由的原理是它们具有通用的结构,只是某些部分发生了变化。 在您的应用程序中,它将是托管页面的名称。 默认情况下,ASP.NET匹配您的路由,如下所示:

/{controller}/{action}/{id}

这意味着,URL中与“ {controller}”单词匹配的部分将存储在“ controller”参数中。 与{action}和{id}相同。 这意味着您可以对托管页面具有如下通用逻辑:

/Page/Details/I eat spinach

映射如下:

  • controller =“ Page”(映射到Controllers目录中的PageController类)
  • action =“ Details”(映射到PageController类的Details方法)
  • id =“我吃菠菜”(作为“详细信息”操作的参数传递。

您的控制器代码将具有以下方法:

public ActionResult Details(string id)
{
    return View(db.FindPage(id));
}

有了这些基本知识,我们就不仅限于这种结构。 只要我们能够提供到正确的控制器,正确的操作的映射,并且可以通过id查找托管页面,我们就可以使URL成为我们想要的。 假设我们希望页面名称排在第一位,而动作则排在第二位,而我们根本不需要担心控制器。 我们将创建一条如下所示的路线:

routes.MapRoute(
    "ManagedPages",  // Route Name
    "{id}/{action}", // URL structure
    // Default route parameters
    new { controller = "ManagedPage", action = "Details", id = "Home" }
);

如果参数未在URL中覆盖,则提供默认值。 这意味着空白URL将始终与ManagedPageController.Details("Home")匹配。 如果您要编辑页面,则URL可能类似于“我吃菠菜/编辑”。

“ id”参数有一些警告,与MVC试图从中拯救您的禁止字符有关。 如果您强制页面名称从不包含这些禁止的字符,则问题将少很多。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM