duck
duck

Reputation: 867

WebAPI - multiple GET methods with no parameters

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?

Upvotes: 2

Views: 4498

Answers (3)

JustinStolle
JustinStolle

Reputation: 4420

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

Upvotes: 2

Ju66ernaut
Ju66ernaut

Reputation: 2691

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
{  
    //...
}

Upvotes: 4

Mostafiz
Mostafiz

Reputation: 7352

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

Upvotes: 1

Related Questions