我一直在开发一个纯粹的MVC CMS以获得乐趣,并且遇到了一个令人讨厌的错误/ ASP.NET路由功能。
CMS中的每个动态托管页面都与从数据库中提取的特定路由相关联。这些是在应用开始时加载的。当用户添加新页面或编辑现有页面的Url时,我需要能够编辑RouteTable以相应地插入/编辑路径。
问题是新路由不需要简单地添加到RouteCollection的末尾,而是可能需要插入到特定位置。除了RouteCollection仅包含从Insert(int idx, RouteBase route)
继承的标准Collection<T>
方法(不包含路由名称)外,似乎足够逻辑。路线的名称很重要,因为我一直使用它来生成动作链接。
查看反射器我无法看到扩展此集合的简单方法,因为_namedMap字典被标记为私有。我尝试在插入点切碎集合并再次重新添加每个项目,但是因为没有方法从RouteCollection反向查找路由的名称,所以我无法使用之前可能具有的名称重新添加它们。太令人沮丧了!!!
为什么路由的名称不是路由对象的属性? 为什么如果MS认真对待我们扩展MVC和路由,他们是否难以扩展关键类?
有关最佳解决方案的任何建议吗?
修改:
好吧也许我应该在这里更多更清楚。我不是在寻找对我的CMS设计的批评。我很欣赏这些评论,但这不是我要问的。
简化问题。如何在运行时将命名路径插入到路径集合中?类上的当前插入方法不足,因为它不包含名称。
干杯,
伊恩
答案 0 :(得分:0)
如果你看一下ClearItems()
方法,这应该提供一种清空路线的方法。如果您首先将路径集合移动到临时集合中(并在其中插入新路由),请运行ClearItems(),然后使用Add()
重新填充。
应该提到的是,您还应该使用GetReadLock()
和GetWriteLock()
,以避免应用程序中的潜在冲突。
答案 1 :(得分:0)
查看IRouteConstraint
界面。基本上你添加一个catch all all route在应用程序启动时添加集合的结尾,它将约束对象作为参数。在这里,如果传入的URL与有效页面匹配,然后返回true或false,您将在CMS中查找,这将指示路由框架是否应该考虑传入请求的路由
public interface IRouteConstraint
{
bool Match(HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection);
}
http://msdn.microsoft.com/en-us/library/system.web.routing.irouteconstraint.aspx
定义类必须实现的合约,以检查URL参数值是否对约束有效。
答案 2 :(得分:-2)
简答:您不会动态插入路线。什么时候改变它们,需要从头开始重建。这有几个原因,最重要的是确保路由系统不是您的应用程序的瓶颈。本质上,路由集意图是映射大量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中未覆盖参数,则参数提供默认值。这意味着空白网址始终与ManagedPageController.Details("Home")
匹配。如果您想编辑页面,URL可能看起来像“我吃菠菜/编辑”。
“id”参数有一些警告,它与MVC试图拯救你的禁用字符有关。如果强制页面名称永远不包含这些禁用字符,那么问题就会少得多。