One of the recent videos on ASP.NET MVC covers the Hands On Labs from Mix. Scott Hanselman runs through a lab called the CustomControllerFactory, demonstrating how to build an intercepting controller.
Having followed the lab and tried the code I was left dazed and confused, and I wasn't the only one. Life would have been easier if the code from the labs were available, but I couldn't find it anywhere.
There seem to be two sources of confusion:
- The video doesn't mention a vital addition to the Global.asax.cs file to change the controller factory
- HandleUnknownAction ends up handling all actions
Getting the Lab Code Working
Add a line to Application_Start (in Global.asax.cs) to set the framework to use the InterceptingControllerFactory instead of the DefaultControllerFactory:
With this line set, any controllers instanciated will be InterceptionControllers. Without it, the default controller factory is used and the interception classes will be completely ignored.
Catching Unknown Actions
Once the lab code is working, you'll soon notice that HandleUnknownAction is catching every single action.
This happens because the InterceptionController never has any actions. It's a wrapper around a controller of the type specified in the URL (the controller with actions), but the InterceptionController itself doesn't have any actions, so every action will trigger the HandleUnknownAction method.
The best way to get your head round this is to download the MVC code from CodePlex, add the project to your solution and reference it directly. It's a great way to learn more about how the MVC framework does its stuff: in our example, the ProcessRequest method of the MVCHandler object creates a controller using our custom controller factory, so ProcessRequest is working with an InterceptionController.
When the Execute method of the InterceptionController is called, it calls InvokeAction, which checks the actions defined on the controller. InterceptionController has none, so Execute calls HandleUnknownAction and our override fires. In the video Scott uses the override to check the actionName value and decide whether or not the controller should continue.
If you're trying to catch only unknown actions then an alternative way is to define a base controller class, inheriting from controller, which overrides HandleUnknownAction:
Now all of your controllers can inherit from this base controller:
The controller created in ProcessRequest will now be of the type specified in the URL and will have actions defined, so HandleUnknownAction will only fire when there really is an unknown action - there is no need to filter on the actionName anymore.