Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WebApi Controller with two GET actions

I want to have two different GET action to query the data by, name and id,

I have these routes:

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

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

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

and these actions in the controller:

    [HttpGet]
    public CompanyModel CompanyId(Guid id)
    {
          //Do something
    }


    [HttpGet]
    public CompanyModel CompanyName(string name)
    {
            //Do something
    }

while a call like this: http://localhost:51119/api/companies/CompanyId/3cd97fbc-524e-47cd-836c-d709e94c5e1e works and gets to the 'CompanyId' method,

a similar call to http://localhost:51119/api/companies/CompanyName/something gets me to 404 not found

but this: 'http://localhost:51119/api/companies/CompanyName/?name=something' works fine

Can anyone explain this behaviour and what am I doing wrong?

like image 314
Doron Sinai Avatar asked Mar 28 '13 12:03

Doron Sinai


People also ask

Can we have multiple get methods in Web API?

As mentioned, Web API controller can include multiple Get methods with different parameters and types. Let's add following action methods in StudentController to demonstrate how Web API handles multiple HTTP GET requests.

Can we have multiple get methods in controller?

Usually a Web API controller has maximum of five actions - Get(), Get(id), Post(), Put(), and Delete(). However, if required you can have additional actions in the Web API controller.

Can we use multiple FromBody?

The [FromBody] attribute can be applied on only one primitive parameter of an action method. It cannot be applied to multiple primitive parameters of the same action method.


1 Answers

The Web API route selector has no way to know if the string at the end of your URL is a GUID or not. Therefore, it is not about to select the correct route for the appropriate GET action.

In order to select the correct route, you need to add a route constraint for the GUID uri template.

    public class GuidConstraint : IHttpRouteConstraint
    {
        public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values,
                          HttpRouteDirection routeDirection)
        {
            if (values.ContainsKey(parameterName))
            {
                string stringValue = values[parameterName] as string;

                if (!string.IsNullOrEmpty(stringValue))
                {
                    Guid guidValue;

                    return Guid.TryParse(stringValue, out guidValue) && (guidValue != Guid.Empty);
                }
            }

            return false;
        }
    }

And then, add the constraint to the route that will handle the GUID.

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

Since this route is more specific than the general "string" route, it needs to be placed above the one that is going to resolve name.

This should appropriately route to the actions.

Hope this helps.

like image 173
Davin Tryon Avatar answered Sep 21 '22 15:09

Davin Tryon