紙殼CMS是一個開源免費的,可視化設計,線上編輯的內容管理系統。基於ASP .Net Core開發,插件式設計的CMS系統 ...
關於紙殼CMS
紙殼CMS是一個開源免費的,可視化設計,線上編輯的內容管理系統。基於ASP .Net Core開發,插件式設計:
GitHub:https://github.com/SeriaWei/ZKEACMS.Core
路由
路由是ASP .Net裡面至關重要的一個組成部分,路由的功能簡單的說就是把用戶請求的地址“轉移”到對應的Controller,Action。而路由,也是紙殼CMS可以自定義頁面的關鍵。
在紙殼CMS中,給路由定義了優先順序,所以在處理用戶請求地址的時候,通過路由的優先順序來決定訪問的流程走向,如果找到匹配的路由,則優先走該路由對應的 Controller -> Action -> View,如果沒有匹配的路由,則走路由優先權最低的“全捕捉”路由來處理用戶的請求,最後返迴響應。
優先順序最低的“全捕捉”路由是用來處理用戶創建的頁面。"{*path}",所有這些請求,都會到 PageController -> Main 進行處理。這樣就可以把原來真實的頁面,變為虛擬的,並由用戶來創建,存到資料庫中。請求流程,大致如下圖所示:
全捕捉路由和通用後臺路由的定義,Priority值越大,優先順序越高:
new RouteDescriptor { RouteName = "pageRoute", Template = "{*path}", Defaults = new { controller = "Page", action = "Main" }, Constraints = new { path = new PageRouteConstraint() }, Priority = -1 }, new RouteDescriptor { RouteName = "admin", Template = "admin/{controller=Dashboard}/{action=index}/{id?}", Defaults=new { module = "admin" }, Priority = 10 }
PageRouteConstraint
PageRouteConstraint,這裡並不是用來約束路由的,而是在這裡處理路由數據,要在這裡構建RouteData,所以看代碼,始終是返回true。
namespace ZKEACMS { public class PageRouteConstraint : IRouteConstraint { public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection) { var value = values[routeKey]; if (routeKey == "path" && value != null) { string path = "/" + value.ToString(); var routeDataProviders = httpContext.RequestServices.GetService<IEnumerable<IRouteDataProvider>>(); foreach (var item in routeDataProviders.OrderBy(m => m.Order)) { path = item.ExtractVirtualPath(path, values); } if (path.IsNullOrWhiteSpace()) { path = "/"; } values[routeKey] = path; } return true; } } }
紙殼CMS裡面使用IRouteDataProvider來自定義處理請求URL和RouteData。例如使用HtmlRouteDataProvider來實現偽靜態:
namespace ZKEACMS.Route { public class HtmlRouteDataProvider : IRouteDataProvider { const string htmlExt = ".html"; public int Order { get { return 0; } } public string ExtractVirtualPath(string path, RouteValueDictionary values) { if (path.EndsWith(htmlExt, StringComparison.OrdinalIgnoreCase)) { path = path.Substring(0, path.LastIndexOf(htmlExt)); } return path; } } }
使用PaginationRouteDataProvider來獲取分頁數據等等:
namespace ZKEACMS.Route { public class PaginationRouteDataProvider : IRouteDataProvider { public int Order { get { return 1; } } public string ExtractVirtualPath(string path, RouteValueDictionary values) { if (CustomRegex.PageRegex.IsMatch(path)) { int page = -1; path = CustomRegex.PageRegex.Replace(path, evaluator => { int.TryParse(evaluator.Groups[1].Value, out page); return string.Empty; }); if (page >= 0 && !values.ContainsKey(StringKeys.RouteValue_Page)) { values.Add(StringKeys.RouteValue_Page, page); } } return path; } } }
插件里路由
每個插件都可以定義自己的路由,所以一定要處理它們的優先順序關係。定義的方式很簡單,在插件類(xxxPlug.cs)裡面,實現RegistRoute方法就可以了。例如自定義表單插件裡面的提交數據路由:
namespace ZKEACMS.FormGenerator { public class FormPlug : PluginBase { public override IEnumerable<RouteDescriptor> RegistRoute() { yield return new RouteDescriptor { RouteName = "FormData", Template = "FormDataHandle/Submit", Defaults = new { controller = "FormData", action = "Submit" }, Priority = 11 }; } } }
最後
紙殼CMS充分利用了路由來實現自定義頁面的功能,而路由不再單純的只有{controller}/{action}。看了紙殼CMS的路由機制,我相信你應該會有所收穫,:-),歡迎有興趣的大神們加入進來!
https://github.com/SeriaWei/ZKEACMS.Core