ASP.NET Core动态URL路由异常求助:控制器识别错误
ASP.NET Core 动态URL路由问题解决方案
问题根源
你当前的实现是在控制器的OnActionExecutionAsync过滤器中修改RouteData来切换控制器和动作,但这个阶段路由匹配已经完成,路由系统仍然认为当前请求匹配的是seourlparam路由(默认指向Home/Index)。修改RouteData只会改变后续执行的控制器动作,但不会更新路由系统的匹配记录,因此任何依赖路由匹配结果的操作(如生成URL、获取当前路由标识)都会沿用最初的Home/Index信息。
解决方案
方案一:使用动态路由(推荐,ASP.NET Core 3.0+)
通过MapDynamicControllerRoute在路由匹配阶段直接解析SEO URL,找到对应的控制器和动作,让路由系统直接识别正确的路由信息。
- 创建动态路由值转换器
public class SeoUrlTransformer : IDynamicRouteValueTransformer { private readonly YourDbContext _dbContext; public SeoUrlTransformer(YourDbContext dbContext) { _dbContext = dbContext; } public async ValueTask<RouteValueDictionary> TransformAsync(HttpContext httpContext, RouteValueDictionary values) { if (values.TryGetValue("seourl", out var seoUrlObj) && seoUrlObj is string seourl) { var sayfa = await _dbContext.Sayfas.FirstOrDefaultAsync(x => x.URL == seourl); if (sayfa != null) { return new RouteValueDictionary { ["culture"] = values["culture"], ["controller"] = sayfa.ControllerName, ["action"] = sayfa.ActionName }; } } // 未匹配到对应页面时,返回原路由值(可根据需求修改为404逻辑) return values; } }
- 配置动态路由
在Program.cs(或Startup.cs)中注册转换器并配置路由:
// 注册转换器 builder.Services.AddScoped<SeoUrlTransformer>(); // 配置动态路由 app.MapDynamicControllerRoute<SeoUrlTransformer>( pattern: "{culture}/{seourl}", defaults: new { culture = "tr-TR" }); // 保留默认路由作为 fallback(可选) app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
此方案会在路由匹配阶段直接解析出正确的控制器和动作,路由系统全程使用正确的路由信息,彻底解决你遇到的问题。
方案二:修改过滤器并更新ActionDescriptor(兼容旧实现)
如果坚持使用原有过滤器方式,需要同时更新ActionDescriptor,让路由系统识别到修改后的控制器和动作:
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { string seourl = context.RouteData.Values["seourl"]?.ToString() ?? ""; string controllername = context.RouteData.Values["controller"]?.ToString() ?? ""; string actionname = context.RouteData.Values["action"]?.ToString() ?? ""; if (!string.IsNullOrEmpty(seourl) && controllername == "Home" && actionname == "Index") { var sayfa = await dbContext.Sayfas.FirstOrDefaultAsync(x => x.URL == seourl); if (sayfa != null) { // 更新RouteData context.RouteData.Values["controller"] = sayfa.ControllerName; context.RouteData.Values["action"] = sayfa.ActionName; // 更新ActionDescriptor,让路由系统识别正确的控制器动作 var controllerType = Type.GetType($"YourProjectNamespace.Controllers.{sayfa.ControllerName}Controller"); if (controllerType != null) { var methodInfo = controllerType.GetMethod(sayfa.ActionName, BindingFlags.Public | BindingFlags.Instance); if (methodInfo != null) { context.ActionDescriptor = new ControllerActionDescriptor { ControllerTypeInfo = controllerType.GetTypeInfo(), MethodInfo = methodInfo, ControllerName = sayfa.ControllerName, ActionName = sayfa.ActionName }; } } } } await base.OnActionExecutionAsync(context, next); }
注意:需替换YourProjectNamespace为你的项目命名空间,此方法依赖反射,不如动态路由优雅,仅作为兼容方案使用。
内容的提问来源于stack exchange,提问作者Burak Kükekiciler
相关产品推荐
相关产品推荐

