ASP.NET MVC Opinionated Software
Out of the box, the ASP.NET MVC framework is very bland – it provides the hooks to add conventions and functionality, but doesn’t provide much in the way of structure itself. To get the most benefit out of it, you need to add in your own set of preferences, conventions, and behaviors.
In the book Getting Real by 37signals, this is referred to as “Opinionated Software.” Don’t be all things to all people, take a stand on the features that you think are important. In that light, here’s a summary of some of a few of the things that I think are the most important opinions that should be added into your basic ASP.Net MVC project. This is of course strongly founded on the work of others, modified here and there to fit the situation for a given project.
No Magic Strings!
ASP.NET MVC relies heavily on dictionaries keyed by strings to get things done. Using formCollection[“name”] to refer to a value posted back is just asking for subtle & hard to find bugs later – when somebody changes the View ID to “firstName,” for example.
Another common scenario: Html.ActionLink(“linkname”, “Create”, “SomeController”); should be replaced with Expressions instead: Html.ActionLink<SomeController>(“linkName”, c => c.Create()); You gain intellisense, refactoring ability, R# validation, and some limited compiling support if your code changes.
In the MVC pattern, the Controller .. controls. It receives an inbound request to do something (an “Action,” like Create or List), and orchestrates both with Application Services to make that something happen, and the View that will present the result.
The Controller does not do the work itself, because that would violate the Single Responsibility Principle (the Controller now controls/orchestrates, plus loops through a collection summing values, or generates an HTML string, or whatever).
Sometimes the line blurs between Controller responsibilities and Application Services responsibilities, but the guiding principle should be that the Controller does not do business logic.
Strongly Typed Views
This is related to avoiding Magic Strings… never bind your Views to a collection of Name/Value pairs. It makes development more difficult and opens you up to a class of bugs that you could avoid entirely if you bind to a Model or ViewModel object instead.
ViewModel != Domain Model
There is some confusion over the term ViewModel, thanks to the View/Model/ViewModel (aka “MVVM”, or “I-Can’t-Believe-That-They-Named-It-THAT” pattern). In this particular case, I’m talking about something that is like your Domain Model, except is stripped down and simplified to work with a specific View. But to the View, this ViewModel is going to be the “M” in MVC and fill all roles and obligations therein. (This might be obvious to everybody, I hope so anyhow.)
Consider a View that shows some sort of table of Order data. Perhaps you want to show the person who sold the order in this table. One idea is to bring back a fully populated Order object, with the expected references to Users, OrderDetails, and whatever. But, this could be a lot of data, and in any case it will be awkward to work with – what if you just had a slimmed down OrderView object, which exposes a SalesName (string) property? Now its a simple projection from your fully-behaviorized Domain Model Order, to essentially a Data Transfer Object (except its not necessarily going over any wires). The view becomes simpler, you don’t have to clutter up your Order or User with View-specific functionality, things just get easier.
There is another very good reason to separate what model your view works with, vs. what model your domain works with — model binding. There are some very real security implications to think about here, which will be the subject of a future post. But in short I leave you with this: “The Client is in the hands of The Enemy.” Remember that they can POST whatever they want to your MVC application, its your responsibility to validate the inputs carefully.