【问题标题】:Ambiguous routes with MVC5 attribute routing具有 MVC5 属性路由的模糊路由
【发布时间】:2014-04-15 16:59:04
【问题描述】:

我在使用属性路由时遇到了不明确的路由问题。问题源于(我相信)在我们的路线根部使用可变参数。让我烦恼的是字面参数似乎没有优先,MVC5无法确定使用哪个路由。

我之前在其他路线上遇到过这种情况,并认为我已经通过定义约定路线来解决问题。考虑到这一点,我在哪里可以找到有关属性路由和解决歧义的最佳实践的更多信息?

这是我遇到问题的代码以及异常。

“/”应用程序中的服务器错误。

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

请求找到了以下匹配的控制器类型:

帐户控制器

圆形控制器

说明:在执行当前网络请求期间发生未处理的异常。请查看堆栈跟踪以获取有关错误及其源自代码的位置的更多信息。

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

请求找到了以下匹配的控制器类型:

帐户控制器

圆形控制器

RouteConfig.cs

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

    // I added this constraint resolver to resolve some other ambiguous routes that end
    // with a literal, but MVC5 wasn't able to determine whether to use those routes
    var constraintResolver = new System.Web.Mvc.Routing.DefaultInlineConstraintResolver();
    constraintResolver.ConstraintMap.Add("notWriteAction", typeof(IsNotWriteActionConstraint));

    routes.MapMvcAttributeRoutes(constraintResolver);

    // This is the convention route I added to resolve another ambiguous route.
    routes.MapRoute(
        name: "Account",
        url: "Account/{action}/{GroupName}/{AccessToken}",
        defaults: new { controller = "Account", action = "Login", GroupName = UrlParameter.Optional, AccessToken = UrlParameter.Optional }
    );

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
}

RoundController.cs

public class RoundController : ControllerBase
{
    [Route("{groupid}/{campaignid}/{accesstoken}")]
    public async Task<ActionResult> TempRoundLink(string groupid, string campaignid, string accesstoken)
    {
    }
}

AccountController.cs

public class AccountController : ControllerBase
{
    [AllowAnonymous]
    [Route("Account/ResetPassword/{token}")]
    public async Task<ActionResult> ResetPassword(string token)
    {
    }
}

【问题讨论】:

  • 有同样的麻烦。我可以通过添加一个否定的正则表达式来解决它,但我认为这是不对的。它会很快失控并变得难以维护。
  • 嗨@JoshWheelock,我需要道歉 - 我打算写下我找到的解决方案。我也开始有一个约束,但为了更易于维护而放弃了它。我最终剥离了我们正在使用的所有 Microsoft 属性路由,并使用了“属性路由”,结果证明这是一个完全不同的包。 attributerouting.net它一直在工作!
  • @aholmes url 已失效,当前 url 为 htmlpreview.github.io/?https://github.com/mccalltd/…
  • 感谢您更新链接!

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


【解决方案1】:

我知道这不是您要问的,但我认为这可以通过使用 RoutePrefix 属性来解决。例如

[RoutePrefix("Round")]
public class RoundController : ControllerBase
{
    [Route("{groupid}/{campaignid}/{accesstoken}")]
    public async Task<ActionResult> TempRoundLink(string groupid, string campaignid, string accesstoken)
    {
    }
}

[RoutePrefix("Account")]
public class AccountController : ControllerBase
{
    [AllowAnonymous]
    [Route("Account/ResetPassword/{token}")]
    public async Task<ActionResult> ResetPassword(string token)
    {
    }
}

我认为它试图不做出假设的原因是因为偏好可能并不总是可以确定的。例如。您希望路由器如何解决这两个问题:

Routes (from attributes):
"Account/ResetPassword/{token}"
"Account/{something}/alpha"

Reequest:
"/Account/ResetPassword/alpha"

但这只是猜测......

【讨论】:

  • 我在想RoutePrefix 是我的答案。不幸的是,RoundController 动作都以可变参数而不是“Round”开头。我认为在使用相同方法的RoutePrefix 时将“Account”留在 AccountController 操作中意味着请求 URL 必须是“/Account/Account/ResetPassword/abc123”。我希望使用RoutePrefixPrecedence 参数,但似乎不再支持。
  • 我的假设是文字应该从左边开始匹配。我敢肯定它不这样做是有原因的,但我不知道为什么。您的示例将匹配 Account/ResetPassword/{token} 因为 Account 匹配文字,而 ResetPassword 匹配第二个文字。此时,文字“alpha”无法匹配。
  • 如果您需要保持与现有路由的向后兼容性,那么是的,这会变得更加困难。不久前,我发现一两个 NuGet 包安装了功能,以允许跟踪解决方案是如何发生的,以帮助解决路由错误。不过我不记得那些名字了。您可以尝试这些,看看它们是否可以让您深入了解为什么它与您的期望相符。也许它会帮助找到另一种方法或确定如何适当地注册路线。
  • 谢谢!看起来好像是 2008 年发布的。我会试一试。 haacked.com/archive/2008/03/13/url-routing-debugger.aspx
  • @aholmes 是的,那是其中之一,而这个是我最幸运的一个。它确实有一个警告,由于某种原因,它不适用于具有 .xml(或其他)扩展名的请求,但适用于 .json 或任何其他任意扩展名(项目设置为完全忽略扩展名)。所以请记住,如果它给出了奇怪的行为,以奇怪的方式修改请求实际上可能会使其工作(最好的黑色艺术)。
【解决方案2】:

我打算写比这更长的东西,但我没有时间。我最终采用的解决方案是去掉对 Microsoft 属性路由库的任何调用,而是使用此处找到的“属性路由”包。 http://htmlpreview.github.io/?https://github.com/mccalltd/AttributeRouting/blob/gh-pages/index.html

它运行良好,*Precedence 属性解决了我在原始问题中遇到的确切问题。

【讨论】:

  • 已更新。 @chris-marisic 评论了上面更新的 URL。
  • 我不敢相信我必须为此转储 MS 路由,但这是我找到的唯一解决方案。有没有人找到真正的解决方法?
  • 现在已经有几年了,但如果我没有记错我在研究中发现的东西,那就是微软库不是为这些更复杂的案例设计的,所以我不相信MS 路由解决方案是可能的。
  • 它没有用于抛出异常。根据我定义的路线的文字部分,我认为它正在做正确的事情。现在看来它从来没有这样做过,我只是对它选择的路线感到幸运。现在我的一堆以前可以工作的应用程序正在抛出异常。
猜你喜欢
  • 2016-01-12
  • 1970-01-01
  • 2016-05-23
  • 1970-01-01
  • 2013-11-02
  • 2014-04-18
  • 2014-12-27
  • 2023-04-10
  • 2016-01-06
相关资源
最近更新 更多