You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 5 中如何动态更新路由表实现CMS自定义内容页路由

解决方案

.NET 5 已经移除了静态的RouteTable类,要实现动态内容路由,推荐以下两种实现方式:

方案一:动态路由匹配(优先推荐)

该方案不需要手动维护路由表,仅通过通配符路由匹配数据库记录,修改页面URL时只需更新数据库即可,实现成本极低,适合绝大多数CMS场景。

  1. 注册通配符路由,放在所有路由规则的最后:
app.UseEndpoints(endpoints =>
{
    // 原有路由规则,比如后台路由、默认控制器路由等
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
    
    // CMS内容页通配符路由,优先级最低,仅匹配未被其他路由命中的请求
    endpoints.MapControllerRoute(
        name: "cms-page",
        pattern: "{*url}",
        defaults: new { controller = "Home", action = "GetPage" });
});
  1. 改造控制器的页面处理逻辑:
public ActionResult GetPage(string url)
{
    // 处理首页空路径的情况
    url ??= string.Empty;
    // 根据请求路径查询对应内容页
    var page = pageService.GetPageByUrl(url);
    if (page == null)
    {
        return NotFound();
    }
    return View("index", page);
}

如果担心数据库查询性能,可以将URL和页面对应关系存入内存缓存,修改页面URL时同步更新缓存即可。

方案二:动态更新路由表

如果需要完全对齐旧框架的路由注册逻辑,每个页面单独注册路由,可以通过.NET Core的IActionDescriptorChangeProvider实现路由的动态重载:

  1. 实现路由变更通知类
public class CmsRouteChangeProvider : IActionDescriptorChangeProvider
{
    private CancellationTokenSource _cts = new();

    public IChangeToken GetChangeToken()
    {
        return new CancellationChangeToken(_cts.Token);
    }

    public void NotifyRouteChanged()
    {
        var oldCts = Interlocked.Exchange(ref _cts, new CancellationTokenSource());
        oldCts.Cancel();
        oldCts.Dispose();
    }
}
  1. 注册服务到容器
// Startup.cs ConfigureServices 中添加
services.AddSingleton<CmsRouteChangeProvider>();
services.AddSingleton<IActionDescriptorChangeProvider>(sp => sp.GetRequiredService<CmsRouteChangeProvider>());
  1. 实现动态路由数据源
public class CmsEndpointDataSource : EndpointDataSource
{
    private readonly IPageService _pageService;
    private readonly ActionDescriptor _getPageAction;

    public CmsEndpointDataSource(IPageService pageService, IActionDescriptorCollectionProvider actionProvider)
    {
        _pageService = pageService;
        // 预获取GetPage方法的Action描述符
        _getPageAction = actionProvider.ActionDescriptors.Items
            .First(a => a.RouteValues["controller"] == "Home" && a.RouteValues["action"] == "GetPage");
    }

    public override IReadOnlyList<Endpoint> Endpoints
    {
        get
        {
            var endpoints = new List<Endpoint>();
            var allPages = _pageService.GetAllPages();
            foreach (var page in allPages)
            {
                var routePattern = RoutePatternFactory.Parse(page.Url.TrimStart('/'));
                var builder = new RouteEndpointBuilder(
                    async context =>
                    {
                        context.Request.RouteValues["guid"] = page.Id.ToString();
                        var invoker = context.RequestServices.GetRequiredService<IActionInvokerFactory>()
                            .CreateInvoker(new ActionContext(context, new RouteData(), _getPageAction));
                        await invoker.InvokeAsync();
                    },
                    routePattern,
                    1
                );
                builder.Metadata.AddRange(_getPageAction.EndpointMetadata);
                endpoints.Add(builder.Build());
            }
            return endpoints;
        }
    }

    public override IChangeToken GetChangeToken()
    {
        return _getPageAction.GetChangeToken();
    }
}

注册该数据源:

services.AddSingleton<EndpointDataSource, CmsEndpointDataSource>();
  1. 页面URL更新后触发路由重载
// 页面URL更新的业务逻辑中
public void UpdatePageUrl(Guid pageId, string newUrl)
{
    // 更新数据库记录
    _pageService.UpdatePage(pageId, new { Url = newUrl });
    // 触发路由重载
    _routeChangeProvider.NotifyRouteChanged();
}

调用NotifyRouteChanged后,框架会自动重新加载所有路由规则,实现路由表的动态更新。


内容的提问来源于stack exchange,提问作者Bimmie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 16:45:02