Diego Barros
Diego Barros

Reputation: 2068

ASP.NET Web API routes not mapping to controller actions

I have an ASP.NET Web API application where I want to respond to the following routes:

1. http://localhost:1234/values
2. http://localhost:1234/values/123
3. http://localhost:1234/values/large
4. http://localhost:1234/values/small

Note: These routes and examples are just that, examples. But they map to what I want achieve.

  1. Should return all values, say a list of numbers.
  2. Should return the value of the resouce with id 123.
  3. Should return a list of what the app considers large values. Whatever that may be.
  4. Should return a list of what the app consider small values.

As with a billion ASP.NET Web Api routing examples, number (1) and (2) are straightforward. But when I try and resolve (3) and (4), then (1) and (2) are no longer working.

This is the routes I have at the moment:

        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // trying to map to "values/large" or "values/small"
        routes.MapHttpRoute(
            name: "ActionsApi",
            routeTemplate: "{controller}/{action}",
            defaults: null,
            constraints: new { action = @"^[a-zA-Z]+$" }
        );

        // trying to map to "values/123"
        routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "{controller}/{id}",
            defaults: null,
            constraints: new { id = @"^\d+$" }
        );

        // trying to map to "values"
        routes.MapHttpRoute(
            name: "ControllerApi",
            routeTemplate: "{controller}"
        );

With the above routes, (3) and (4) work.

(2) returns:

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
No action was found on the controller 'Values' that matches the name '123'.
</string>

And (1) returns:

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
Multiple actions were found that match the request:
System.Collections.Generic.IEnumerable`1[System.String] Get() on type MvcApplication3.Controllers.ValuesController
System.Collections.Generic.IEnumerable`1[System.String] Large() on type MvcApplication3.Controllers.ValuesController
System.Collections.Generic.IEnumerable`1[System.String] Small() on type MvcApplication3.Controllers.ValuesController
</string>

I am at a loss as to how to setup the routes to support the 4 API examples I listed above.

EDIT: Thanks to David, he pointed out that \w also matched digits, hence a problem. I changed it to [a-zA-Z]+ to match large and small.

Now all work except for (1).

EDIT 2 As suggested by @andrei I made the id parameter optional, to try and get (1) working, but resulted in the following error for that route:

The resource cannot be found.

Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable.  Please review the following URL and make sure that it is spelled correctly. 

The optional default I added here:

        routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "{controller}/{id}",
            defaults: new { id = RouteParameter.Optional },
            constraints: new { id = @"^\d+$" }
        );

Upvotes: 1

Views: 4036

Answers (1)

jmc
jmc

Reputation: 1058

Have you considered leaving the routing as default, and dealing with the "values" in your controller?

e.g. Change your Get to make id of type string, then check for "special" values inside your controller.

public class ValuesController : ApiController
    {

    // GET api/values/5
    public string Get(string id)
    {
        if (id == "large")
        {
            return "large value";
        }

        if (id == "small")
        {
            return "small value";
        }

        return "value " + id;
    }
}

Upvotes: 1

Related Questions