2

I've been able create whatever endpoints I've wanted as long as the parameters for each one is different:

public IHttpActionResult GetFightersByWeightClass(string WeightClass)
...

public IHttpActionResult GetFighterByExactName(string NameEquals)
...

But as soon as I try to create two differently named functions that share the same parameters I am unable to use both. I have two endpoints that don't require parameters, shown below:

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);
    }
}

Both URLs return this:

{"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.<SendAsync>d__1.MoveNext()"}

Not sure why this is happening they each have their own unique action and function name, so I thought they would work like this...:

http://localhost:55865/api/fighter/GetAllUndefeatedFighters -- Just shows fighters with zero losses

http://localhost:55865/api/fighter/ -- shows all fighters

...but instead neither works. If I remove one of them, they other works and vice versa. So they aren't working when they are both active. Any idea why?

duck
  • 747
  • 14
  • 31
  • Possible duplicate of [Web Api Routing for multiple Get methods in ASP.NET MVC 4](http://stackoverflow.com/questions/12775590/web-api-routing-for-multiple-get-methods-in-asp-net-mvc-4) – Orel Eraki Jul 23 '16 at 18:54

3 Answers3

4

Web API allows you to use Attribute routing to customize endpoint URIs. To use it, add:

config.MapHttpAttributeRoutes();

to the Register method in your WebApiConfig class. Then you can set the endpoints to whatever you want regardless of the Action name.

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

And your URI becomes:

api/fighter/getallfighters

You can even add attribute routing to your controller:

[RoutePrefix("api/v1/fighters")]
public class FightersController : ApiController
{  
    //...
}
JustinStolle
  • 4,182
  • 3
  • 37
  • 48
Ju66ernaut
  • 2,592
  • 3
  • 23
  • 36
2

A combination of the two other answers works well for me. (I've changed the names slightly from the question.)

[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);
    }
}

As such, your endpoints would be:

GET /api/v1/fighters

GET /api/v1/fighters/undefeated

JustinStolle
  • 4,182
  • 3
  • 37
  • 48
1

Use route attribute

    /// <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);
    }

and call two method using different route

http://www.yourdomain/api/GetAllFighters
http://www.yourdomain/api/GetAllUndefeatedFighters
Mostafiz
  • 7,243
  • 3
  • 28
  • 42