Extending ASP.NET MVC To Add Conventions

UPDATE: Much of this post is out-of-date with the latest versions of MVC. We long sinced removed the ControllerAction attribute.

Note: If you hate reading and just want the code, it is at the bottom.

Eons ago, I was a youngster living in Spain watching my Saturday morning cartoons when my dad walked in bearing freshly made taquitos and a small cup of green stuff. The taquitos looked delicious, but I was appalled at the green stuff.

Was this some kind of joke? My dad wanted me to simply just taste it but I refused because I absolutely knew it would suck just by looking at it. The green stuff, of course, was guacamole, which I love by the truckload now.

Guacamole

With all the code samples and blog posts published about the ASP.NET MVC Framework, there’s been some debate about the big picture stuff.

  • Should I be looking to migrate to this? (Depends)
  • Will this replace Web Forms? (NO!)
  • Is this feature even necessary? (I sure think so!)

Interestingly enough, the most passionate debate I’ve seen is not around these big picture questions, but is centered around very specific detailed design decisions. After all, we are software developers, and if there’s one thing software developers love to do, it’s debate the design and architecture of code.

I’m no exception to this rule and admit I rather enjoy it, sometimes to the point of absurdity and pointlessness. At the end of the day, however, the framework developer has to make a decision and move forward so he or she can go home. These choices will never make everyone happy because there is no such thing as a perfect design that satisfies everyone.

That doesn’t mean we give up trying though!

Hopefully the quality of feedback the framework designer receives pushes that designer to reevaluate assumptions and either reinforces the decision, or provides insight for an even better decision.

One design decision in particular that seems to have drawn somewhat disproportionate amount of attention is the decision to require a [ControllerAction] attribute on public methods within a controller class that are meant to be a web visible action. There’s been much discussion in various mailing lists and in some blog posts before the CTP has been released.

This post is not going to rehash these concerns nor address these concerns. If I think it would help, perhaps I will have a follow-up post in which I explain some of the reasoning behind this decision. This would give those who feel all that strongly about this a chance to make a well-reasoned point by point refutation should they wish.

I worry about focusing too much on this one issue. I don’t want it to become such a hang up that it disproportionately dominates discussion and feedback at the expense of gathering valuable feedback on other areas of the framework. There is much more to the framework than this one issue.

At the same time, I do understand this issue is about more than a single attribute. It’s about applying a design philosophy centered around convention over configuration and where it works well and where it doesn’t.

Like guacamole, I hope that critics of this particular issue don’t judge it by sight alone and give it a real honest try. See if it makes as big a difference as you think. Maybe it does. Maybe it doesn’t. At least you’ve tasted it. Feedback based on trying it out for a while is more valuable and potent than feedback based on just on seeing sample code.

Please understand that I’m not dismissing feedback based on what you have seen. It certainly is valuable and much of it has been incorporated and discussed in our design meetings. Some of it has led to changes. All I am saying is that as valuable as that feedback is, feedback based on usage is even more valuable.

The Convention Controller

However, if you still hate it, I have a little workaround for you :). I’ve written a custom controller base class that allows for a more “convention over configuration” approach to building your controllers named ConventionController.

By inheriting from this controller instead of the vanilla Controller class, you no longer need to add the [ControllerAction] attribute to every public method. You also don’t need to call RenderView if you name your view the same name as the action. Of course this means you cannot use strongly typed views and must use the ViewData property bag to pass data to the view.

So instead of writing your controller like this:

public class HomeController : Controller
{
  [ControllerAction]
  public void Index()
  {
    //Your action logic
    RenderView("Index");
  }
}

Using my class you could write it like this

public class HomeController : ConventionController
{
  public void Index()
  {
    //Your action logic
  }
}

The key point in posting this code is to demonstrate how easy it is to override the behavior we bake in with something more to your liking. When you look at the code, you will see it wasn’t rocket science to do what I did. Extending the framework is quite easy.

We may not provide the exact out of box experience that you want, but we do try and give you the tools to control your own destiny with this framework and provide you with the power of choice.

I will look into adding this to the MVC Contrib project started by some community members. In the meanwhile, if you like this approach or style of building controllers, you can either add the ConventionController.cs class to your own project or compile it into a separate assembly and drop it into your own projects.

To get to this class, download the example code.

What others have said

Requesting Gravatar... Tales from the SharpSide Dec 09, 2007 12:29 AM
# Links from the Sharpside [12-09-07]
Links from the Sharpside [12-09-07]
Requesting Gravatar... Aaron Jensen Dec 09, 2007 12:36 AM
# re: Extending ASP.NET MVC To Add Conventions
Nice Phil. This is another example of why the controller should be broken up into separate services. Wouldn't it be nice if you could just add a different IActionInvoker and IViewRenderer to your container instead of having to use inheritance? :)
Requesting Gravatar... Haacked Dec 09, 2007 12:49 AM
# re: Extending ASP.NET MVC To Add Conventions
Hi Aaron, we've received this feedback from you and others. We're looking into it. It's too late to change for the CTP, but we'll evaluate it for the future releases.

I have to say though, since we don't ship with a DI framework (choose your own), using inheritance certainly is a lot easier. I don't have to know what your DI container is, I just post a subclass. Also, he DI approach is a lot more configuration.

This is not a ding against composition over inheritance nor a ding against your idea, only to say inheritance is a valid choice sometimes. :)
Requesting Gravatar... Ayende Rahien Dec 09, 2007 2:00 AM
# re: Extending ASP.NET MVC To Add Conventions
It is good to see that it is easy to do.
Requesting Gravatar... Aaron Jensen Dec 09, 2007 2:12 AM
# re: Extending ASP.NET MVC To Add Conventions
> I have to say though, since we don't ship with a DI framework
> (choose your own), using inheritance certainly is a lot easier. I
> don't have to know what your DI container is, I just post a
> subclass. Also, he DI approach is a lot more configuration.

You can provide the classes and a new implementation of ControllerFactory. No container needed.

> This is not a ding against composition over inheritance nor a
> ding against your idea, only to say inheritance is a valid choice
> sometimes. :)

Define valid. If by valid you mean it works, then yes, of course. You can do plenty with inheritance. That doesn't mean its the best way. I'm not going to beat a dead horse on the value of composition vs. inheritance, but maybe someone should as it seems a lot of people still don't get it. Putting out a framework that requires per-controller subclassing to make things easily testable... well, is just a bad idea and certainly doesn't show off good practices.
Requesting Gravatar... eric hexter Dec 09, 2007 5:37 AM
# re: Extending ASP.NET MVC To Add Conventions
It is good to see the alternative approaches being talked and prototyped. This is a nice sign that shows some your listening. :)
Requesting Gravatar... David Fauber Dec 09, 2007 6:08 AM
# re: Extending ASP.NET MVC To Add Conventions
Personally I don't find the attribute thing to be a big deal, and it seems a surprising thing to get bent over. Don't you run into the same sort of thing with AOP in various places? (This is a serious question, not rhetorical)


"It adds a lot of extra typing for no real benefit."
I do think this coming from the ALT.NETinati is pretty funny, in line of the "roll eyes" attitude when Mort says the same of DI. (and yes, that is a completely unfair apples and oranges comparison but I still find it hilarious)

One other thing:
Controller is going to be in System.Web.Extensions right?
Requesting Gravatar... Sean Chambers Dec 09, 2007 7:02 AM
# re: Extending ASP.NET MVC To Add Conventions
Phil,

This post was EXACTLY what I personally was looking for. I must admit that I haven't looked at the framework enough yet and I should have dove deeper before I made a post asking questions. Next time I will be sure to do my research first.

Now that you have described that this is very easy to accomplish I personally am satisfied. I don't think there is any point of talking about the matter any further. I'm sure once the CTP comes out I'll have many more things to pick at =)

@David
This type of thinking and labeling people as part of a particular community is hurting more then it is helping. We really need to get past this mindset if we want to progress and move forward. In addition, I really feel we should not be labeling people as "morts" anymore. This is very counter-productive and doesn't help anyone as a whole. Call me what you will but let's try to keep the sweeping stereotype's to a minimum please. This will help everyone out =)
Requesting Gravatar... David Fauber Dec 09, 2007 9:56 AM
# re: Extending ASP.NET MVC To Add Conventions
"Call me what you will..."

I just used your quote since it was the best one-line representation of what I've perceived as a general attitude, no need to martyr yourself. :)

It was just something I thought was funny (although completely unfair, as I pointed out), and was trying to use "domain language" to get across my meaning. Anyway, the post-mortem will reveal that I made a low-content post that ultimately did more harm than good. Sorry about that, I plead boredom while waiting on the ctp and now return you to productive discussion.
Requesting Gravatar... Haacked Dec 09, 2007 11:21 AM
# re: Extending ASP.NET MVC To Add Conventions
Yes please, productive discussion is encouraged. :)

@David, for the CTP, Controller is in the assembly System.Web.Extensions but the namespace System.Web.Mvc.

Requesting Gravatar... AgileJoe Dec 09, 2007 11:39 AM
# Convention over Configuration: The Haack Response
Yesterday Sean and I talked briefly about Convention over Configuration and how disappointed we both
Requesting Gravatar... Jason Haley Dec 09, 2007 12:16 PM
# Interesting Finds: December 9, 2007
Requesting Gravatar... Nick Parker Dec 09, 2007 2:45 PM
# The Pitfalls of Concession
The Pitfalls of Concession
Requesting Gravatar... Sean Chambers Dec 09, 2007 4:32 PM
# re: Extending ASP.NET MVC To Add Conventions
@David
I apologize for snapping. Hindsight tells me that I was a little harsh in my response to you.

To add to the discussion, I am greatly looking forward to the CTP. When is the exact date of the release Phil?
Requesting Gravatar... Haacked Dec 09, 2007 4:48 PM
# re: Extending ASP.NET MVC To Add Conventions
@Sean I appreciate you being civil and apologizing Sean. It really elevates the level of discourse. It's funny, as we get closer to the CTP, I've noticed better discourse in several forums I'm in. ;)

As for the exact date, I'm afraid to say anything in case some last minute thing comes up again. How's "sometime soon" for an answer?
Requesting Gravatar... Christopher Steen Dec 09, 2007 10:17 PM
# Link Listing - December 9, 2007
ASP.NET Asp.Net Control For Google Charts [Via: Luke Foust ] Sharepoint Forms based apps with Infopath...
Requesting Gravatar... Christopher Steen Dec 09, 2007 10:17 PM
# Link Listing - December 9, 2007
Link Listing - December 9, 2007
Requesting Gravatar... Mike Thomas Dec 09, 2007 11:39 PM
# re: Extending ASP.NET MVC To Add Conventions
One way that the framework could make changes like this easier would be to break up the execution flow into more virtual methods. For example add a 'protected virtual GetActionMethod(string actionName)' to the Controller class :)
Requesting Gravatar... Florian Krüsch Dec 10, 2007 3:14 AM
# re: Extending ASP.NET MVC To Add Conventions
Yes, it is nice that you have the flexibility to do that. On the other hand, the attribute makes it safe and is consistent with the rest of the framework, which are IMO good reasons to have it there.
Also, great flexibility and 'convention over configuration' are somewhat contradictive.

cheers
Florian
Requesting Gravatar... AgileJoe Dec 10, 2007 8:45 PM
# Now MVC has rescues: Kind Of
I really missed using the [Rescue] attribute from MonoRail in the ASP MVC framework. I missed it so much
Requesting Gravatar... Roberto Gattinoni Dec 11, 2007 2:13 AM
# re: Extending ASP.NET MVC To Add Conventions
I'll immediately download your Controller class and use it. Having experienced the elegance and conciseness of Rails I must say this is the right choice.
Requesting Gravatar... Jeffrey Palermo Dec 14, 2007 5:00 AM
# re: Extending ASP.NET MVC To Add Conventions
If anyone here is motivated, we'd love to have this functionality in the MvcContrib open source project.
Requesting Gravatar... Ayende @ Rahien Dec 16, 2007 11:47 PM
# On the faults of thinking: It is extensible, the users can add this
On the faults of thinking: It is extensible, the users can add this
Requesting Gravatar... Francois Tanguay Dec 19, 2007 6:11 PM
# re: Extending ASP.NET MVC To Add Conventions
Not sure the ConventionController supports RedirectToAction. From what I see:

class MyController : ConventionController
{
public void Foo()
{
RedirectToAction("Bar");
}
}

When Foo returns, won't it result in a call to RenderView("Foo")?
Requesting Gravatar... anonymous Mar 30, 2008 3:37 PM
# re: Extending ASP.NET MVC To Add Conventions
Can someone explain what the big deal behind the requirement to put that attribute above the controller methods is? Is there some valid design aspect that you can make a good point on or is this just the fact that developers are too lazy to put a simple attribute on a method? Which is it here? Is it a matter of just sickening nerd coders that have nothing to do or is there more behind the problem of simply having to include a lousy attribute on a method. I mean someone please explain this "problem" to me cause I don't get it.
Requesting Gravatar... Dave Mar 30, 2008 3:44 PM
# re: Extending ASP.NET MVC To Add Conventions
OK, let me observe.

I mean really, don't most developers out there have any sort of life? Not even 10%? Go have some "guacamole" and watch a football game and get away from code for once in your life and quit bitching about such stupid sh**. Who cares about this lousy attribute! Just use it and go home and enjoy your life!!! Find a girlfriend, get married, go to a strip bar, start a side business. You only live once...I'm sure there is far better use of your time everyone then debating a simple requirement such as this. If you have that much time, do what Phil says, go and reinvent MVC every weekend. Just use it and maybe improved it but damn, I mean really. I have far better things to do with my time.

- Dave
Requesting Gravatar... Haacked Mar 30, 2008 5:59 PM
# re: Extending ASP.NET MVC To Add Conventions
It's a moot point. We ended up removing the attribute.
Requesting Gravatar... AG Aug 04, 2008 8:29 PM
# re: Extending ASP.NET MVC To Add Conventions
Phil, How would handle the situation where you want a to do something more intrinsic without compromising the spirit of MVC. For example, lets say you wanted to provide fine grained access to sections of a web page i.e <%= if (IsVisible("sectionname", username))%>. Of course I would want to just access a collection that already had the data i needed (lets call it a dictionary). In the web forms days I would just drop in an HttpModule that would load the data and just access the data (I know barf).
Requesting Gravatar... haacked Aug 04, 2008 9:02 PM
# re: Extending ASP.NET MVC To Add Conventions
I'd use an action filter.

What do you have to say?

(will show your gravatar)
Please add 1 and 1 and type the answer here: