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

时间:2014-01-28 18:59:35

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

...猜猜我是第一个问这个问题的人吗?

假设您有以下路由,每个路由在不同的控制器上声明:

[HttpGet, Route("sign-up/register", Order = 1)]
[HttpGet, Route("sign-up/{ticket}", Order = 2)]

...除了Order参数之外,您可以在MVC 5.0中使用相同的代码执行此操作。但升级到MVC 5.1后,您会在问题标题中收到异常消息:

  

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

那么新的RouteAttribute.Order属性只是控制器级别的?我知道在AttributeRouting.NET中你也可以做SitePrecedence。当所有操作都在同一个控制器中时,是唯一可以获得上述路线的方法吗?

更新

抱歉,我应该提到这些路由是在MVC控制器上,而不是WebAPI。我不确定这会如何影响ApiControllers。

3 个答案:

答案 0 :(得分:16)

如果您知道ticket将是int,您可以在路线中指定该类型以帮助解决路线:

[HttpGet, Route("sign-up/register")] [HttpGet, Route("sign-up/{ticket:int}")]

根据用户1145404的评论,此方法适用于我,其中包含指向Multiple Controller Types with same Route prefix ASP.NET Web Api

的链接

答案 1 :(得分:12)

在属性路由的情况下,Web API会尝试查找与请求匹配的所有控制器。如果它看到多个控制器能够处理这个,那么它会抛出异常,因为它认为这可能是用户错误。此路线探测与第一场比赛获胜的常规路线不同。

作为一种解决方法,如果您在同一个控制器中有这两个操作,那么Web API将遵循路由优先级,您应该看到您的方案正常工作。

答案 2 :(得分:3)

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

正则表达式约束,如下所示:MVC Route Attribute error on two different routes

或自定义路线约束,例如: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的判断以及匹配时没有特异性规则。但至少你可以按照自己想要的方式获取网址。希望您的约束列表不会太长。如果是,或者您不想对路由字符串参数及其约束进行硬编码,则可以在操作方法之外以编程方式构建它,并将其作为变量提供给Route属性。