【问题标题】:AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfiedAmbiguousActionException:匹配多个操作。以下操作匹配路线数据并满足所有约束
【发布时间】:2016-11-24 23:16:55
【问题描述】:

我正在使用 ASP.NET Core MVC 创建一个网站。当我单击某个操作时,我收到此错误:

AmbiguousActionException: Multiple actions matched. The following actions matched route data and had all constraints satisfied:

Web.Controllers.ChangeEventsController.Create (Web)
Web.Controllers.ProductsController.CreateChangeEvent (Web)

这就是我在 index.cshtmlm 中为 ProductsController 定义操作的方式:

<a asp-controller="ChangeEvents" asp-action="Create" asp-route-id="@item.Id">Create Change Event</a>

这是我的路线:

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });

这是我定义动作的方式:

// ChangeEventsController
[HttpGet("{id}")]
public IActionResult Create(Guid id)

// ProductsController
[HttpGet("{id}")]
public IActionResult CreateChangeEvent(Guid id)

我做错了什么?

更新

感谢@MegaTron 的回复,但是我想知道为什么我不能为不同的控制器提供相同的操作路径。如果我有许多控制器每个都创建实体,我觉得你提出的解决方案无法很好地扩展。

【问题讨论】:

  • 你不需要 IShouldNotNeedThisIThink 路由声明。
  • 我需要那条路线吗?
  • 在最简单的情况下,您只需要默认的。

标签: c# asp.net-core asp.net-core-mvc asp.net-core-routing


【解决方案1】:

试试:

// ChangeEventsController
[HttpGet("Create/{id}")]
public IActionResult Create(Guid id)

// ProductsController
[HttpGet("CreateChangeEvent/{id}")]
public IActionResult CreateChangeEvent(Guid id)

【讨论】:

  • 为什么不同的控制器不能有相同的动作名称?
  • 不要采用这种方法!它可以工作,但会导致糟糕的 REST API 设计,并且很难为许多控制器和操作进行维护。不要使用唯一前缀路由注释所有操作,而是使用唯一路由注释控制器类以区分每个控制器持有的操作。
  • 正如@B12Toaster 提到的,这个答案无助于解释为什么不同的控制器不能具有相同的动作名称并且它不遵循 RESTful 设计。
【解决方案2】:

虽然投票最多的答案确实解决了问题,但正如 @B12Toaster 所提到的那样,它会违反 REST 规则。有了我的回答,我将尝试在保持 RESTful 的同时解决问题。


TLDR:将 Name 属性添加到您的 HTTP 动词属性(GET 或其他方式)

为了让两个 GET 在两个控制器中工作,请执行以下操作:

// ChangeEventsController
[HttpGet(Name = "Get an event")]
[Route("{id}")]
public IActionResult Create(Guid id)

// ProductsController
[HttpGet(Name = "Get a product")]
[Route("{id}")]
public IActionResult CreateChangeEvent(Guid id)

This answer 解释了为什么在 Web API 中的两个不同控制器上不能有两个同名的路径。您可以实施答案中讨论的解决方案来避免此问题,也可以使用我个人推荐的ServiceStack


长答案:解释如何在 Web API 中实现 RESTful

首先:让我们关注控制器名称。控制器名称应该是复数和名词。这将导致这两个控制器:

  • 事件:而不是 ChangeEvents。更改可能发生在 PUT 中,而不是控制器名称。
  • 产品

Explanation on RESTful naming standards


第二:控制器内的端点应该被命名为 CRUD 操作相对于 RESTful 标准。

  • 发布
  • 获取
  • 删除
  • 补丁:可选

这不是 Create 和 CreateChangeEvent。这可以帮助您找到您正在调用的动词。操作不需要自定义命名,因为每个控制器一开始就不应该有太多的操作。


第三:你的路线应该有每个自定义名称。同样,坚持我们的方法名称,它们应该只是 CRUD 操作。

在这种情况下:

// EventsController
[HttpGet(Name = "Get an event")]
[Route("events/{id}")]
public IActionResult Get(Guid id)

// ProductsController
[HttpGet(Name = "Get a product")]
[Route("products/{id}")]
public IActionResult Get(Guid id)

这将导致:

  • 获取 /events/{id}
  • 获取 /products/{id}

最后:对于 GET HTTP 调用,您应该通过查询而不是正文发送输入。只有 PUT/POST/PATCH 应该通过正文发送表示。这是 REST 中 Roy Fieldings 约束的一部分。如果您想进一步了解,请查看herehere

您可以通过在每个参数前添加 [FromQuery] 属性来做到这一点。

// EventsController
[HttpGet(Name = "Get an event")]
[Route("events/{id}")]
public IActionResult Get([FromQuery] Guid id)

// ProductsController
[HttpGet(Name = "Get a product")]
[Route("products/{id}")]
public IActionResult Get([FromQuery] Guid id)

我希望这对未来的读者有所帮助。

【讨论】:

  • 这篇文章帮助了我,拯救了我的一天。很棒。
  • 很高兴能提供帮助。 :)
  • 最佳答案
【解决方案3】:

如果您想使用默认路由,请按照自吹仪:

  1. 从“ChangeEvents”控制器顶部删除[Route("[controller]")](如果存在)。
  2. HttpGet 中删除路由模式

夏天,试试这个:

// ChangeEventsController
[HttpGet]
public IActionResult Create(Guid id)

// ProductsController
[HttpGet]
public IActionResult CreateChangeEvent(Guid id)

【讨论】:

    【解决方案4】:

    在 ASP.NET 中使用路由来避免模棱两可的方法。将您的代码更改为此

    // ChangeEventsController
    [HttpGet("{id}")]
    public IActionResult Create(Guid id)
    
    // ProductsController
    [HttpGet]
    [Route("[action]/{id}")]
    public IActionResult CreateChangeEvent(Guid id)
    

    【讨论】:

      【解决方案5】:

      在每个控制器上方添加[Route("api/[controller]")] 属性以使动作路由在不同路径下,然后您可以在每个控制器中使用相同的[HttpGet("{id}")]。这应该可以很好地扩展。请参阅 Microsoft 文档中的 this 示例。

      如果您不使用 [Route] 注释为每个控制器指定路由,则您的 ASP.NET Core MVC 无法立即知道选择哪个操作来处​​理请求。

      【讨论】:

        猜你喜欢
        • 2019-08-02
        • 2018-08-12
        • 2018-12-13
        • 2020-09-14
        • 1970-01-01
        • 1970-01-01
        • 2019-04-28
        • 1970-01-01
        • 2020-12-01
        相关资源
        最近更新 更多