我们有一个IRouteConstraint
得到的检查远远超过应有的检查。经过进一步测试后,Order
上的[Route]
似乎被路由约束忽略了。
例如,如果我有以下约束:
public class TestConstraint : IRouteConstraint {
public bool Match(
HttpContextBase httpContext,
Route route,
string parameterName,
RouteValueDictionary values,
RouteDirection routeDirection
) {
Debug.WriteLine("TestConstraint");
return true;
}
}
然后连线:
constraintResolver.ConstraintMap.Add("testConstraint", typeof(TestConstraint));
并有以下路线:
public partial class HomeController {
[Route("test/0", Order = 1)]
public ActionResult Test0() {
return Content("Test0");
}
[Route("{someParam}/{test:testConstraint}", Order = 10)]
public ActionResult Test1() {
return Content("Test1");
}
}
然后请求http://localhost/test/0
,它会返回正确的内容(Test0
),但TestContraint.Match()
仍在执行。
我认为只有在RouteTable
遇到路由后才会执行路由约束,但它似乎在每个请求上运行它,可以匹配[Route]
图案。
如果它有所不同,我们使用的是ASP.NET MVC v5.2.4。
答案 0 :(得分:2)
在ASP.NET MVC管道中,路由阶段和调用控制器操作的选择阶段是分开的。在路由阶段,您不能只选择第一个匹配操作并停止进一步查找。找到的行动(严格来说,方法)可以在以后阶段过滤。例如,它可能不满足应用的操作选择器(例如NonAction
属性)。
这就是为什么基本动作选择算法如下:
现在有以下选项:
如果您对对应的ASP.NET MVC源代码感兴趣,可以参考以下内容:
IRouteConstraint.Match()
中的ProcessConstraint()
方法调用 System.Web.Routing.Route
。调用堆栈中最近的方法,在路由集合级别上运行,是GetRouteData()
类中的System.Web.Mvc.Routing.RouteCollectionRoute
方法:
以下是source code:
public override RouteData GetRouteData(HttpContextBase httpContext)
{
List<RouteData> matches = new List<RouteData>();
foreach (RouteBase route in _subRoutes)
{
var match = route.GetRouteData(httpContext);
if (match != null)
{
matches.Add(match);
}
}
return CreateDirectRouteMatch(this, matches);
}
如您所见,找到匹配的路线时,循环不会中断。
应用操作选择器的代码,执行排序并选择动作候选位于DirectRouteCandidate.SelectBestCandidate()
(source code):
public static DirectRouteCandidate SelectBestCandidate(List<DirectRouteCandidate> candidates, ControllerContext controllerContext)
{
Debug.Assert(controllerContext != null);
Debug.Assert(candidates != null);
// These filters will allow actions to opt-out of execution via the provided public extensibility points.
List<DirectRouteCandidate> filteredByActionName = ApplyActionNameFilters(candidates, controllerContext);
List<DirectRouteCandidate> applicableCandidates = ApplyActionSelectors(filteredByActionName, controllerContext);
// At this point all of the remaining actions are applicable - now we're just trying to find the
// most specific match.
//
// Order is first, because it's the 'override' to our algorithm
List<DirectRouteCandidate> filteredByOrder = FilterByOrder(applicableCandidates);
List<DirectRouteCandidate> filteredByPrecedence = FilterByPrecedence(filteredByOrder);
if (filteredByPrecedence.Count == 0)
{
return null;
}
else if (filteredByPrecedence.Count == 1)
{
return filteredByPrecedence[0];
}
else
{
throw CreateAmbiguiousMatchException(candidates);
}
}