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

.NET Core 6 MVC中CMS动态路由实现方案咨询

.NET Core 6 MVC类CMS网站动态路由实现方案

需求回顾

需要构建前后端均为.NET Core 6 MVC的类CMS系统,实现以下动态路由能力:

  • 后端创建/更新页面时,前端站点自动注册对应路由
  • 前端视图可通过路由名称生成页面链接
  • 页面Slug修改时,前端路由可实时更新

可行方案

方案1:自定义路由约束+缓存映射

这是最轻量化的实现方式,无需复杂的路由扩展:

  1. 注册通用基础路由
    在前端站点的Program.cs中注册一个匹配任意Slug的路由:
    app.MapControllerRoute(
        name: "cms-page",
        pattern: "{*slug}",
        defaults: new { controller = "Page", action = "Detail" }
    );
    
  2. 实现自定义路由约束
    创建实现IRouteConstraint的约束类,在匹配逻辑中从缓存读取页面Slug与PageId的映射关系,验证请求Slug是否有效,并注入PageId到路由值:
    public class CmsPageRouteConstraint : IRouteConstraint
    {
        private readonly IMemoryCache _cache;
        private readonly IPageService _pageService;
        private const string CacheKey = "CmsPageSlugMap";
    
        public CmsPageRouteConstraint(IMemoryCache cache, IPageService pageService)
        {
            _cache = cache;
            _pageService = pageService;
        }
    
        public bool Match(HttpContext? httpContext, IRouter? route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
        {
            if (!values.TryGetValue("slug", out var slugValue) || slugValue is not string slug)
                return false;
    
            var slugMap = _cache.Get<Dictionary<string, int>>(CacheKey) ?? RefreshSlugMap();
            if (slugMap.TryGetValue(slug, out var pageId))
            {
                values["id"] = pageId;
                return true;
            }
            return false;
        }
    
        private Dictionary<string, int> RefreshSlugMap()
        {
            var pages = _pageService.GetAll();
            var slugMap = pages.ToDictionary(p => p.Url, p => p.PageId);
            _cache.Set(CacheKey, slugMap, TimeSpan.FromMinutes(5));
            return slugMap;
        }
    }
    
    然后修改基础路由,添加约束:
    app.MapControllerRoute(
        name: "cms-page",
        pattern: "{*slug:cmsPage}",
        defaults: new { controller = "Page", action = "Detail" }
    );
    // 注册约束
    services.Configure<RouteOptions>(options =>
    {
        options.ConstraintMap.Add("cmsPage", typeof(CmsPageRouteConstraint));
    });
    
  3. 动态更新路由
    后端修改页面Slug时,调用前端站点的API接口,触发缓存刷新:
    // 前端站点的刷新接口示例
    [HttpPost("refresh-slug-map")]
    public IActionResult RefreshSlugMap()
    {
        _cache.Remove("CmsPageSlugMap");
        return Ok();
    }
    
  4. 生成页面链接
    在Razor视图中,直接通过Slug生成链接:
    @foreach (CmsPage page in Pages)
    {
        <a href="@Url.Action("Detail", "Page", new { slug = page.Url })">@page.Title</a>
    }
    

方案2:自定义动态路由提供程序

适合需要保留原ASP.NET MVC中命名路由特性的场景:

  1. 实现IDynamicRouteProvider
    引用Microsoft.AspNetCore.Mvc.Routing包,实现动态路由提供程序,从数据库读取页面信息注册路由:
    public class CmsDynamicRouteProvider : IDynamicRouteProvider
    {
        private readonly IPageService _pageService;
    
        public CmsDynamicRouteProvider(IPageService pageService)
        {
            _pageService = pageService;
        }
    
        public void PopulateDynamicRoutes(DynamicRouteProviderContext context)
        {
            var pages = _pageService.GetAll();
            foreach (var page in pages)
            {
                context.Routes.Add(new Route(
                    new MvcRouteHandler(),
                    page.Url,
                    new RouteValueDictionary(),
                    new RouteValueDictionary(),
                    new RouteValueDictionary(new { controller = "Page", action = "Detail", id = page.PageId }),
                    null,
                    $"page-{page.PageId}"
                ));
            }
        }
    }
    
  2. 注册服务
    在Program.cs中注册该提供程序:
    services.AddSingleton<IDynamicRouteProvider, CmsDynamicRouteProvider>();
    
  3. 动态更新路由
    可以通过后台定时任务刷新路由,或者在后端更新页面时,通过消息队列通知前端站点重新加载路由:
    // 示例:通过IHostApplicationLifetime触发路由刷新
    public async Task RefreshRoutes(IHostApplicationLifetime lifetime)
    {
        // 可结合轻量配置刷新逻辑,避免重启站点
        lifetime.ApplicationStopping.Reset();
        // 重新加载路由逻辑
    }
    
  4. 生成页面链接
    沿用原ASP.NET MVC的方式,通过路由名称生成链接:
    @foreach (CmsPage page in Pages)
    {
        <a href="@Url.RouteUrl($"page-{page.PageId}")">@page.Title</a>
    }
    

方案3:自定义EndpointDataSource

适合需要完全控制端点生命周期的场景:

  1. 实现自定义EndpointDataSource
    该类负责从数据库读取页面信息生成Endpoint,并支持动态刷新:
    public class CmsEndpointDataSource : EndpointDataSource
    {
        private readonly IPageService _pageService;
        private List<Endpoint> _endpoints = new();
        private readonly object _lock = new();
    
        public CmsEndpointDataSource(IPageService pageService)
        {
            _pageService = pageService;
            RefreshEndpoints();
        }
    
        public void RefreshEndpoints()
        {
            lock (_lock)
            {
                var pages = _pageService.GetAll();
                _endpoints = pages.Select(page =>
                {
                    var routePattern = RoutePatternFactory.Parse(page.Url);
                    var endpoint = new RouteEndpoint(
                        context =>
                        {
                            context.Request.RouteValues["controller"] = "Page";
                            context.Request.RouteValues["action"] = "Detail";
                            context.Request.RouteValues["id"] = page.PageId;
                            return Task.CompletedTask;
                        },
                        routePattern,
                        0,
                        new EndpointMetadataCollection(new MvcActionEndpointMetadata()),
                        $"page-{page.PageId}"
                    );
                    return endpoint;
                }).ToList();
            }
            NotifyChanged();
        }
    
        public override IReadOnlyList<Endpoint> Endpoints => _endpoints;
    }
    
  2. 注册数据源
    在Program.cs中注册为单例:
    services.AddSingleton<EndpointDataSource, CmsEndpointDataSource>();
    
  3. 动态更新路由
    后端修改页面Slug时,调用前端站点的API触发RefreshEndpoints()方法,路由系统会自动感知端点变化:
    [HttpPost("refresh-endpoints")]
    public IActionResult RefreshEndpoints([FromServices] CmsEndpointDataSource dataSource)
    {
        dataSource.RefreshEndpoints();
        return Ok();
    }
    
  4. 生成页面链接
    同样支持通过路由名称生成链接,与方案2一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 17:05:41