How can I add multiple Get actions with different

2019-09-08 23:20发布

问题:

I'm trying to figure out whats the best way to have multiple Get actions in a REST controller.

I would like to do something like this:

Get By Id:

public ResponseType Get(Guid id)
{
   // implementation
}

Get By Enum Type:

public ResponseType Get(EnumType type)
{
   // implementation
}

Get By Other Enum Type:

public ResponseType Get(OtherEnumType otherType)
{
   // implementation
}

etc..

Now when I do something like that, I get the next error message:

Multiple actions were found that match the request

I understand why I get the message and I was thinking how is the best way to do something like that (I want to stick with REST).

I know I can add a route like this:

routeTemplate: "api/{controller}/{action}/{id}"

But then I would need to change the action names and the urls - And this seems like a workaround when we are talking about rest.

Another thing I thought was to create multiple controllers with one Get - But that seems even wronger.

The third workaround was to handle one Get action with an input param that will have the state:

public ResponseType Get(ReqeustObj obj)
{
   switch(obj.RequestType)
   {
        case RequestType.GetById:
        // etc...
   }
}

Anyway, I would like to know whats the best way to do something like that in REST (WebApi).

回答1:

As you now, when Web API needs to choose an action, if you don't specify the action name in the route, it looks for actions whose name starts with the method name, GET in this case. So in your case, it will find multiple methods.

But it also try to match the parameters. So, if you include the parameters as part of the url (route parameters) or the query string, the action selector will be able to choose one of the available methods.

If you don't specify a parameter or specify the id in the url (or even in the query string) it should invoke the first overload. If you add the parameter name of the second action in the query string like this: ?type=VALUE it should choose the corresponding overload, and so on.

The question is that the parameter names must be different, or it will not be able to choose one or the other among all the overloads.

For example, if you use the urls in the comments in your browser, you'll see how the right method is chosen:

public class TestController : ApiController
{
    // GET api/Test
    public string Get()
    {
        return "without params";
    }

    // GET api/Test/5
    public string Get(int id)
    {
        return "id";
    }

    // GET api/Test?key=5
    public string Get(string key)
    {
        return "Key";
    }

    // GET api/Test?id2=5
    public string Get2(int id2)
    {
        return "id2";
    }
}

NOTE: you can also use route constraints to invoke differet methods without using query string parameters, but defining different route parameter names with different constraints. For example you could add a constraint for id accepting only numbers "\d+" and then a second route which accepts "key" for all other cases. In this way you can avoid using the query string