Search code examples
c#asp.net-web-apiasp.net-web-api-routing

API multiple Get methods and routing


I have a controller with only Get Methods

public class DeviceController : ApiController
{
    List<Device> machines = new List<Device>();

    public IEnumerable<Device> GetAllMachines()
    {
        //do something
        return machines;
    }

    [HttpGet]
    public IEnumerable<Device> GetMachineByID(int id)
    {
        //do something
        return machines;
    }

    [HttpGet]
    public IEnumerable<Device> GetMachinesByKey(string key)
    {
        //do something
        return machines;
    }

}

I would like to be able to access these via URL and get the data back

../api/{contorller}/GetAllMachines
../api/{contorller}/GetMachineByID/1001
../api/{contorller}/GetMachiesByKey/HP (machines exist)

When i run the first two in IE developer mode (f12) i get Json back displaying all machines and machine 1001. However when i run GetMachinesByKey/HP i get 404 error.

Also my WebApiConfig looks like this

        config.MapHttpAttributeRoutes();

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

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

Anyone enlighten me as to what I am doing wrong?


Solution

  • The routing engine is expecting to bind to a variable named id as defined in the route config:

    config.Routes.MapHttpRoute(
        name: "ActionApi",
        routeTemplate: "api/{controller}/{Action}/{id}", //<--- here {id} means bind to parameter named 'id'
        defaults: new { id = RouteParameter.Optional }
    );
    

    In your action GetMachinesByKey(string key) parameter is named key and so the framework isn't connecting those dots for you.

    You could pass the parameter in the querystring so using a URL of the form /api/{contorller}/GetMachiesByKey/?key=HP will bind correctly (you may need to change the route config as this doesn't pass an id parameter that the current config will be expecting).

    Alternatively I believe you can specify a route for an action using attribute routing. This allows you to decorate your action method with an attribute which tells the framework how the route should be resolved e.g:

    [Route("<controller>/GetMachinesByKey/{key}")]
    public IEnumerable<Device> GetMachinesByKey(string key)