...猜猜我是第一个问这个问题的人吗?
假设您有以下路由,每个路由在不同的控制器上声明:
[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。
答案 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属性。