Getting Started with ASP.NET Core Web API - A Brief Discussion on non-RESTful Route Overriding
TLDR
- By inheriting from
BasicControllerand setting[Route("[controller]/[action]")], you can manage API routes centrally and reduce redundant configurations. - The
[Route]attribute at the Controller level will directly override the default route defined inBasicController. - The
[Route]attribute at the Action level will, by default, be concatenated with the Controller's route. - If an Action needs to completely replace the Controller's route configuration, add a
/or~prefix to the beginning of the[Route]string. - If you only need to modify the URL name of an Action, it is recommended to use the
[ActionName]attribute.
In non-RESTful Web API development, to simplify maintenance, it is common to unify route definitions by inheriting from a BasicController.
Unified Route Configuration
When do you encounter this issue: When the project standard adopts the Controller/Action format and you want to avoid repeatedly writing route attributes in every Controller.
By defining an abstract class BasicController, you can manage route rules centrally:
[ApiController]
[Route("[controller]/[action]")]
public abstract class BasicController : ControllerBase {
}
public class TestRouteController : BasicController {
// URL: /TestRoute/TestAction
[HttpPost]
public void TestAction() {
}
}Route Overriding and Concatenation Rules
When do you encounter this issue: When existing API paths do not match the default rules and you need to adjust paths for specific Controllers or Actions.
In ASP.NET Core, the behavior of [Route] depends on where it is placed and whether it contains special prefixes:
- Controller Overriding: Using
[Route]on a Controller will directly replace the configuration fromBasicController. - Action Concatenation: If you use
[Route]on an Action, it will be concatenated with the Controller's route by default, which can easily lead to excessively long paths. - Complete Override (Absolute Path): Adding
/or~to the beginning of the[Route]string in an Action allows you to ignore the Controller's route configuration.
The following are implementation examples for different scenarios:
[ApiController]
[Route("[controller]/[action]")]
public abstract class BasicController : ControllerBase {
}
[Route("Override/[action]")]
public class TestRouteController : BasicController {
// Scenario: Controller overrides Route, Action is not handled
// URL: /Override/OverrideController
[HttpPost]
public void OverrideController() {
}
// Common misuse scenario: Both Controller and Action override Route, causing the Action URL to be a concatenation of both
// URL: /Override/OverrideAction/Action/OverrideAction
[HttpPost]
[Route("Action/[action]")]
public void OverrideAction() {
}
// Scenario: Action does not want to use the Route set by the Controller; add "/" to the beginning of the Route
// URL: /Action/OnlyAction
[HttpPost]
[Route("/Action/[action]")]
public void OnlyAction() {
}
// Scenario: Action does not want to use the Route set by the Controller; add "~" to the beginning of the Route, same effect as above
// URL: /Action/OnlyAction2
[HttpPost]
[Route("~/Action/[action]")]
public void OnlyAction2() {
}
// Scenario: Only want to modify the Action name
// URL: /Override/Rename
[HttpPost]
[ActionName("Rename")]
public void RenameAction() {
}
}Conclusion
For non-RESTful architectures, it is recommended to prioritize using BasicController for global route standardization. If you need to adjust the path for an individual Action, first evaluate whether you only need to modify the name (using [ActionName]). If you need to completely change the path structure, be sure to use the / or ~ prefix to avoid unnecessary route concatenation.
Changelog
- Initial version created.