In most Web API projects, endpoints are usually defined one of two ways: by adding routes to WebApiConfig or by using attribute routing on the API controller actions. I’m not the biggest fan of attribute routing (a post for another time), so I tend to put all my routes in WebApiConfig. Plus, the APIs I build tend to need additional defaults that require on-the-fly changes in a production environment, such as logging API requests.
For instance, I might not want to log API requests for every endpoint by default, just some of them. However, there might be a scenario where I need to troubleshoot API calls, which starts with enabling logging for endpoints not already being logged. But I don’t want to have to rebuild and redeploy my API just to enable logging. I want to be able to “flip a switch” in a config file, capture some log data, then flip the switch back when I have what I need.
Here is a sample set of API routes that deal with products. Straightforward enough, but notice the “logging” flag on each route defaults (assume I have a handler in place to check this flag on each request). Logging is enabled for the POST, PUT, and DELETE, but is disabled for the GET methods:
But let’s say that for whatever reason, I need to enable logging for those GET methods. To do so in this manner, I would have to modify the WebApiConfig code, rebuild the API project, then redeploy to production. Not only that, I would have to do that *again* as soon as I want to turn logging back off for those routes. Not ideal.
A Configuration Solution
So what if we took those routes defined in WebApiConfig and moved them into a config file? This is what that solution would look like.
1. The Routes.config File
In the root of your Web API project, create a new file named Routes.config. This file will contain all route definitions for your API, including any custom route defaults. Using the same product routes as above, here’s an example:
2. Create Routes Config Section Handler
To read and parse the Routes.config file, you need a custom configuration section handler, which requires the following 3 classes:
- Route.cs – Holds route data for each individual route.
- RoutesConfig.cs – Contains the list of routes.
- RoutesConfigSectionHandler.cs – The implementation for the custom config section handler.
3. Register the Config Section Handler in Web.config
Now you need to register the custom config section handler in the Web.config using the configSource attribute, as shown below:
4. Modify Application_Start to Read Routes Config
With all that in place, modify the Application_Start method in global.asax to do 2 things:
- Read the routes config section.
- Add the RoutesConfig object to the GlobalConfiguration properties. We do this so that we can grab the routes in the WebApiConfig.Register method.
5. Modify WebApiConfig
And finally, the last thing to do is to modify the WebApiConfig to pull the RoutesConfig object from the GlobalConfiguration properties and iterate over the routes to add them to the Web API route table. So now your WebApiConfig will look something like this:
- Create a Routes.config file that contains all route definitions for the API, including any custom route defaults.
- Implement a custom config section handler to parse the Routes.config file.
- Add the custom config section handler to the Web.config file, using the configSource attribute..
- Update Application_Start to read the routes section and store the routes config in the properties of GlobalConfiguration.
- Modify WebApiConfig to grab the routes from the GlobalConfiguration properties and add the routes to the route table.
So there you have it. In the scenario I described above, this approach allows me to enable/disable logging for each API endpoint on-the-fly without having to do the rebuild/redeploy dance. It’s a beautiful thing.