“Controllerless” MVC with the MVCommand

May 25, 2010

When I first started working with ASP.NET MVC, I was excited to be rid of the drawbacks of the WebForms model: memorizing the order of the page life cycle events, the weight of ViewState, etc.  After working with MVC for a few months, I began to realize that the mantra of how it “moves your code-behind to a separate class” was all too real.  My controllers got huge while trying to handle all basic CRUD operations for a single page (and yes, IIMHO, once you approach 300 lines your classes are getting way too big).

Faced with this, I attempted to build a framework with ideas that I liked that Brian Donahue espoused in several blog posts.  I was able to mess around with my own framework, and I gave a high-level overview of it a while back.  Since then, I’ve been able to flesh out the framework as it was dog-fooded on several internal projects here.  Because it’s been used with some success (and a lot of changes occurred that made my previous post inaccurate now), I’d like to take some time to go into detail about the framework in a series of blog posts.

Introducing MVCommand

Yes, the name of the framework is the extremely original “MVCommand”.  The point was that I wanted to replace the concept of controllers with the ability to have a request map to one or more commands, whose only job is to retrieve data and return it.  The command should have no knowledge of the HttpContext, or even that it’s being used on the web at all.  It simply gets data from the view (in the form of a DTO), and interacts with the data access layer to retrieve the appropriate data, which is then returned.

The Front Controller

The title of this post has “Controllerless” in quotes because, in reality, this framework actually does use one controller.  Using the Front Controller pattern here allows the framework to utilize as much as possible of the already in place ASP.NET MVC framework.  My goal was to not rewrite MVC, but put a wrapper around it so that we could utilize its good parts without having to stick with the contoller model.

In MVCommand, the purpose of the front controller is to take in the current request, map it to the correct command (or set of commands), and return the data in the correct format (whether its putting data returned by the command into the ViewData dictionary, or serializing it to JSON).  My goal was to not have the command need to know how the data should be returned, but simply to have it returned and let the type of request determine how it should be used.

Mapping a Request to Commands

To understand this, first we must start by remembering how ASP.NET MVC breaks up the components of the request’s url for handling routing.  If you look in the Global.asax of any MVC project, you will see there are 2 keys by default: “controller” and “action”.  In MVCommand, I renamed these to “context” and “event”.  I liked these names better for the framework because controllers don’t exist in it, and I felt that a page really represented the context of the system.

Now, there are two ways that a request can map to one or more commands.  The first way is simply by placing the command in the appropriate namespace.  If the namespace ends with the context and event that maps to the request, any command in that namespace will be fired.  For example, if your url is http://myapp/user/edit, the context is “user”, and the event is “edit”.  Therefore, any commands that have a namespace that ends with “user.edit” will be fired.  I liked this functionality because I didn’t want to require configuration changes every time you add a command to your application.

The second way to map commands is by using a dictionary, which MVCommand contains a fluid API for.  Basically, you can tell MVCommand to map the context and event to the set of commands you supply in your dictionary, instead of using namespaces.  This is useful both for sharing commands across multiple requests (where different pages need the same data), and for when firing commands in a specific order is important.

The Code

Now that you’ve read through all of this, feel free to check out the code.  It’s hosted on github at: git@github.com:cerikpete/MVCommand.git.  You will notice 2 branches up there: master and mvc2.  Master, as you might guess, works with the MVC 1.0 framework, and the MVC2 branch contains updates needed to work nicely with ASP.NET MVC 2.0 (and also VisualStudio 2010).

What’s Next?

I plan to write a series of blog posts detailing how to get started with MVCommand on your project, as well as go into detail about what the internals are doing.

My hope is you find that there is pretty low friction in getting started with MVCommand, and that its APIs are useful, and I look forward to any feedback.

Advertisement

3 Responses to ““Controllerless” MVC with the MVCommand”

  1. [...] to Vote“Controllerless” MVC with the MVCommand (5/25/2010)Tuesday, May 25, 2010 from cerikpeteWhen I first started working with ASP.NET MVC, I was excited to [...]

  2. Renso said

    Nice post Erik, great concept. Key here I think is that Mvc framework is plug-able and extensible that makes this all possible. What comes to mind is the out-of-the-box attribute support that comes with ASP.Net Mvc, like the ones for Actions, like [AcceptVerbs(HttpVerbs.Get)], the TModel binder options, and others? Also the Edit action for example automatically knows it is for a post when it contains a FormCollection parm as opposed to a regular Edit action that has none other than regular parms like int accountId. Not sure how you will or should handle these or if MvCommand is not intended for this kind of use.

  3. cerikpete said

    The ideal is that commands should have no knowledge that they’re being used in an HTTP context. Therefore, they shouldn’t have verb limitations (i.e., get/post). Your calls should set the appropriate HTTP headers (in a RESTful way) to specify a get or post request. It might be beneficial in the long run to limit this on the command side, like you said, but that’s still something that should remain outside of the command itself, and maybe something I can look into.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.