I'm not an architectural design pattern ninja by any means, but I was pretty sure I knew what a Controller object was, at least in the web context. I even blogged about the Page Controller patternas it relates to ASP.NET a few months ago, confident in my knowledge of the pattern and its intricacies. In that post, I quoted a passage from Martin Fowler's Patterns of Enterprise Application Architecture:
The basic responsibilites of a Page Controller are:
- Decode the URL and extract any form data to figure out all the data for the action.
- Create and invoke any model objects to process the data. All relevant data from the HTML request should be passed to the model so that the model objects don't need any connection to the HTML request.
- Determine which view should display the result page and forward the model information to it.
Based on that description, we can sum up the Controller as being the first major object that handles the request for a page. It's the Controller's responsibility to decode the request, grab the correct data/model from our Business Domain, and then pass that info on to the correct View, which in my example was implemented as an ASP.NET UserControl object. Sounds simple right?
In the design pattern world, there's two major implementations of the Controller:
- Page Controller (which I've already detailed)
- Front Controller
The Front Controller is similar, with the main difference being that a Front Controller handles all the requests for a given application, not just requests for a specific page. It's generally more complex to implement, but offers genuine advantages in a few situations. The main example that I can think of is in CMS type applications (like DotNetNuke), where all the requests pass through a single .aspx page. The Front Controller is actually the code-behind of the Default.aspx page in DNN, which has the responsibility of decoding the URL, and then passing concerns like authentication and which view to load on to various helper classes. A quick and dirty workflow of this process is as follows:
- Decode the request, and determine what view needs to be loaded (in DNN 2.X, this is accomplished by grabbing the TabId parameter)
- Pass off to a helper class that determines if the current user has permissions to view the requested page.
- Load the correct view and display it (In DNN, this entails loading the skin for the page, and injecting the correct module UserControls into the correct placeholders).
Rock. This is pretty simple still, right? My confusion, and the reason for this post, lies in several good posts made by David Hayden at CodeBetter. David describes several examples of popular .NET applications using Controllers to retrieve information for a view, but by the definitions I know, what he calls a Controller isn't actually a Controller. The best example of this is the DNN "*Controller" objects, which lie deeply buried in the "Domain" logic of DNN. Is this where a Controller is supposed to reside? By definition, a Controller should talk to the Domain logic, but I don't think it's supposed to actually reside within it. Here's an example from the HtmlModule class of DNN
As I see it, the HtmlTextController from this example is actually a business layer object, and not a controller. Am I being semantically difficult here, or do I have a point? In my mind the Controller in this example is whatever object that actually determined to load the HtmlModule UserControl in the first place. If you're really looking for a Controller example in DNN, look no further than the Default.aspx page's code-behind which does most of the actual work.
I'd be most interested in hearing thoughts on this.