The MVC framework – the Controller lifecycle
In my last post,we’ve seen how the MvcRouteHandler creates an IController instance that is responsible for processing the current request. Today I’ll keep talking about the MVC platform and we’re going to step through the tipical controller lifecycle.
When you build a new controller, you end up extending the System.Web.Mvc.Controller class. This class implements several interfaces. The IController is a special interface and it’s the one you need to implement if you don’t want to reuse the behavior of the Controller class. This interface has only one method:
public interface IController
void Execute(ControllerContext controllerContext);
Currently, the Controller class implements the Execute method by perfoming the following actions:
- initializes the ControllerContext property with the parameter passed to the method (do notice that the ControllerContext extends the RequestContext class by adding a new property – called Controller – which will let you get a reference to the controller that is handling the request. Yes, I guess that you won’t really be using this property from within a controller, but do notice that this class is extended – more about this in future posts - and this property might be usefull when you’re not in the controller scope);
- initializes the TempData by using the currently set TempDataProvider. TempData is a just a temporary dictionary which, by default, is persisted on the current session state. Keep in mind that you can create your own TempDataProvider, which is responsible for persisting the data wherever you want.The only thing you shoudl keep in mind about TempData is that the data you put there will only be persisted (ie, saved) between two consecutive requests;
- Gets a reference to the current action (by getting the value of the action parameter from the current RouteData);
- Gets a reference to an instance of the ControllerActionInvoker and calls its InvokeAction to start the “real” processing of the current request. As we’ll see in a future post, this class is responsible for doing most of the work associated with the response that is returned to the client (ie, it will end up calling your controller methods and filters);
- Saves the TempData dictionary.
As you can see, the basic lifecycle of the controller is not really complicated. There are still some more details which I didn’t mention in the previous lists. For instance, you must have noticed that I mentioned that the ControllerActionInvoker class ends up calling your controller methods and *filters*. Filters? Yeah, filters. You can see filters as a way of intercepting the “normal” execution of a controller action, at different stages.
Currently, and as you might expect, there are several types of filters. Do notice that the advantage of creating your own filters is that you’ll end up creating classes that can be reused across different controllers (and even different projects). If you just need to perform a specific operation on a particular case, you can follow another approach: instead of creating a filter, you can rely on the fact that the Controller class implements most of the “filter interfaces”. This means that you can simply override the necessary methods and add the code you want there.
On the other hand, if you’re into filters (and I’ll have more to say about this), then you’re supposed to build custom attributes which can be applied to your controller class or your controller’s methods. For instance, if you’re interested in acting before or after a specific controller action is executed, then you can simply extend the ActionFilterAttribute type and override the methods you’re interested in. After doing that, you just need to apply that custom attribute to the controller (or method) you want.
And that’s it: this is the basic lifecycle of the Controller class. On the next post, we’ll keep talking about some of the internal details that haven’t been mentioned here. There are still lots of things to talk about, so stay tuned!