2010-11-17 70 views
4

我一直在開發純粹的MVC CMS以獲得樂趣,並且遇到了煩人的ASP.NET路由錯誤/功能。在ASP.NET路由中擴展RouteCollection

每個動態 CMS中的託管頁面與從數據庫中提取的特定路由相關聯。這些在應用程序啓動時加載。當用戶添加新頁面或編輯現有頁面的Url時,我需要能夠編輯RouteTable以相應地插入/編輯路由。

問題是,新路由不需要簡單地添加到RouteCollection的末尾,而是可能需要插入到特定位置。似乎符合邏輯,只是RouteCollection僅包含從Collection<T>繼承的標準Insert(int idx, RouteBase route)方法,該方法不包含路由名稱。路由的名稱非常重要,因爲我始終使用它來生成操作鏈接。

看着反射器我看不到一個簡單的方法來擴展這個集合,因爲_namedMap字典被標記爲私有。我嘗試在插入點切入集合並重新添加每個項目,但是因爲沒有方法從RouteCollection中反向查找路由名稱,所以我無法用它們之前可能已有的名稱重新添加它們。太令人沮喪了!

爲什麼路線的名稱不是路線對象的屬性? 爲什麼如果MS認真對待我們擴展MVC和路由,他們會使關鍵類難以擴展?

對此處最佳解決方案有何建議?

編輯:

好吧,也許我本來應該很多很多清晰的在這裏。我不是在尋找對我的CMS設計的批評。我很欣賞這些評論,但這不是我所要求的。

簡化的問題。我如何在運行時將命名路線插入路線集合中?該類上的當前插入方法不足,因爲它不包含名稱。

乾杯,

伊恩

+0

爲什麼你正確地將路由映射到託管頁面?您可能能夠簡化您的URL結構,以便您可以不斷重複使用獨立於託管頁面的相同路由。 – 2010-11-17 16:56:49

+0

@Berin:啊,是的。我沒有想到這一點。每頁一條路線確實是一個糟糕的設計。應該使用現有路線中的參數值來識別頁面。 – 2010-11-17 17:00:54

+0

我不是很清楚,例如我有一個託管的博客詳細信息頁面,其中包含post/{name}/{id}的url,我不必管理url解析。我有一個處理簡單的靜態URL的託管路由塊的結尾,所以它不是每頁一個路由,它的每個動態頁面+ 1的路由。我的問題依然存在。 – madcapnmckay 2010-11-17 17:32:59

回答

0

如果你看看ClearItems()方法,這應該提供一種方法來清空路由。如果您首先將路由集合移動到臨時集合中(並在其中插入新路由),請運行ClearItems(),然後使用Add()重新填充。

應該提到的是,您還應該使用GetReadLock()GetWriteLock()以避免應用程序中的潛在衝突。

+0

正確,但我會因此而失去所有現有路線的名稱信息。由於名稱信息存儲在private _namedMap字典中,因此它不是路由本身的一部分。需要的是一個Insert(名稱,RouteBase路由)方法。 – madcapnmckay 2010-11-18 11:22:01

+0

不是'RouteData.DataTokens'包含您可以簡單提取的信息嗎?更多信息 - http://stackoverflow.com/questions/363211 – 2010-11-18 11:27:36

-2

簡短的回答:你不插入路由動態。當需要改變它們時,他們需要從頭開始重建。這有幾個原因,最重要的是確保路由系統不是應用程序的瓶頸。基本上,這組路徑是,意圖是是映射大量URL的一組靜態資源。關於路由系統的一切都是在設計時考慮到的。

這是許多開發者的出發點,特別是來自基於文件的框架(如無路由WebForms項目)。它的確會迫使你以不同的方式思考URL。 http://en.wikipedia.org/wiki/Representational_State_Transfer


URL路由最近被Ruby on Rails的,這反過來又得到了從具象狀態傳輸(REST)一紙想法流行起來。這個概念在Rails之前就存在了,但它是一個延續到ASP.NET MVC的概念。

RESTful路由背後的原理是它們有一個共同的結構,只有某些部分發生變化。在您的應用程序中,它將是託管頁面的名稱。默認情況下,ASP.NET匹配這樣的路線:

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

這意味着該URL的一部分匹配,其中「{}控制器」字將被保存在「控制器」參數。與{action}和{id}一樣。這意味着,你可以有共同的邏輯管理的網頁是這樣的:

/Page/Details/I eat spinach 

這被映射如下:

  • 控制器=「頁面」(映射到的PageController類在你的控制器目錄)
  • 行動=「詳細資料」(映射到詳細方法上的PageController類)
  • 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 overidden。這意味着一個空白的URL總是與ManagedPageController.Details("Home")匹配。如果你想編輯頁面,URL可能看起來像「我吃菠菜/編輯」。

「id」參數有一些注意事項,它們與MVC試圖從中保存的禁止字符有關。如果強制頁面名稱不包含這些禁止使用的字符,那麼問題就會少得多。

+0

呃。感謝您的努力,但我很清楚路由如何工作。我的問題是如何動態地將路由插入到ASP.NET路由中的RouteCollection中。 – madcapnmckay 2010-11-17 18:35:34

+0

我的答案是,我相信你會讓它變得更加複雜而不是必要的。 – 2010-11-17 21:09:16

0

看看IRouteConstraint接口。基本上你添加一個catch所有的路由在應用程序啓動時添加集合的結尾,這以一個約束對象作爲參數。在這裏,你會在你的CMS查找如果傳入的URL匹配的有效頁面,然後返回true或false,這將指示路由框架的路徑是否應被視爲對傳入的請求或不

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參數值是否對約束​​有效。