Published: 18 Jan 2010
By: Dino Esposito

In this article, Dino Esposito focuses on the core part of the ASP.NET MVC framework - the controller - and shares some considerations about the ideal structure it should have as a class and its intended role.

Contents [hide]

Introduction

With ASP.NET MVC 2 that approaches its final stage of RTM, more and more developers and architects, recent or early adopters of this powerful and alluring framework, begin wondering what would be the ideal structure of their controller classes and, more importantly, what is the "exact" role that the controller class play in the economy of an ASP.NET MVC application.

I haven't been a big fan of ASP.NET MVC in the beginning, and I was not certainly an early adopter of it. I severely contrasted a group (should I say, a school of thought?) in my company strongly advocating ASP.NET MVC over Web Forms about a year and a half ago when not even a Beta of ASP.NET MVC was available. As a matter of fact, that group prevailed, stable versions of ASP.NET MVC followed one another regularly, and we actually took the project home. Seamlessly. That gave me great fodder to think about ASP.NET MVC and study it from the underpinnings - the same runtime environment of ASP.NET Web Forms.

Today, as you may read also in my blog, I do recognize the inherent technical and architectural superiority of the ASP.NET MVC framework over ASP.NET Web Forms. Note that by recognizing ASP.NET MVC as superior all that I'm making is a relative statement. I still believe that ASP.NET MVC deserves more work and evolution to be ready to fully replace Web Forms and become the primary, if not unique, option for just any Web developers.

In this article, I'll focus on the core part of the ASP.NET MVC framework - the controller - and share some considerations about the ideal structure it should have as a class and its intended role.

Be Careful with Controllers

Controllers are the core of the ASP.NET MVC framework. Because of this, a blurred definition of their role and software structure may be as disruptive for your development efforts as, say, placing direct ADO.NET calls straight in your code behind event handlers.

In a way, ASP.NET MVC controllers have a lot in common with Web Forms code-behind classes. In ASP.NET MVC, controllers are the place where you start writing your code and implementing your use-cases. Similarly, code-behind event handlers are the first place where you start writing code in a Web Forms scenario. The simple fact of choosing ASP.NET MVC instead of Web Forms doesn't take you to write clean, nifty and well designed code. For sure, ASP.NET MVC shows you the way to go that is most appropriate for today's development. Web Forms, on the other hand, is based on a vision of software that was ideal for the time in which it was first devised - about a decade ago.

ASP.NET MVC shows you the way to go and also takes you at the beginning of the path. But at that point you are left alone to walk the way. And, in a way, you are left free of making your own right and wrong decisions. So pay a lot of attention when (and if) you add a new controller, and be careful with its methods and their implementation especially.

Creating Controller Classes

Visual Studio tools make creating controller classes definitely easy. I would even say that Visual Studio tools make it deceptively easy if I could be sure that this would not be perceived as a negative statement about Visual Studio ASP.NET MVC tooling. If you look at Figure 1, you get the idea that adding a controller class is a relatively simple task that tools can make even simpler by creating a bunch of stub methods for you.

Figure 1: Adding a controller in Visual Studio 2010.

Adding a controller in Visual Studio 2010.

At its core, a controller class is a class with a collection of public methods but the hardest part of it is the number and purpose of methods and the structure of the code you associate with each method.

Adding a new controller to an ASP.NET MVC application is never a task to be taken with a light heart. A controller is part of the presentation layer and exists to respond to some of the requests a user makes through the user interface. As such, the final set of controllers in an ASP.NET MVC application will effectively meet the needs of the presentation layer and map nicely to the URL scheme of choice. By the rule of thumb, you should endeavor to have one controller class for each significant entity in the domain of the problem that your application is called to solve. More precisely, you need a controller for each entity that is both significant in the domain and is exposed through the presentation layer. If no use cases exist for manipulating, say, an invoice then you probably don't need an InvoiceController class. At the same time, you may need a helper class in the data access layer for any server operation on invoice entities.

Code for an Action Method

More than the number of controllers and the list of their action methods, it's the structure of the code in the various action methods that determines how well designed an ASP.NET MVC application is. The ideal template of an action method can be outlined through the following steps.

  • Process input values
  • Perform the intended task
  • Process calculated values and deal with errors
  • Prepare the view model
  • Select the view to render

The first step is mostly accomplished automatically through model binders. This fact moves the emphasis for developers from the binding algorithm to the proper definition of the signature of the method. The default model binder, in fact, works well for most applications. The need for a custom binder is commonly limited to situations in which you need to process special input forms with a granularity different from the granularity of the data types used in the signature.

The code used to perform the task associated with the action method is the most critical part. How do you want the controller to work? Do you want it to be the direct executor of any task or you want it to simply orchestrate the activity of other components? As I see things, the answer is simple. The controller is logically part of the presentation layer; as such, it should delegate the implementation of any business related work to components in the business layer. From the perspective of a controller, performing the task should mean invoking an external component - typically, a coarse-grained method on a service layer - and delegating any business rule validation and operation to it.

It should also be noted that placing business code outside the controller requires extra work and extra layers. Layered solutions are a proven way of dealing with complexity; but additional layers are also a certain way of adding some complexity. In simple scenarios, moving business code outside the controller makes the solution inherently more complex. To exemplify, if you're writing a simple data entry Web application with no significant business rules to validate, you can perform data access right from the presentation. It would not make perhaps for an "ideal" application, but it would do its job quickly and effectively.

When the controller yields to some business layer component, it may receive error messages resulting from the server operation. A responsibility of the controller is integrating these messages into the view. More in general, the controller is responsible for incorporating any calculated response into the view. ASP.NET MVC requires that the controller packs data into a dictionary (or preferably into a strong typed view model object) and passes it down to the view.

In ASP.NET MVC, a controller's method is not responsible for producing the response itself. It is, however, responsible for triggering the process that will take a distinct view object to render content to the output stream. The action method identifies the type of response and sets up an ActionResult object as appropriate. Various types of result are supported natively such as file, plain data, HTML, JavaScript, JSON, and others can be added via custom classes.

Extensions to the Controller

Even in moderately complex applications, the controller has a few dependencies - logger, services or repositories, perhaps some text provider for localization. How would you handle these dependencies? The most natural answer is that you can inject dependencies into the controller through one of the IoC containers available today such as Unity, NInject, or Autofac to name just a few.

This approach gives you the greatest flexibility, but forces you to register your own controller factory. A made-to-measure controller factory is necessary because the default factory can only use the default parameterless constructor of the controller. A custom factory, instead, can inject any additional parameter in the controller. For example, it could just use the container object to resolve the controller and all of its possible, chained dependencies:

This means that if you have a controller like the one below, and all involved types are registered with the container of choice, then you're all set with the simple registration of the factory shown in the preceding listing.

When you have to deal with the dependencies of a controller, you can also opt for a more lightweight solution that doesn't require the use of an IoC framework. Your controller class will look like the one below:

Invoked by the default factory, the default constructor will anyway instantiate correctly all of the dependencies your controller may have. Adding a new dependency is as easy as adding a new private member. At the same time, you have a second constructor where dependencies are listed explicitly thus making testing the controller just a breeze.

Summary

To a careless observer, the controller may look like the code-behind class of ASP.NET Web Forms, that is just the place where you start writing the code that performs the action. What would be the difference between ASP.NET MVC and Web Forms then? Oh well, controllers are separated from views and offer SoC and testability.

All of this is correct, but considering the controller simply the "place where you start writing code" for an action is a dangerous approach. The controller is part of the presentation layer and all you should really expect from it is delegation of the execution to some other module. That should be the rule; simpler approaches are still possible and, to some extent, encouraged, but only as the exception.

<<  Previous Article Continue reading and see our next or previous articles Next Article >>

About Dino Esposito

Dino Esposito is one of the world's authorities on Web technology and software architecture. Dino published an array of books, most of which are considered state-of-the-art in their respective areas. His most recent books are “Microsoft ® .NET: Architecting Applications for the Enterprise” and “...

This author has published 54 articles on DotNetSlackers. View other articles or the complete profile here.

Other articles in this category


Code First Approach using Entity Framework 4.1, Inversion of Control, Unity Framework, Repository and Unit of Work Patterns, and MVC3 Razor View
A detailed introduction about the code first approach using Entity Framework 4.1, Inversion of Contr...
jQuery Mobile ListView
In this article, we're going to look at what JQuery Mobile uses to represent lists, and how capable ...
Exception Handling and .Net (A practical approach)
Error Handling has always been crucial for an application in a number of ways. It may affect the exe...
JQuery Mobile Widgets Overview
An overview of widgets in jQuery Mobile.
Book Review: SignalR: Real-time Application Development
A book review of SignalR by Simone.

You might also be interested in the following related blog posts


MvcContrib working on Portable Areas read more
MvcContrib version control has moved to GitHub read more
The ASP.NET MVC ActionController The controllerless action, or actionless controller read more
You should NOT use ASP.NET MVC if. . . read more
Is ASP.NET MVC a half-baked solution? read more
MvcContrib v1.0 Released! Download now read more
MvcContrib Release Candidate posted to CodePlex - now with more consolidated packaging read more
ASP.NET MVC Release Candidate 2 read more
How to use Ninject with ASP.NET MVC read more
Donut Caching in ASP.NET MVC read more
Top
 
 
 

Please login to rate or to leave a comment.