18

...猜猜我是第一个问这个的?

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

[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。

4

3 回答 3

19

如果您知道这ticket将是一个,int您可以在路由中指定该类型以帮助解析路由:

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

根据 user1145404 的评论,这种方法对我有用,其中包括指向具有相同路由前缀 ASP.NET Web Api 的多个控制器类型的链接

于 2015-09-09T12:17:10.380 回答
12

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

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

于 2014-01-28T19:36:24.747 回答
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,也没有特定规则。但至少你可以让你的 URL 看起来像你想要的那样。希望您的约束列表不会太长。如果是,或者您不想对路由字符串参数及其约束进行硬编码,您可以在操作方法之外以编程方式构建它,并将其作为变量提供给 Route 属性。

于 2017-07-20T05:27:40.900 回答