Your official information source from the .NET Web Development and Tools group at Microsoft.
Tutorial and Tool written by Troy Dai (Twitter @troy_dai) with assistance from Rick Anderson (Twitter @RickAndMSFT)
Search for “asp.net web api routing” on stackoverflow, you’ll find many questions. How exactly does Web API routing work? Why doesn’t my route work? Why is this action not invoked? Often time it is difficult to debug route.
To address this issue I wrote this tool named “ASP.NET Web API Route Debugger” trying to make Web API developers’ lives a bit easier.
In this article I’ll first introduce stdebugger. Then I’ll introduce how routing works in Web Api. It is followed by three examples of how to use the route debugger in real cases.
You can install Route Debugger from NuGet (http://www.nuget.org/packages/WebApiRouteDebugger/)
1: PM> Install-Package WebApiRouteDebugger
The NuGet package will add a new area and to your project. The image below shows the new files added to the project. (The + icon shows new files and the red check icon shows changed files)
Hit F5 to compile and then navigate to http:// localhost:xxx/rd for the route debugger page.
Enter the URL you want to test and press Send. The results page is displayed.
I’ll explain how to read the results in the following sections.
The routing mechanism of ASP.NET Web API is composed of three steps: find the matching route and parse the route data, find the matching controller, and find the matching action. In any step fails to find a selection the steps following will not be executed. For example, if no controller is found, the matching ends and no action is looked for.
In the first step, a route will be matched. Every route is defined with route template, defaults, constraints, data tokens and handler. (Routes are configured by default in App_Start\WebApiConfig.cs ) Once a route is matched, the request URL is parsed into route data based on the route template. Route data is a dictionary mapping from string to object.
Controller matching is purely done based on the value of “controller” key in route data. If the key “controller” doesn’t exist in route data, controller selection will fail.
After controller is matched, all the public methods on the controller are found through reflection. To match the action, it uses the following algorithm:
Source: http://stackoverflow.com/questions/13876816/web-api-routing
The controller and routes are shown below. The URL doesn’t match the MachineApi route.
1: localhost/api/machine/somecode/all
You can download Sample1 and install the route debugger NuGet package to follow along.
1: public class MachineController : ApiController
2: {
3: public IEnumerable<Machine> Get()
4: {
5: return new List<Machine>{
6: new Machine {
7: LastPlayed = DateTime.UtcNow,
8: MachineAlertCount = 1,
9: MachineId = "122",
10: MachineName = "test",
11: MachinePosition = "12",
12: MachineStatus = "test"
13: }
14: };
15: }
16:
17: public IEnumerable<Machine> All(string code)
18: {
19: return new List<Machine>
20: {
21: new Machine
22: {
23: LastPlayed = DateTime.UtcNow,
24: MachineAlertCount = 1,
25: MachineId = "122",
26: MachineName = "test",
27: MachinePosition = "12",
28: MachineStatus = "test"
29: }
30: };
31: }
32: }
1: config.Routes.MapHttpRoute(
2: name: "MachineApi",
3: routeTemplate: "api/machine/{code}/all"
4: );
5:
6: config.Routes.MapHttpRoute(
7: name: "DefaultApi",
8: routeTemplate: "api/{controller}/{id}",
9: defaults: new { id = RouteParameter.Optional }
Test http://localhost/api/machine/somecode/all in the route debugger:
The route debugger output shows the “controller” value is not found in the route data or route defaults. The default controller selector relies on “controller” value to find a proper controller.
A common misunderstanding of route templates is that the values are mapped based on their position. That’s not true. In this case even though Machine is placed right after Api, there is no hint that this segment of URL should be picked up.
Add a default value specifying the machine controller to the first route:
3: routeTemplate: "api/machine/{code}/all",
4: defaults: new { controller = "Machine" });
After this change, you get an HTTP 200 return, the machine controller is matched and the Action is matched. The matching route, controller and action are highlighted in green in the route debugger as shown below.
http://stackoverflow.com/questions/13869541/why-is-my-message-handler-running-even-when-it-is-not-defined-in-webapi
Source: http://stackoverflow.com/questions/14058228/asp-net-web-api-no-action-was-found-on-the-controller
1: public class ValuesController : ApiController
3: // GET api/values
4: public IEnumerable<string> Get()
5: {
6: return new string[] { "value1", "value2" };
7: }
8: // GET api/values/5
9: public string Get(int id)
10: {
11: return "value";
12: }
13: // POST api/values
14: public void Post([FromBody]string value)
15: {
16: }
17: // PUT api/values/5
18: public void Put(int id, [FromBody]string value)
19: {
20: }
21: // DELETE api/values/5
22: public void Delete(int id)
23: {
24: }
25:
26: [HttpGet]
27: public void Machines()
28: {
30: public void Machines(int id)
31: {
33: }
2: name: "DefaultApi",
3: routeTemplate: "api/{controller}/{action}/{id}",
4: defaults: new { action = "get", id = RouteParameter.Optional });
Try the following three routes which work correctly
However the URL /api/Values/1 Returns a 404 error.
There are two pivots here.
The route debugger tool shows that with the URL http://localhost:xxx/api/values/1, “1” is the action name and no such action exits.
Use one strategy of action matching, either by action name or by verb. Don’t put both in one controller and one route.
Source: Why don’t my routes find the appropriate action? http://stackoverflow.com/questions/14614516/my-web-api-route-map-is-returning-multiple-actions
The URL cause 500 is http://localhost/api/access/blob
1: public class AccessController : ApiController
3: // GET api/access/blob
4: [HttpGet]
5: public string Blob()
6: {
7: return "blob shared access signature";
8: }
9:
10: // GET api/access/queue
11: [HttpGet]
12: public string Queue()
13: {
14: return "queue shared access signature";
3: routeTemplate: "api/{controller}/{id}",
4: defaults: new { id = RouteParameter.Optional }
5: );
6:
7: config.Routes.MapHttpRoute(
8: name: "AccessApi",
9: routeTemplate: "api/{controller}/{action}"
10: );
The root problem is that both routes match and the first one is picked while the developer was expecting the second route to match. The “action” name is ignored and eventually action selector tries to match action based on verb alone.
Two solutions:
The greedy route selection can lead to difficult to resolve errors, especially when you assume the wrong route was selected. The route debugger is especially useful for this problem, as it shows you the route template selected.
Web API routing problems can get tricky and be difficult to diagnose. The Route Debugger tool can help you find routing problems and understand how routing works. We plan to address routing problems in the future (at least partially) with Attribute routing in Web API.
The tool’s source code is available. You can also download the source to the route debugger http://aspnet.codeplex.com. Click the Source Code tab and expand Tools\WebApi\RouteDebugger.
IE 9 gives errors on string trim() method. Replace with $.trim(str) and it works fine.
it depends on a version of knockout that we cannot yet upgrade to internally. frustrating!
A route isn't working for me althought the route debugger has highlighted it in green, yet I still receive:
"404 file not found" on my PUT request :(
It would be helpful to explain in this article and in the nuget gallery that use of this tool is dependent on the use of the async keyword and related support. This is only reliably supported starting with the VS2012 csharp compiler. There is no reliable mechanism for successfully compiling the RouteDebugger source in VS2010 even if you are using .NET 4.5. The Async CTP is flakey and ultimately not supported (see blogs.msdn.com/.../asyncctp-installation-problems-and-vs11.aspx), so there really isn't a solid means for using this tool in any dev environment other than VS2012.
Very interesting post. This is a helpful post also. Thanks for sharing this useful post.
For those who are getting 404 Not Found, you need to register areas in your Application_Start in Global.asax.
Before your route configuration, add:
AreaRegistration.RegisterAllAreas();