.NET 7 MVC应用中如何注册自定义IRouter?
方案可行性与注册步骤
首先,在.NET 7 MVC中使用自定义IRouter完全符合你的需求,是正确的技术方案。你的场景需要动态解析路由(从数据库映射短ID到控制器/动作)、权限与时效校验,且要隐藏底层路由结构,这正是自定义路由的典型适用场景,没有思路问题。
注册自定义IRouter的步骤
1. 注册自定义路由服务
先将你的自定义IRouter实现类注册到依赖注入容器中(假设你的实现类名为ShortUrlRouter,依赖数据库上下文等服务):
builder.Services.AddScoped<ShortUrlRouter>();
2. 配置路由优先级
在Program.cs的路由配置环节,将自定义路由添加到路由集合的最前面(路由匹配按顺序执行,短URL路由需要优先匹配),再配置默认MVC路由:
var app = builder.Build(); // ...其他中间件配置(如静态文件、认证授权等)... app.UseRouting(); app.UseEndpoints(endpoints => { // 注入自定义路由并添加到路由集合 var shortUrlRouter = app.Services.GetRequiredService<ShortUrlRouter>(); endpoints.Routes.Add(shortUrlRouter); // 配置默认MVC路由 endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); });
自定义IRouter核心实现要点
确保你的RouteAsync方法完成以下关键逻辑:
public class ShortUrlRouter : IRouter { private readonly IRouter _defaultRouter; private readonly AppDbContext _dbContext; public ShortUrlRouter(IRouter defaultRouter, AppDbContext dbContext) { _defaultRouter = defaultRouter; _dbContext = dbContext; } public async Task RouteAsync(RouteContext context) { var shortId = context.HttpContext.Request.Path.Value.Trim('/'); // 跳过空路径或已有层级的路径,交给默认路由处理 if (string.IsNullOrEmpty(shortId) || shortId.Contains('/')) { await _defaultRouter.RouteAsync(context); return; } // 从数据库查询短ID对应的路由映射 var mapping = await _dbContext.ShortUrlMappings .FirstOrDefaultAsync(m => m.ShortId == shortId); if (mapping == null) { await _defaultRouter.RouteAsync(context); return; } // 校验访问时效与用户权限 if (mapping.ExpiresAt < DateTime.UtcNow || !IsAuthorized(context.HttpContext.User, mapping.AllowedRoles)) { context.HttpContext.Response.StatusCode = StatusCodes.Status403Forbidden; return; } // 设置路由数据,指向目标控制器与动作 context.RouteData.Values["controller"] = mapping.TargetController; context.RouteData.Values["action"] = mapping.TargetAction; // 如有必要,添加额外路由参数 // context.RouteData.Values["targetId"] = mapping.TargetId; // 交给默认路由处理后续请求 await _defaultRouter.RouteAsync(context); } // 实现GetVirtualPath方法,支持生成短URL(你已实现此部分,确保逻辑正确即可) public VirtualPathData GetVirtualPath(VirtualPathContext context) { // 你的短URL生成逻辑,比如根据控制器/动作反向生成短ID // 示例: if (context.Values.TryGetValue("controller", out var controller) && context.Values.TryGetValue("action", out var action)) { var mapping = _dbContext.ShortUrlMappings .FirstOrDefault(m => m.TargetController == controller.ToString() && m.TargetAction == action.ToString()); if (mapping != null) { return new VirtualPathData(this, $"/{mapping.ShortId}"); } } // 无匹配时返回null,交给默认路由生成URL return _defaultRouter.GetVirtualPath(context); } // 自定义权限校验方法 private bool IsAuthorized(ClaimsPrincipal user, string allowedRoles) { // 你的权限校验逻辑 if (string.IsNullOrEmpty(allowedRoles)) return true; return allowedRoles.Split(',').Any(role => user.IsInRole(role)); } }
注意事项
- 路由顺序:自定义短URL路由必须放在默认路由之前,否则会被默认路由抢先匹配。
- 性能优化:频繁查询数据库解析路由可能影响性能,建议添加缓存(如MemoryCache)存储短ID与路由映射的关系,定期更新缓存。
- 异常处理:在
RouteAsync中添加异常捕获,避免数据库查询异常导致整个路由系统崩溃。
内容的提问来源于stack exchange,提问作者Mats
相关产品推荐
相关产品推荐

