ASP.NET MVC Controllers and Conventions

Why is it that ASP.NET MVC has such strongly-enforced naming conventions? Can conventions for the default behaviour of code actually help to reduce the complexity of applications, and at what point is it wise to break conventions in application architecture. Dino investigates the issues.

Convention-over-Configuration (CoC) is an approach to software design that seeks to assign a specific conventional meaning to predefined code structures. If the developer is happy with the convention, then there is little or no need for configuration. In a CoC-enabled framework, you can therefore implement default behaviour for ‘normal’ objects in a fraction of the time because you need to write only a fraction of the code that would otherwise be necessary. In a way, CoC is analogous to a math axiom-a statement that is accepted as true without requiring proof. A CoC behavior happens because the framework was coded in that way and it does not require any further ad-hoc code or configuration on the developer’s end.

CoC makes software development easier, but developers need to understand the overall CoC mechanism of any given framework so as to to ensure that they are in full command of the framework itself. This article touches on an extremely popular convention you find in ASP.NET MVC-controller’s naming-and analyzes the built-in mechanism that makes it happen.

Popular Examples of CoC

In the past, Romans used the expression “nomen omen” as a way to recognize some signs of the future fate in the name of a person. CoC is the software counterpart of “nomen omen” where the name of a software element (e.g., a class method) says it all about its intended role and behavior.

Even if you never heard of CoC, it’s still possible that you used it in some project. For example, how many times did you use the Page_Load method in an ASP.NET Web Forms page? I guess you did it quite often. If you look at the source code of the page class, then Page_Load is simply a method in a class and nothing makes it different from other public methods.

Yet, when that ASP.NET Web Forms page gets processed, the Page_Load method is run at a specific time no matter what. Page_Load runs to let developers complete the page initialization because of the convention used in its name. By default, it is treated as if it were the event handler associated with the Load event of the Page class. However, as a developer you are not required to “configure” the system explicitly to act this way; the behavior occurs by “convention.”

So when you implement CoC in a software framework, you assign a predefined default behavior to some syntax conventions-most frequently, the name of a method. Can you change conventions? And, more, what’s the cost of changing predefined conventions?

The final word on whether you can change conventions belongs to the framework itself and how CoC is implemented. In software, conventions are mostly a shortcut to improve productivity, so CoC-based frameworks generally provide hooks for developers to change conventional behavior.

ASP.NET MVC is certainly a CoC-based framework. You see conventions everywhere, in the way you code actions, define views, arrange routes, and more. However, the most popular convention in ASP.NET MVC is probably the naming convention of controller classes. Let’s explore this aspect further and see what you can do to change defaults.

ASP.NET MVC Controllers at a Glance

More often than not, I happen to interview ASP.NET MVC developers. My favorite question to open up discussion is “In ASP.NET MVC a controller class is required to be a class that implements the IControllerinterface. Is it true or false?”

Asked abruptly for a binary answer to such a question, I’m not sure I would come up myself with the right answer. To be honest, I’m not even sure a binary answer can be found before defining a bit of context first. The reason for this is just the amount of CoC you have in ASP.NET MVC. So let’s bring up some clear facts about controllers in ASP.NET MVC.

First and foremost, in ASP.NET MVC a controller is a class that implements the IControllerinterface, either directly or via inheritance from a class that does it. The IController interface is defined as below:

As you can see, the IControllerinterface is fairly simple; by contrast, a controller class is expected to perform quite a complex task. In ASP.NET MVC, therefore, all controller classes inherit from a base System.Web.Mvc.Controller class which, in turn, builds upon the functionalities hardcoded in the ControllerBase class. In light of this, I should rephrase my previous statement as “In ASP.NET MVC a controller is a class that inherits from the Controller class“.

And again, is this statement true or false?

Can one claim that a user-defined class is a valid ASP.NET MVC controller merely if it derives from the System.Web.Mvc.Controller class? Yes, it is sufficient for the code to compile successfully. However, if you create a controller class named, say, Foo, it throws an exception every time you invoke it!

In ASP.NET MVC, controller classes are also subject to some strong naming conventions. By convention, in fact, an ASP.NET MVC controller class must be given a name that ends with the word “Controller”. This condition is carved in stone in the framework. You can change this rule, but it will require you some nontrivial work. Let’s find out more about the way in which the actual controller name and type is sorted out in ASP.NET MVC.

Inside the Controller Factory

For each request that hits the site, ASP.NET MVC figures out the name of the controller class that will handle the request and manages to create a new instance of that class. The component responsible for the creation of controller instances is the controller factory. A controller factory is a class that implements the IControllerFactory interface:

ASP.NET MVC comes with a default controller factory implemented through theDefaultControllerFactoryclass.

As you can guess, all the magic around a controller factory takes place in the implementation of the CreateController method. There, the logic that figures out the real name of the controller type is applied. The factory gets a string with the controller’s nickname (e.g., Home) and returns an instance of a type that implements IController.

How does the factory transform a string like “Home” into an instance of a real class loaded in the application process space that is named HomeController?

For performance reasons, the default factory uses a type cache internally. The type cache is implemented in the ControllerTypeCacheclass. During the application initialization, the ControllerTypeCacheclass uses .NET reflection to enumerate all the referenced assemblies and explores them looking for publicly exposed controller types. A controller type is any referenced type that passes the following test:

A controller type is a type public and non-abstract; the type name must terminate with the suffix Controllerand the type must be assignable to a variable of type IController.

The controller type cache uses a dictionary to store controller types and keep them mapped to controller names. The key in the dictionary is the controller name; for example, it is Home when the detected type is HomeController.

If you want to change conventions and start having controller classes with a different naming pattern you have to plan writing a new controller factory class.

Planning a Custom Controller Factory

Overall, the most effective way to create a custom controller factory is to derive a new class from DefaultControllerFactory. Implementing theIControllerFactory interface directly requires writing a lot of plumbing code from scratch such as the type cache. It should be noted, in fact, that many helper types used in a controller factory are private or internal and can’t be reused in a third-party assembly.

On the other hand, the DefaultControllerFactoryclass offers a couple of virtual methods you can override to customize some key steps such as getting a controller type and instance. In the end, by inheriting from DefaultControllerFactory you get enough customization power at a much lower cost than implementing the interface directly.

Before I go any further, let me spend a few moments on the fundamental point: when do you really need to write your factory?

In five years of ASP.NET MVC, I’ve found one major use-case: when you need (or want) to use an IoC framework extensively to resolve and inject dependencies into controllers (e.g., repositories). In addition, you might likely need to resort to custom factories when you get weird requests from customers and wish to exceed their expectations!

In particular, it happened to me once that a customer asked if it was really possible to rename controller classes in a way different from the default convention. I took the challenge and won it with a relatively low effort. The listing below shows the full source code of a controller factory that uses Unity as an IoC framework and opts for a custom naming convention for controller class names.

Names of the overridable methods are for the most part self-explanatory. GetControllerType gets the controller’s nickname (e.g., Home) and returns the Type object for the matching controller type. This is the method to focus on if you wish to offer an alternate naming convention.

GetControllerInstance, instead, receives the type information calculated at the previous step and does whatever is in its power to return an instance of that type. In the code above, the Unity framework is used to resolve the type and return a valid instance. In a similar way, you can use another IoC library such as StructureMap or Ninject. Let’s focus on GetControllerType now.

The mission of the method is fairly clear: transform a name (e.g. Home) into a type using whatever mapping algorithm you like. The default algorithm consists in adding “Controller” to the provided name and looking for a controller type with that name in the list of referenced assemblies. Getting a string for the type name is not the main point, though. The following code is not enough:

You now have a string that expresses the desired type name but you need to find related type information and you’re lacking namespace information as well. The default factory uses the type cache to work around this issue. It scans the referenced assemblies via reflection and builds the cache of the controller types available in the application’s process space. Next, it gets the controller name and looks up the cache for type information.

You need a similar infrastructure if you want mean to change the naming convention. And building this infrastructure is up to you. If, instead, it’s OK for you to stick to a fixed sets of namespaces then you can proceed as below:

In this way, you have changed the naming convention to xxxPresenter but in a fixed set of namespaces.

Does It Make Sense to Change Conventions?

In ASP.NET MVC, conventions can be found in a variety of places. Controller naming is the most illustrious example, but similar conventions apply to views and layouts. Conventions are definitely helpful as a way to simplify and sometimes speed up coding. Also conventions are helpful to force people to keep their code clean and well organized.

Is there any value in changing software conventions?

Simply put, there’s no value in changing software conventions as much as there’s no intrinsic value in applying patterns or using IoC frameworks or perhaps object-oriented languages. As I see things, the only way to measure value in software is looking at requirements and ways to accomplish them. For the most part, software conventions improve productivity and should not be changed until they prevent some achievements or prove to be clearly inadequate for your purposes.

Back to ASP.NET MVC, even though I did it once, I see really no value in changing the naming convention for controllers. I do see some value, instead, in modifying the default view engines to organize views in different way. For example, if you use a long list of partial view you might want to group them in a different folder instead of mixing views and partial views under the same directory. For this to happen, you need a custom view engine that supports a different convention. Likewise, I do see value in using a custom controller factory if you need to inject layers of code into controllers. This feature requires that instances of controllers be created via IoC; hence, a custom factory is mandatory.

In the end, conventions over configuration help software development; configuration over conventions help reaching your exact goals. The good architect knows when breaking conventions pays off.