来自 ASP.NET MVC CMS 数据库的动态路由
Posted
技术标签:
【中文标题】来自 ASP.NET MVC CMS 数据库的动态路由【英文标题】:Dynamic Routes from database for ASP.NET MVC CMS 【发布时间】:2013-04-08 05:34:17 【问题描述】:基本上我有一个使用 ASP.NET MVC 构建的 CMS 后端,现在我要转到前端站点,并且需要能够根据输入的路径从我的 cms 数据库中加载页面。
因此,如果用户输入 domain.com/students/information,MVC 将在 pages 表中查看是否存在具有与学生/信息匹配的永久链接的页面,如果存在,它将重定向到页面控制器,然后从数据库中加载页面数据并返回给视图显示。
到目前为止,我已经尝试了一条包罗万象的路线,但它只适用于两个 URL 段,即 /students/information,但不适用于 /students/information/fall。我在网上找不到任何关于如何做到这一点的信息,所以我想在这里问一下,在我找到并开源 ASP.NET MVC cms 并剖析代码之前。
这是我目前的路线配置,但我觉得有更好的方法来做到这一点。
public static void RegisterRoutes(RouteCollection routes)
routes.IgnoreRoute("resource.axd/*pathInfo");
// Default route to handle core pages
routes.MapRoute(null,"controller/action/id",
new action = "Index", id = UrlParameter.Optional ,
new controller = "Index"
);
// CMS route to handle routing to the PageController to check the database for the route.
var db = new MvcCMS.Models.MvcCMSContext();
//var page = db.CMSPages.Where(p => p.Permalink == )
routes.MapRoute(
null,
"*.",
new controller = "Page", action = "Index"
);
如果有人能指出我将如何从数据库加载 CMS 页面(最多三个 URL 段)并且仍然能够加载具有预定义控制器和操作的核心页面的正确方向。
【问题讨论】:
【参考方案1】:您可以使用约束来决定是否覆盖默认路由逻辑。
public class CmsUrlConstraint : IRouteConstraint
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
var db = new MvcCMS.Models.MvcCMSContext();
if (values[parameterName] != null)
var permalink = values[parameterName].ToString();
return db.CMSPages.Any(p => p.Permalink == permalink);
return false;
在路由定义中使用它,例如,
routes.MapRoute(
name: "CmsRoute",
url: "*permalink",
defaults: new controller = "Page", action = "Index",
constraints: new permalink = new CmsUrlConstraint()
);
routes.MapRoute(
name: "Default",
url: "controller/action/id",
defaults: new controller = "Home", action = "Index", id = UrlParameter.Optional
);
现在,如果您在“页面”控制器中有一个“索引”操作,例如,
public ActionResult Index(string permalink)
//load the content from db with permalink
//show the content with view
-
所有 url 都会被第一条路由捕获并通过约束进行验证。
如果永久链接存在于 db 中,则 url 将由页面控制器中的 Index 操作处理。
如果不是,约束将失败并且 url 将回退到默认路由(我不知道您在项目中是否有任何其他控制器以及您将如何决定您的 404 逻辑)。
编辑
为了避免在Page
控制器的Index
动作中重新查询cms页面,可以使用HttpContext.Items
字典,比如
在约束中
var db = new MvcCMS.Models.MvcCMSContext();
if (values[parameterName] != null)
var permalink = values[parameterName].ToString();
var page = db.CMSPages.Where(p => p.Permalink == permalink).FirstOrDefault();
if(page != null)
HttpContext.Items["cmspage"] = page;
return true;
return false;
return false;
然后在行动中,
public ActionResult Index(string permalink)
var page = HttpContext.Items["cmspage"] as CMSPage;
//show the content with view
希望这会有所帮助。
【讨论】:
非常感谢,我会试试这个并标记为答案,如果它有效。 :) 太棒了,它工作得很好,只需要添加一个检查 if (values[parameterName] != null),但其他方面完美!谢谢你:) 你好@shakib,如果有 50K 个项目,性能如何。据我所知,有一个路由表缓存或类似的东西,但无论如何它都会从数据库中检查。 @BarbarosAlp 正如你所说的“无论如何它都会从数据库中检查”,我能想到的最好的方法就是优化数据库查询。 @jallen 已经有一段时间了,但是您可以使用HttpContext.Items
字典来避免在操作中重新查询cms 页面。【参考方案2】:
我使用不需要任何自定义路由器处理的更简单的方法。 只需创建一个处理一些可选参数的单个/全局控制器,然后根据需要处理这些参数:
//Route all traffic through this controller with the base URL being the domain
[Route("")]
[ApiController]
public class ValuesController : ControllerBase
//GET api/values
[HttpGet("a1?/a2?/a3?/a4?/a5?")]
public ActionResult<IEnumerable<string>> Get(string a1 = "", string a2 = "", string a3 = "", string a4 = "", string a5 = "")
//Custom logic processing each of the route values
return new string[] a1, a2, a3, a4, a5 ;
domain.com/test1/test2/test3 上的示例输出
["test1","test2","test3","",""]
【讨论】:
以上是关于来自 ASP.NET MVC CMS 数据库的动态路由的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET MVC 的 Piranha CMS 路由问题
从零开始实现ASP.NET Core MVC的插件式开发 - 使用ApplicationPart动态加载控制器和视图