Asp.Net MVC: My Personal View Rules
I’ve been working with a team of guys on several Asp.Net MVC projects since October of 2009. While that isn’t the greatest amount of time, and I’m still no expert, I thought I’d jot down a few of the practices that we have developed to help make coding a bit smoother. Asp.Net MVC, as with every new technology can be used poorly, and when use poorly you try to identify why that code was bad, how it could have been done better.
First, lets think about what the view should be doing – in a single responsibility sort of way: turn data into html. That right there rules out several options. No retrieving data, no extra data transformations. Just turn some data into html. And frankly, that is complicated enough. So a side goal that I strive for is to create a markup page (the aspx) that is similar to the desired html output. The main reason for that side goal is to make double checking the output that much easier. I want to see a ‘div’ in my markup, and have a reasonable idea where that ‘div’ will show up in the html.
- Keep as much code out of your views as you can.
Don’t make this rule overly simplistic. Some code belongs in the view. A ‘for’ loop to create a table, a simple ‘if’ block to show administrator functionality, stuff like that. But you shouldn’t be having to specify the DateTime format, or string parsing. That is what the ViewModels should do for you. Rule of thumb, if you see a block where there is more C# than HTML, you probably did it wrong.
2. Make Views typed.
This is true for all views where you have to pass data from the controller to the view. Make a View Model for the view and pass data via that model. This opens up a whole host of better patterns for you, like typed HtmlHelpers. As a result, it is VERY rare that I will share a view model between views, or even Controller Actions. I make separate models for GET, POST, and DELETE. I guess my view is, the more the merrier.
3. Make the View Models specific to the needs of the view.
OK, this isn’t actually a View best practice, but it is highly related. If you try to keep the model for the view too generic, you end up with a lot of logic in the view to transpose the data into something useful. The key point is that the data in the model serves the view, so all of the work to get the data into the correct format should be done when putting the data into the model. I will often take this to the point where the model will give html elements in the view their CSS classes. So that means I have more than data from the database in the views.
Side note: when it comes to populating View Models with data specific for the View, AutoMapper rocks! That is all.
4. Custom Html Helpers are wonderful things
It is remarkably simple to create your own Html Helper, and once you get the hang of them they are beautiful. They are wonderful little ways to encapsulate a small amount of logic so you can get it out of the aspx view. Use them to encapsulate small amounts of code you need in various place through the project.
Another little “trick” I will use from time to time to create custom models just for a html helper (passed in via the view’s view model). I have a few places where I need to change the markup because of the browser being used…so I create a custom helper that can detect the browser.
5. Standard HTML Helpers are great, but remember html
The key point I’m trying to make here is to become familiar with the output of the standard HTML helpers. While the helpers can be great, they have their warts (anything having to do with an attribute name/value is a bit ugly). Sometimes it is easier to swap them out with the standard html (especially with inputs) to get the exact output you want. As a bonus, it is easier for the next guy coming in to figure out what you were after. Currently, I’d say I use the helpers about 50% of the time over raw HTML.
Now, typing the html, or the helper, still kind of stinks. You have to type the same code over and over. Take a look at what Zen-Coding does. You can do the same thing with ReSharper Templates or Visual Studio snippets…or just install one of the ReSharper or Visual Studio pluggins. But beyond that, there is an art to customizing Visual Studio that you should learn.
6. Wrap all links in Url.Content and Url.Action
7. Get to know Partial Views for Ajax calls.
8. Make the Master page work for you.
It isn’t that there is something inherently wrong with the existing master page that you get when you create a new Asp.net MVC project. Typically it is 80% of what you would want. But, as soon as I know what my general page is supposed to look like, I rip right into the Master Page. Also keep in mind that you can nest Master Pages as well.
9. Think about what a designer would want.
OK, 10 rules is quite enough (I didn’t even think I would get that many). To the american’s reading this: Happy Independence Day.
18 thoughts on “Asp.Net MVC: My Personal View Rules”
Happy Independence Day.
Your views are shared by me, but what about keeping logic out of your views?
Not sure I agree about having as many view models as possible. If you can chuck one or two collections into the property bag then surely it is a lot simpler than creating a view model – project-wide this must be immensely simpler and easier to maintain.
@Jag: I didn’t directly address the “keep login out of your views”, but indirectly that is covered by #1. If you don’t have any code in the view, you wont end up with logic in there either.
@nick: as many as possible isn’t quite right, but having view-models specific to a purpose is more what I was after. And frankly, I don’t see having many classes as making the project much simpler. With fewer classes you end up with loads of special case logic that actually does become a maintenance issue.
I can’t entirely agree with making view models that are specific enough to include formatted strings, because at the end of the day, everything displayed is a string. I use an extension method for DateTimes to format them, because I’m not going to throw away entities by having to map them all to something else. I realize there are things like AutoMapper, but frankly I don’t think a “ToAwesomeString()” method in a view is selling my soul.
i’ve been using asp.net mvc around the same period of time and all my web dev now is exclusively mvc. I have never used HTML helpers (relying on pure html), but I have used some advanced constructs and had a little adventure with mvccontrib (though I didn’t use it in a later project).
The project that I am buidling now is my third professional project in MVC. The first too scripts can be seen at: http://codebix.com, and http://astro91.com
Not top-of the line stuff but we have a fair mix of jquery though I am no designer the websites are doing okay.
But my MVC learning odyssey has now seemed to arrive at a dead end, I know enough to get by and there’s no major push to learn more. Most of the articles are no revelation either.
Now I need some motivation to dig out adcanced mvc content and read it.
@Jeff Putz: Actually, I’m fine with .ToAwesomeString() in the view. It is way better than .ToString(“my-crazy-date/time-format-string”) all over your code.
I think balance is the key. I don’t want to litter my project with viewmodels that serve as simple wrappers anymore than I want to litter my views with logic, but the fact is (in my mind anyway) that *view* logic is perfectly suited for putting in the view. String formatting is view logic, so there’s no reason to not include it. That said, I agree that helper methods are a good refactoring for cleaning up the HTML; I just think that it’s possible to take the “rules” too far in the other direction.
I also think something like formatting does belong in the view. Though I am still relatively new to MVVM and how to apply it efficiently. Currently stuff like date formatting is handled in the view via ValueConverters. (Then again this is a Silverlight application, not ASP.Net MVC) The important thing is I don’t want a web server doing anything with formatting.
I’m still iffy about adopting MVVM whole-hog over MVP for WPF and Silverlight for instance; but in MVP, the formatting of values was definitely something that was the responsibility of the View.
Thank you Chris for this article.
I particularly find interesting the ongoing discussion about rule #3 and what it means for the separation of concerns between layers. I think that inheritance should be used to build model classes.
Generic business rules should be coded in a base model class (ex: Customer) and presentation rules should end up in an inherited model class (ex: CustomerInvoice). In my example ‘CustomerInvoice’ class would have the responsibilities of formating customers fields and validate data for its use in the context of an invoice. ‘Customer’ class would also validate data but in the context of the business entity (ex: name should always be supplied no matter the context).
It could help maintainability and having classes closer to the data layer or to the presentation layer but not both while keeping most of the rules (business and presentation) out of the view. And its good OOP practice.
@Steve: Asp.Net MVC is not Silverlight/MVVM. Different rules will apply. Specifically because of the differences between the UI control sets. Some of what I talked about works for Silverlight/MVVM, but the particular advice of converting everything to string (for Asp.Net MVC) does not apply to Silverlight/MVVM where you have control sets that natively read the DateTime type.
@Pierre, this might shock you a bit. But I’ve gone down that road before, and don’t want to go there again. In fact, I would not suggest it at all for a web application. It complicates your ORM mapping considerably, and really serves no purpose that could not be better handled with composition.
So my CustomerInvoice would NOT inherit from Customer (or anything for that matter), but instead would have a Customer property. What inevitably happens when you start using domain class inheritance is that you get domain classes with more crap properties than valuable ones. Plus, now to hidrate the entity you have a tone more work that HAS to happen. Not so with composition.
Second, my preference is to have one set of domain classes specifically for the data access (Repository Domain), and separate Domain classes for Views, and sometimes different domain layers for other layers, and have a robust mapping layer. This seems like a lot more work, but it actually keeps things much cleaner.
But, in all fairness, my Domain (in the DDD sense) is not your Domain. Mine works very well for me. Not knowing your Domain, yours could work well for you, but not for me, and vise versa.
@Chris: True, So long as the server respects the current client’s Locale in both directions where applicable. In my experience, passing dates formatted as strings in anything other than ISO format eventually leads to pain.
With regards to having separate Model and ViewModel objects, this becomes almost obligatory because you do not want your data model polluted with UI concerns, such as validation rules, etc. In most ‘enterprise size’ applications you will be using different assemblies for your domain model, service layer, and UI so you will require something like AutoMapper to map between your domain and view models.
I saw an interesting variation in one of Scott Guthrie’s screencasts where he was using Linq or EF and everything was in one project. He was therefore able to use a partial class for the domain model which included all the validation rules and UI hints. This approach will not work using separate assemblies because partial classes have to be in the same assembly but it is an interesting option for smaller-scale projects.
@Rob: I have the greatest respect for Scott Guthrie, he is an amazing individual in Microsoft and doing excellent work. But I can’t recommend doing that. Even for Scott, I can only imagine his thinking was that he only had 30 minutes to do a demo, and how could he cram as much in there as possible.
Demos to not equate good coding practices.
But, I will say this in defense of that method: if you can code the site, start to finish, in under 4 hours then I don’t care what your code looks like. Worst case you can rewrite the entire thing later. If your project is going to take days to complete, then an ounce of prevention is worth a pound of cure.
Great article and very sound advice!
I hope you don’t mind, but I intend to make quite a few references to your article in my talk at mvcconf.com next week to demonstrate how the Spark View Engine can help you achieve a lot of what you talk about here. If that’s a problem for you, would you mind letting me know by email?
All the best,
Great post. It has a very good tips. Thank you.
I have a question concerning the rule #7. In wich way or how do you use the setTimeout to call the load() function? Could you post an example or something like that?
Thanks a lot.
$(myDivForTheResults).load(“<%=Url.Action("Action", "Controller") %>“)
Do you have a code sample that demonstrate this? It’d be a lot easier to see this than to mentally map it out. I’d like to see the automapper/composition over inheritance action in code.
By the way, the comment system here is kind of wacky. I was lost at first because your replies started on one page and the original comment ended on another.
Comments are closed.