【问题标题】:MVC Route Attribute error on two different routes两条不同路由上的 MVC 路由属性错误
【发布时间】:2014-11-07 17:07:23
【问题描述】:

我在使用 MVC 5.2 时遇到属性路由错误。错误是

找到多个与 URL 匹配的控制器类型。如果多个控制器上的属性路由与请求的 URL 匹配,就会发生这种情况。

有问题的路线是

[Route("{classname}/{id:int}")]
[Route("Edit/{id:int}")]

url /Edit/123 会抛出错误,而 url /someword/123 不会抛出错误

鉴于 Edit/123 比 someword/123 更具体,为什么它会在 /Edit/123 上引发错误?

谢谢,

约翰

【问题讨论】:

  • 如果classnameEdit 会发生什么? :)
  • 我当然可以改变路线。我的问题实际上是关于理解为什么它坏了。如果由于属性路由的设计导致路由不明确,我想了解为什么会这样,我的理解是更具体的路由将始终匹配。我相信,我可能错了,路由 /Edit/123 比 /Edit/{id:int} 更具体,后者比 /{name}/{id:int} 更具体。
  • Chris,所以错误是有多个路由匹配 /Edit/123?我认为它会找到精确的匹配并使用它,但如果它抛出路由直到只剩下一个,我就会明白这是多么模棱两可。
  • 我只是将我的评论移到了答案中。是的,它会查找所有可能的匹配路由,如果找到多个路由,则会出现错误。属性路由比标准路由更挑剔一些,因为没有内在的顺序。在标准路由中,它只是自上而下读取路由配置,第一个匹配获胜。属性路由没有逻辑起点。
  • 我即将尝试它,但可能是这里描述的自定义路由约束:blogs.msdn.microsoft.com/webdev/2013/10/17/… 我同意;这真是糟糕的设计。

标签: asp.net-mvc attributerouting


【解决方案1】:

路由框架不会判断您可能想要的路由(实际上有一个带有 Edit 的路由,所以显然我想要那个)。它所看到的只是它有两条与它所拥有的 URL 匹配的路由,它举起手来。

只要您永远不需要“编辑”作为classname 的值,类似以下的内容应该可以解决歧义:

[Route("{classname:regex(^(?!Edit)$)}/{id:int}")]

【讨论】:

【解决方案2】:

有两种方法可以解决这个问题:

正如 Chris 指出的那样,一个正则表达式约束。

或者自定义路由约束,比如这里:https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/

您可以通过实现 IRouteConstraint 接口来创建自定义路由约束。例如,以下约束将参数限制为一组有效值:

public class ValuesConstraint : IRouteConstraint
{
    private readonly string[] validOptions;
    public ValuesConstraint(string options)
    {
        validOptions = options.Split('|');
    }

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
    {
        object value;
        if (values.TryGetValue(parameterName, out value) && value != null)
        {
            return validOptions.Contains(value.ToString(), StringComparer.OrdinalIgnoreCase);
        }
        return false;
    }
}

以下代码展示了如何注册约束:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        var constraintsResolver = new DefaultInlineConstraintResolver();

        constraintsResolver.ConstraintMap.Add("values", typeof(ValuesConstraint));

        routes.MapMvcAttributeRoutes(constraintsResolver);
    }
}

现在您可以在路由中应用约束:

public class TemperatureController : Controller
{
    // eg: temp/celsius and /temp/fahrenheit but not /temp/kelvin
    [Route("temp/{scale:values(celsius|fahrenheit)}")]
    public ActionResult Show(string scale)
    {
        return Content("scale is " + scale);
    }
}

在我看来,这不是很好的设计。除非您自己明确设置它们,否则在匹配时不会判断您想要什么 URL,也没有特定规则。但至少你可以让你的 URL 看起来像你想要的那样。希望您的约束列表不会太长。如果是,或者您不想对路由字符串参数及其约束进行硬编码,您可以在操作方法之外以编程方式构建它,并将其作为变量提供给 Route 属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-10
    • 2016-11-01
    • 2013-10-28
    • 1970-01-01
    • 1970-01-01
    • 2012-01-26
    相关资源
    最近更新 更多