【问题标题】:WebAPI - multiple GET methods with no parametersWebAPI - 多个没有参数的 GET 方法
【发布时间】:2016-11-27 11:21:07
【问题描述】:

只要每个端点的参数不同,我就可以创建任何我想要的端点:

public IHttpActionResult GetFightersByWeightClass(string WeightClass)
...

public IHttpActionResult GetFighterByExactName(string NameEquals)
...

但是,一旦我尝试创建两个共享相同参数的不同名称的函数,我就无法同时使用这两个函数。我有两个不需要参数的端点,如下所示:

public class FighterController : ApiController
{
    /// <summary>
    /// Gets all fighters.
    /// </summary>
    /// <returns></returns>
    [ActionName("GetAllFighters")]
    public IEnumerable<Fighter> GetAllFighters()
    {
        return allFighters;
    }

    /// <summary>
    /// Gets all fighters that are currently undefeated.
    /// </summary>
    /// <returns></returns>
    [ActionName("GetAllUndefeatedFighters")]
    public IHttpActionResult GetAllUndefeatedFighters()
    {
        var results = allFighters.FindAll(f => f.MMARecord.Losses == 0);

        if (results == null)
        {
            return NotFound();
        }

        return Ok(results);
    }
}

两个 URL 都返回这个:

{"Message":"An error has occurred.","ExceptionMessage":"Multiple actions were found that match the request: \r\nGetAllFighters on type MMAAPI.Controllers.FighterController\r\nGetAllUndefeatedFighters on type MMAAPI.Controllers.FighterController","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.&lt;SendAsync&gt;d__1.MoveNext()"}

不知道为什么会发生这种情况,它们每个都有自己独特的动作和函数名称,所以我认为它们会像这样工作......:

http://localhost:55865/api/fighter/GetAllUndefeatedFighters -- 只显示零损失的战士

http://localhost:55865/api/fighter/ -- 显示所有战士

...但两者都不起作用。如果我删除其中一个,它们就会起作用,反之亦然。因此,当它们都处于活动状态时,它们不工作。知道为什么吗?

【问题讨论】:

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


【解决方案1】:

其他两个答案的组合对我来说效果很好。 (我从问题中稍微更改了名称。)

[RoutePrefix("api/v1/fighters")]
public class FighterController : ApiController
{
    /// <summary>
    /// Gets all fighters.
    /// </summary>
    /// <returns>An enumeration of fighters.</returns>
    [Route(""), HttpGet]
    public IEnumerable<Fighter> GetAllFighters()
    {
        return allFighters;
    }

    /// <summary>
    /// Gets all fighters that are currently undefeated.
    /// </summary>
    /// <returns>An enumeration of fighters.</returns>
    [Route("undefeated"), HttpGet]
    public IEnumerable<Fighter> GetAllUndefeatedFighters()
    {
        return allFighters.FindAll(f => f.MMARecord.Losses == 0);
    }
}

因此,您的端点将是:

GET /api/v1/fighters

GET /api/v1/fighters/undefeated

【讨论】:

    【解决方案2】:

    Web API 允许您使用属性路由来自定义端点 URI。 要使用它,请添加:

    config.MapHttpAttributeRoutes();
    

    WebApiConfig 类中的 Register 方法。然后,您可以将端点设置为您想要的任何内容,而不管操作名称如何。

    [Route("getallfighters"), HttpGet, ResponseType(typeof(Fighter))]
    public IHttpActionResult ThisNameDoesntMatterNow()
    {
        //...
    }
    

    你的 URI 变成:

    api/fighter/getallfighters
    

    您甚至可以向控制器添加属性路由:

    [RoutePrefix("api/v1/fighters")]
    public class FightersController : ApiController
    {  
        //...
    }
    

    【讨论】:

      【解决方案3】:

      使用路由属性

          /// <summary>
          /// Gets all fighters.
          /// </summary>
          /// <returns></returns>
          [HttpGet]
          [System.Web.Http.Route("api/GetAllFighters")]
          public IEnumerable<Fighter> GetAllFighters()
          {
              return allFighters;
          }
      
          /// <summary>
          /// Gets all fighters that are currently undefeated.
          /// </summary>
          /// <returns></returns>
          [HttpGet]
          [System.Web.Http.Route("api/GetAllUndefeatedFighters")]
          public IHttpActionResult GetAllUndefeatedFighters()
          {
              var results = allFighters.FindAll(f => f.MMARecord.Losses == 0);
      
              if (results == null)
              {
                  return NotFound();
              }
      
              return Ok(results);
          }
      

      并使用不同的路由调用两个方法

      http://www.yourdomain/api/GetAllFighters
      http://www.yourdomain/api/GetAllUndefeatedFighters
      

      【讨论】:

      • 为什么我们不能只使用不同的动作名称而需要路由属性?
      猜你喜欢
      • 2021-11-14
      • 1970-01-01
      • 1970-01-01
      • 2018-07-04
      • 2020-03-22
      • 2021-08-15
      • 2017-05-19
      • 1970-01-01
      • 2015-05-03
      相关资源
      最近更新 更多