// Base route config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional }); // Nested route (must be distinguishable by param names from above) - Deisgnated by leading _ config.Routes.MapHttpRoute("NestedRoute", "_/{controller}/{rootId}"); // Root controller signature: public class AppDataController : ApiController { public IQueryable GetById(long id) { return this.documentService.Get(id); } } //Nested controller signature: public class HistoryController : ApiController, INestedApiController { // Designate parameter mappings to parent using attributes public IQueryable Get([RootParamName("id")]long rootId) { return this.historyService.GetForParent(rootId); } } /* So our algorithm goes as follows: * Identify nested\base controllers using interfaces. - AppDataController - HistoryController * Use Api Explorer to determine potential routes for root controller - api/{controller}/{id} * Use Api Explorer to determine potential routes for nested controller that start with _ - _/{controller}/{rootId} * Take base route and swap out {controller} for our root controller name - api/AppData/{id} * Take nested route and swap out {controller} for our nested controller name - _/History/{rootId} * Translate parameter names in base route accoring to attributes in nested action signature, and also remove any matching params from the nested route - api/AppData/{rootId} - _/History * Now we create a new route based on a combination of these two, we need to remove the optional flag from any base root params - api/AppData/{rootId}/History/ defaults = { controller = "History" } * Finally, we must ensure to remove any route patterns starting with _ so they will not be present in the runtime routing table QED! */