【问题标题】:RouteAttribute's Order is completely ignored on IRouteConstraintRouteAttribute 的 Order 在 IRouteConstraint 上被完全忽略
【发布时间】:2018-04-17 03:35:43
【问题描述】:

我们有一个IRouteConstraint,它得到的检查比它应该得到的要多得多。经过进一步测试,看起来[Route] 上的Order 被路由约束忽略了。

例如,如果我有以下约束:

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] 模式的请求上运行它。 p>

如果它有所作为,我们使用的是 ASP.NET MVC v5.2.4。

【问题讨论】:

  • 它会返回正确的内容(Test1) - 你的意思是"Test0"
  • @StephenMuecke 是的,感谢您的指出。已更正。

标签: asp.net-mvc asp.net-mvc-5 attributerouting


【解决方案1】:

在 ASP.NET MVC 管道中,路由阶段和调用控制器动作的选择阶段是分开的。在路由阶段,您不能只选择第一个匹配操作并停止进一步查找。找到的动作(严格来说是方法)可以在后期过滤。例如,它可能不满足应用的操作选择器(例如NonAction 属性)。

这就是为什么基本的动作选择算法如下:

  1. 通过配置的路由传递请求 URL 并选择所有匹配的操作。
  2. 通过动作选择器传递所有匹配的动作,过滤掉不匹配的动作。
  3. 按路由顺序对候选操作进行排序。

现在有以下选项:

  1. 未找到匹配的操作。请求结果为 404 错误。
  2. 多个匹配操作共享相同的最高顺序。抛出异常(“当前请求在以下操作方法之间不明确......”)。
  3. 恰好一个匹配动作具有最高顺序(或一个动作完全匹配)。选择并执行该操作。

如果您对相应的 ASP.NET MVC 源代码感兴趣,这里有一些参考资料:

IRouteConstraint.Match()System.Web.Routing.Route 中的ProcessConstraint() 方法调用。调用堆栈中最近的方法,它在路由集合级别上运行,是System.Web.Mvc.Routing.RouteCollectionRoute 类中的GetRouteData() 方法:

这是它的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);
    }
}

【讨论】:

  • 所以这是一个错误还是设计使然,对我来说似乎没有意义,所以对我来说这是一个巨大的错误我错过了什么
猜你喜欢
  • 2012-11-19
  • 2019-11-27
  • 1970-01-01
  • 2022-06-15
  • 2011-10-19
  • 1970-01-01
  • 1970-01-01
  • 2014-09-03
  • 1970-01-01
相关资源
最近更新 更多