作为this question的后续内容,我正在尝试实施自定义路由约束,以便动态修改特定路由的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<string, object> 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 < methodParameters.Length; i++) {
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
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> { ParamType.INT, ParamType.INT })) }
);
(我在构造函数中传递的内容基本上是“要查找的参数模式是两个整数”。所以当调用Match
方法时,如果在url中指定的操作,它将返回true无论实际参数名称如何,都有两个整数参数。)
那么,有没有办法可以覆盖此请求的RouteValueDictionary?还是有其他方法我可以做到这一点,我错过了?
答案 0 :(得分:4)
如果我确实理解了什么是问题:
那么,有没有办法可以为此覆盖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 ...
答案 1 :(得分:1)
您可以使用正则表达式轻松地将参数限制为正整数:
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});
正如我在回答你earlier question时所说,你不应该担心控制器动作中的参数名称。给那些过于有意义的名字会让你陷入困境。