The default route in MVC {controller}/{action}/{id} for the most part quite useful, as it can set a default value if the incoming URL does not include a parameter, but there is also a way to specify a default action when actions does not exist on the controller?
What I want to achieve is to have controllers with a few specific actions, and then my own catchall, which uses a url to grab content from the underlying CMS.
For example, a product controller would look something like this:
public class ProductsController: Controller{ public ActionResult ProductInfo(int id){...} public ActionResult AddProduct(){...} public ActionResult ContentFromCms(string url){...} }
If the default route would handle /Products/ProductInfo/54 , etc., but the request URL /Products/Suppliers/Acme would return ContentFromCms("Suppliers/Acme"); (sending the URL as a parameter would be nicer, but not needed, and a method without parameters, in which I get it from the request, is good).
Currently, I can imagine two possible ways to achieve this:
Create a new constraint that reflects over the controller to see if it has an action with the given name and use it in the {controller}/{action}/{id} route, which allows me to have a more general look, like {controller}/{*url} .
HandleUnknownAction on the controller.
The first approach seems to be a pretty workaround for checking this out, and for the second I don't know the internal components of MVC and Routing well enough to know how to proceed.
Update
There were no answers, but I thought I would leave my decision if someone finds this in the future or offers improvements / better ways for people
For the controllers that I wanted to have my own, I gave them an interface
interface IHasDefaultController { public string DefaultRouteName { get; } System.Web.Mvc.ActionResult DefaultAction(); }
Then I got the result from ControllerActionInvoker and redefined FindAction. This calls the underlying FindAction function, then if the base returns null and the controller enters the interface, I again call FindAction with the default action name.
protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) { ActionDescriptor foundAction = base.FindAction(controllerContext, controllerDescriptor, actionName); if (foundAction == null && controllerDescriptor.ControllerType.GetInterface("Kingsweb.Controllers.IWikiController") != null) { foundAction = base.FindAction(controllerContext, controllerDescriptor, "WikiPage"); } return foundAction; }
Since I also need parameters from routing, I also replace RouteData at the beginning of the default ActionResult on the controller
ControllerContext.RouteData = Url.RouteCollection[DefaultRouteName].GetRouteData(HttpContext);