[英]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
映射如下:
您的控制器代码将具有以下方法:
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.