Coder Perfect

In ASP.NET Web API, a single controller can have several GET methods.

Problem

I had a class with a similar structure in Web API:

public class SomeController : ApiController
{
    [WebGet(UriTemplate = "{itemSource}/Items")]
    public SomeValue GetItems(CustomParam parameter) { ... }

    [WebGet(UriTemplate = "{itemSource}/Items/{parent}")]
    public SomeValue GetChildItems(CustomParam parameter, SomeObject parent) { ... }
}

It was quite straightforward to obtain the proper request at the right place because we could map particular methods. IActionValueBinder was successfully utilized for a similar class that only had a single GET method but also had an Object parameter. In the situation given above, however, I receive the following error:

Multiple actions were found that match the request: 

SomeValue GetItems(CustomParam parameter) on type SomeType

SomeValue GetChildItems(CustomParam parameter, SomeObject parent) on type SomeType

I’m trying to solve this problem by altering ApiController’s ExecuteAsync method, but I’m having no luck so far. I’m looking for some guidance on this.

I failed to note that I’m now trying to port this code to ASP.NET Web API, which uses a different routing method. How can I make the code work with ASP.NET Web API, then?

Asked by paulius_l

Solution #1

This is the best technique I’ve discovered to accommodate both additional GET methods and standard REST methods. To your WebApiConfig, add the following routes:

routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id = RouteParameter.Optional }, new { id = @"\d+" });
routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}");
routes.MapHttpRoute("DefaultApiGet", "Api/{controller}", new { action = "Get" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
routes.MapHttpRoute("DefaultApiPost", "Api/{controller}", new {action = "Post"}, new {httpMethod = new HttpMethodConstraint(HttpMethod.Post)});

With the help of the test class listed below, I was able to confirm this solution. I was able to correctly execute each of the following methods in my controller:

public class TestController : ApiController
{
    public string Get()
    {
        return string.Empty;
    }

    public string Get(int id)
    {
        return string.Empty;
    }

    public string GetAll()
    {
        return string.Empty;
    }

    public void Post([FromBody]string value)
    {
    }

    public void Put(int id, [FromBody]string value)
    {
    }

    public void Delete(int id)
    {
    }
}

It supports the following requests, according to my tests:

GET /Test
GET /Test/1
GET /Test/GetAll
POST /Test
PUT /Test/1
DELETE /Test/1

If your extra GET operations don’t start with ‘Get,’ you might want to give the method a HttpGet attribute.

Answered by sky-dev

Solution #2

Go from this:

config.Routes.MapHttpRoute("API Default", "api/{controller}/{id}",
            new { id = RouteParameter.Optional });

To this:

config.Routes.MapHttpRoute("API Default", "api/{controller}/{action}/{id}",
            new { id = RouteParameter.Optional });

As a result, you can now define the action (method) to which your HTTP request should be sent.

“http://localhost:8383/api/Command/PostCreateUser” invokes the following:

public bool PostCreateUser(CreateUserCommand command)
{
    //* ... *//
    return true;
}

Posting to “http://localhost:8383/api/Command/PostMakeBooking” causes the following to happen:

public bool PostMakeBooking(MakeBookingCommand command)
{
    //* ... *//
    return true;
}

This works great in a self-hosted WEB API service application:)

Answered by uggeh

Solution #3

Attributes are easier to utilize than manually adding them via code, in my opinion. Here’s an easy example.

[RoutePrefix("api/example")]
public class ExampleController : ApiController
{
    [HttpGet]
    [Route("get1/{param1}")] //   /api/example/get1/1?param2=4
    public IHttpActionResult Get(int param1, int param2)
    {
        Object example = null;
        return Ok(example);
    }

}

In your webapiconfig, you’ll also need this.

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

Some Useful Links http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api This one discusses the routing process in further detail. http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

Answered by Kalel Wade

Solution #4

This works beautifully in VS 2019:

[Route("api/[controller]/[action]")] //above the controller class

In the code, there’s also:

[HttpGet]
[ActionName("GetSample1")]
public Ilist<Sample1> GetSample1()
{
    return getSample1();
}
[HttpGet]
[ActionName("GetSample2")]
public Ilist<Sample2> GetSample2()
{
    return getSample2();
}
[HttpGet]
[ActionName("GetSample3")]
public Ilist<Sample3> GetSample3()
{
    return getSample3();
}
[HttpGet]
[ActionName("GetSample4")]
public Ilist<Sample4> GetSample4()
{
    return getSample4();
}

As previously said, you can have numerous gets.

Answered by Tom

Solution #5

Additional routes must be defined in global.asax.cs as follows:

routes.MapHttpRoute(
    name: "Api with action",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

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

Answered by Alexander Zeitler

Post is based on https://stackoverflow.com/questions/9499794/single-controller-with-multiple-get-methods-in-asp-net-web-api