【问题标题】:Multiple actions were found that match the request: WebAPI 2找到与请求匹配的多个操作:WebAPI 2
【发布时间】:2017-10-26 12:08:45
【问题描述】:

我已经阅读了一些 SO posts,但没有一篇能完全涵盖我的情况,所以我将在这里发布。

给定以下路由配置注册:

public static void Register(HttpConfiguration config)
{
    // Web API configuration and services

    // Web API routes
    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

以及从 ApiController 继承的控制器中的这些控制器操作:

public GetDocumentsResponse Post([FromBody]GetDocumentsRequest request)
{

}

public FinishDocumentsResponse Post([FromBody] FinishDocumentsRequest request)
{

}


public class GetDocumentsRequest
{
    public string CorrelationId { get; set; }
    public int Id { get; set; }
    public string ObjectId { get; set; }
    public string BusinessArea { get; set; }
    public string UserId { get; set; }
    public string SystemName { get; set; }
    public string SystemToken { get; set; }
    public Letter LetterDetails { get; set; }
    public List<KeyValuePair<string, string>> KeyValue { get; set; }
}

public class FinishDocumentsRequest
{
    public string CorrelationId { get; set; }
    public string[] Documents { get; set; }
}

我认为这样做足以消除歧义,让 IHttpActionSelector 正确选择路由,但不幸的是,事实并非如此。

所以我的问题是“有没有办法让这段代码正常工作,并将它保存在同一个控制器中?”

谢谢你, 斯蒂芬

【问题讨论】:

  • 您是否打算对两者进行相同的 URL 调用?

标签: c# asp.net-web-api


【解决方案1】:

您可以为此使用attribute routing

将路由定义为方法顶部的 Route 属性中的字符串 as this

[Route("api/controller/Post1")]
[HttpPost]
public GetDocumentsResponse Post([FromBody]GetDocumentsRequest request)
{

}
[Route("api/controller/Post2")]
[HttpPost]
public FinishDocumentsResponse Post([FromBody] FinishDocumentsRequest request)
{

}

【讨论】:

    【解决方案2】:

    请求路由管道不够智能,无法确定请求正文是否与参数类型匹配(也称为重载)。 (编译器足够聪明的,这就是为什么它会编译并且你有运行时问题。)

    你有几个不同的选择。

    1. 您可以在两个帖子中添加[Route(&lt;ActionName&gt;)] 属性。
    2. 制作两个控制器,一个用于GetDocuments,一个用于FinishDocuments
    3. 制作一个模棱两可的Post 方法。 (我会避免这种情况)

    如果您选择选项 1,您的 API uri 必须是 .../api/MyController/MyActionName 而不是 .../api/MyController/。还建议在您的方法中添加 [HttpGet][HttpPost] 属性。

    示例:

    public class DocumentController : ApiController 
    {
        // POST /api/Document/GetDocuments
        [HttpPost]
        [Route("GetDocuments")]
        public GetDocumentsResponse Post([FromBody]GetDocumentsRequest request) { ... }
    
        // POST /api/Document/FinishDocuments
        [HttpPost]
        [Route("FinishDocuments")]
        public FinishDocumentsResponse Post([FromBody] FinishDocumentsRequest request){ ...}
    }
    

    如果选择选项 2,则必须维护一个额外的代码文件。

    public class GetDocumentsController : ApiController
    {
        // POST /api/GetDocuments
        [HttpPost]
        public GetDocumentsResponse Post([FromBody]GetDocumentsRequest request) { ... }
    }
    
    public class FinishDocumentsController : ApiController 
    {
        // POST /api/FinishDocuments/
        [HttpPost]
        public FinishDocumentsResponse Post([FromBody] FinishDocumentsRequest request){ ...}
    }
    

    如果您选择选项 3,愿上帝怜悯您的灵魂,您将很难维持它。

    【讨论】:

      【解决方案3】:

      将 Route 属性装饰添加到您的 web api 函数中,这将帮助选择器选择路由:

      [Route("Post1")]
      public GetDocumentsResponse Post([FromBody]GetDocumentsRequest request)
      {
      
      }
      
      [Route("Post2")]
      public FinishDocumentsResponse Post([FromBody] FinishDocumentsRequest request)
      {
      
      }
      

      我还建议添加http方法装饰,例如[HttpPost][HttpGet]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-04-08
        • 2016-10-18
        • 2016-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多