Working with API projects, it’s easy to miss some key rules about the routing. This post is basically the result of some that I missed, and subsequent the investigation. It covers some very basic routing rules, and it certainly not intended to be an exhaustive guide.
.Net Framework
Starting with a .Net Framework Web API, let’s create a new web app:
And add a new controller:
Here’s the code for the controller; as you will see, it’s massively complex, but the good news is that you only need to pay attention to the name of the action, and the code inside it:
public class TestController : ApiController
{
[HttpGet]
public IHttpActionResult TestAction()
{
return Ok("TestAction Performed");
}
}
Let’s run the project and navigate to the URL:
How did I know that was the URL? It’s magic, and you can buy some of that magic by sending a cheque for the low, low price of $25 to the address shown at the bottom of the screen.
Actually, it’s defined in WebApiConfig.cs:
Parameters
Where there is more than a single function, one surprising (to me) feature is that the parameters that it accepts is more important to the routing than the name of the controller. Here’s a second action with a parameter:
[HttpGet]
public IHttpActionResult TestAction2(string test)
{
return Ok("TestAction2 Performed");
}
… and here’s it working:
However, should I not give it the parameter that it craves, it hides away, and instead, we get the first function that’s no too fussy about parameters:
It doesn’t even matter whether I just put some drivel as the controller name; the first criteria is the parameter:
This is because, according to this it follows these criteria:
The default implementation is provided by the ApiControllerActionSelector class. To select an action, it looks at the following: • The HTTP method of the request. • The “{action}” placeholder in the route template, if present. • The parameters of the actions on the controller.
So, if we add the {action} placeholder, that ensures that it uses the correct method:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
//routeTemplate: "api/{controller}/{id}",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
Otherwise, we get a best guess based on the parameters.
.Net Core Web API
The rules have changed since switching to .Net Core; WebApiConfig has gone and, in its place, it a localised routing system.
Here, you tell the class how to handle routing; for example, the following:
[Route("api/[controller]")]
Will result anything decorated with HttpGet being called when the controller is called. The parameters must be explicitly decorated; so passing no parameters would look like this:
[HttpGet]
public string OneTest()
{
return "TestOne";
}
Whereas, a single parameter would look like this:
[HttpGet("{id}")]
public string aaa(int id)
{
return "value aaa";
}
If you duplicate the signatures then they are not found. As with the framework version, you can simply tell it to look to the action name that you give it:
[Route("api/[controller]/[action]")]
public class TestController : Controller
{
[HttpGet]
public IEnumerable<string> TestActionOne()
{
return new string[] { "one value1", "value2" };
}
[HttpGet]
public string TestActionTwo()
{
return "two value";
}
But, again, it pays no attention to parameters until you decorate it correctly.
References
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing