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