动态修改RouteValueDictionary

作为这个问题的后续,我正在尝试实现自定义路由约束,以便为特定路由动态修改RouteValueDictionary

我95%的方式:我可以根据提供的参数模式匹配任何路由,匹配url中指定的操作。 此过程的最后一步是覆盖RouteValueDictionary以将键重命名为控制器操作的适当参数。

这是我的代码的相关片段(整个类几乎是300行,所以我不想添加所有的,但我可以,如果需要):

 public class CustomRouteConstraint : IRouteConstraint { public bool Match(HttpContextBase httpContext, Route route, string paramName, RouteValueDictionary values, RouteDirection routeDirection) { if (routeDirection.Equals(RouteDirection.UrlGeneration)) { return false; } //this will grab all of the "actual" parameters out of the RVD, excluding action and controller Dictionary unMappedList = values.Where(x => x.Key.Contains("param")).OrderBy(xi => xi.Key).ToDictionary( kvp => kvp.Key, kvp => kvp.Value); string controller = values["controller"] as string; string action = values["action"] as string; //this method tries to find the controller using reflection Type cont = TryFindController(controller); if (cont != null) { MethodInfo actionMethod = cont.GetMethod(action); if (actionMethod != null) { ParameterInfo[] methodParameters = actionMethod.GetParameters(); //this method validates that the parameters of the action that was found match the expected parameters passed in the custom constraint; it also performs type conversion if (validateParameters(methodParameters, unMappedList)) { for (int i = 0; i  x.Key == unMappedList.ElementAt(i).Key).Key = methodParameters.ElementAt(i).Name; //above doesn't work, but even if it did it wouldn't do the right thing return true; } } } } return false; } } 

这是我如何使用自定义约束:

 routes.MapRoute( name: "Default2", url: "{controller}/{action}/{param1}-{param2}", defaults: new { controller = "Admin", action = "Index" }, constraints: new { lang = new CustomRouteConstraint(new RoutePatternCollection( new List { ParamType.INT, ParamType.INT })) } ); 

(我传递给构造函数的基本上是说“要查找的参数模式是两个整数”。所以当调用Match方法时,如果url中指定的动作有两个整数参数,它将返回true,无论如何的实际参数名称。)

那么,有没有办法可以覆盖此请求的RouteValueDictionary? 还是有其他方法我可以做到这一点,我错过了?

如果我确实理解了什么是问题:

那么,有没有办法可以覆盖此请求的RouteValueDictionary? 还是有其他方法我可以做到这一点,我错过了?

我已经采取了您的解决方案并更改了这些行来替换参数名称:

 for (int i = 0; i < methodParameters.Length; i++) { // I. instead of this //values.First(x => x.Key == unMappedList.ElementAt(i).Key) // .Key = methodParameters.ElementAt(i).Name; //above doesn't work, but even if it did it wouldn't do the right thing // II. do this (not so elegant but working;) var key = unMappedList.ElementAt(i).Key; var value = values[key]; values.Remove(key); values.Add(methodParameters.ElementAt(i).Name, value); // III. THIS is essential! if statement must be moved after the for loop //return true; } return true; // here we can return true 

注意:我喜欢你的方法。 有时,扩展/调整路由更加重要,然后转到代码并“修复错误的参数名称”。 当然,他们很可能不正确。

这是关注分离的力量。

  • url是一个地方。
  • 控制器,动作和参数名称之一。
  • 和强大的自定义路由……

……作为处理这个问题的唯一正确的地方。 这是关注的分离。 不调整动作名称来为Url服务…

您可以使用正则表达式轻松地将参数限制为正整数:

 private const string IdRouteConstraint = @"^\d+$"; routes.MapRoute( name: "Default2", url: "{controller}/{action}/{param1}-{param2}", defaults: new { controller = "Admin", action = "Index" }, constraints: new { param1 = IdRouteConstraint, param2 = IdRouteConstraint}); 

正如我在回答您之前的问题时所说 ,您不应该担心控制器操作中的参数名称。 给那些过于有意义的名字会让你陷入困境。