You might create a custom IControllerFactory
, e.g. by deriving from DefaultControllerFactory
.
Its GetControllerInstance
method will be called with a null
value for the controllerType
argument, when no matching controller could be resolved.
At this point, you are ahead of the Exception
.
IController GetControllerInstance(RequestContext requestContext, Type controllerType)
Here you decide how to handle the request, like e.g. logging and/or handling the request by a specific controller.
The example below shows how the ErrorController
is being used as fallback, executing its Index
action method.
class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
var routeData = requestContext.RouteData;
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "Index";
controllerType = typeof(ErrorController);
}
return base.GetControllerInstance(requestContext, controllerType);
}
}
A custom controller factory gets installed from within e.g. Application_Start
in Global.asax.cs
using:
ControllerBuilder.Current.SetControllerFactory(new CustomControllerFactory());
Note that this doesn't guard you from a related exception in case the contoller does exist, but the action doesn't.
E.g. given a HomeController
without an Ufo
action method, the url www.myapp.com/home/ufo
results in an Exception
"A public action method 'ufo' was not found on controller '...HomeController"
.
A simple solution to handle such scenario is by overriding HandleUnknownAction
in a custom base controller of which all your controllers inherit.
The example below shows how a shared Error
view (Shared\Error.cshtml
) gets executed.
public abstract class BaseController : Controller
{
protected override void HandleUnknownAction(string actionName)
{
View("Error").ExecuteResult(ControllerContext);
}
}