There seems to be much confusion about the usage of typed views and ViewModel pattern in ASP.NET MVC. What it is, how it came about and when best to use it? In this article I discuss how the ViewModel pattern came about, what problem it addresses and how it can be implemented in ASP.NET MVC. In later blog posts I will also discuss a few of the variants on the ViewModel pattern, their use cases, their benefits and their disadvantages.
Let’s say we are developing a blog application. For the home page – or the Index view – we display a list of Posts along with the links for the most popular posts. Here are the models for our scenario. I am using EF 4 Code First as my ORM solution here.
public class Post
{
public int ID { get; set; }
public string Title { get; set; }
public string Body { get; set; }
public string CreatedBy { get; set; }
public string CreatedOn { get; set; }
public ICollection<Comment> Comments { get; set; }
}
public class Comment
{
public int ID { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Url { get; set; }
public string Body { get; set; }
}
public class PopularPost
{
public int ID { get; set; }
public Post Post { get; set; }
// The number of times the post was viewed/read.
public long ViewedCount { get; set; }
}
ViewData pattern
One option available to us out of the box is the usage of ViewData both in our controller action method and in our aspx views. So the usage might result in our Controller action method as follows,
public class PostController : Controller
{
private readonly SimpleBlogDb _simpleBlogDb = new SimpleBlogDb();
public ActionResult Index()
{
// Get the top 10 most recent posts.
var posts = from d in _simpleBlogDb.Posts
orderby d.CreatedOn ascending
select d;
ViewData["Posts"] = posts.Take(10);
// Get the top 10 most read posts.
var popularPosts = from p in _simpleBlogDb.PopularPosts
orderby p.ViewedCount descending
select p;
ViewData["PopularPosts"] = popularPosts;
return View();
}
}
Then in our Index view, we might implement it as follows:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> <%@ Import Namespace="SimpleBlog.Models" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Index </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Index</h2> <% foreach (var post in ViewData["Posts"] as IEnumerable<Post>) {%> <li class="post"> <h3> <%: post.Title %> </h3> <div class="post-info"> <span> <%: post.CreatedBy %></span> - <span> <%: String.Format("{0:g}", post.CreatedOn)%></span> </div> <p> <%: post.Body %> </p> </li> <% }%> <div> <% ViewData["PopularPosts"] as IEnumerable<PopularPost> %> </div> </asp:Content>
Disadvantages of ViewData
One disadvantage of this approach is that the use of “magic strings” such as “Posts”, “PopularPosts” could be a source of Null Reference exception errors. The most frequent common cause for this type of error is a typo when setting or getting values from ViewData using these “magic strings”.
Most of us developers tend to overlook – initially – the fact that the source of our errors is a simple typo. Only after going through a few debugging session do we realize these errors – albeit with much chagrin. The more frequently we use these “magic strings” as variables in our application the more chances we increase of such bugs and thus compound negatively our productivity.
In addition, changing the values of these “magic strings” is also difficult once they are used in our views, controllers and or view helpers. In our scenario, the “magic strings” would also propagate in our create, edit, and details views thus making our solution brittle to change and refactoring and increasing possibilities of errors occurring.
In summary, though the usage of magic strings look innocuous initially, the more we use them the more unwieldy and difficult to manage they become.
Typed Views
The deficiencies introduced by the usage of magic strings in our application can be removed – by and large – via the usage of strongly typed views and ViewModel pattern. Let’s first start with a strongly typed view since usage of it necessitates our usage of ViewModel pattern.
For our Index view since we need to display a list of Posts, here’s how we make it a strongly typed view via the VS.NET 2010.
- First put the cursor in our Index action method, right-click and choose Add View option.
- Choose strongly typed view option and select the model it will bind to. In our case we choose the Post model.
Our resulting strongly typed Index view.
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<<SimpleBlog.Models.Post>>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Index
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<ul class="posts">
<% foreach (var post in Model)
{ %>
<li class="post">
<h3>
<%: post.Title %>
</h3>
<div class="post-info">
<span>
<%: post.CreatedBy %></span> - <span>
<%: String.Format("{0:g}", post.CreatedOn)%></span>
</div>
<p>
<%: post.Body %>
</p>
</li>
<% } %>
</ul>
<div> <% ViewData["PopularPosts"] as IEnumerable<PopularPost> %> </div>
</asp:Content>
Note lines 1 and 7. Our code is more concise as we do not have to use casting. Similarly for our controller we we need to send our strongly typed variable for our view to use. Here's how we modify our controller action method to make use of our strongly typed Index view.
public class PostController : Controller
{
private readonly SimpleBlogDb _simpleBlogDb = new SimpleBlogDb();
public ActionResult Index()
{
// Get the top 10 most recent posts.
var posts = from d in _simpleBlogDb.Posts
orderby d.CreatedOn ascending
select d;
// Get the top 10 most read posts.
var popularPosts = from p in _simpleBlogDb.PopularPosts
orderby p.ViewedCount descending
select p;
ViewData["PopularPosts"] = popularPosts;
return View(posts.Take(10));
}
}
Note line 19 above where we send posts variable for the perusal of our view. Now, we did manage to make our view strongly typed to IEnumerable<Post> and remove the usage of "Posts" magic string. However, "PopularPosts" magic string still remain. Therein lies our problem, typed views in ASP.NET MVC can only be associated with one Type but our view - Index - also needs Popular Posts data to fulfil our requirements. So how do we solve this problem?
ViewModel Pattern
Enter ViewModel pattern. As its name implies, the ViewModel pattern encapsulates the data requirements of a view. In ASP.NET MVC ViewModel is a POCO - plain old CLR object.
For our scenario, here's how we implement it. The accepted convention in ASP.NET MVC is to put our view models in a separate folder named 'ViewModels'. The figure on the left shows what our folder structure might look like.And here's our POCO ViewModel implementation.
public class PostIndexViewModel
{
public IEnumerable<Post> Posts { get; set; }
public IEnumerable<PopularPost> PopularPosts { get; set; }
}
We might start to wonder the differences between our Model classes and our ViewModel classes. One important difference being that ViewModels are not directly persisted in the database/storage. Secondly, the data contained within ViewModels are optimized for a specific view usage and as such are generally not reused across multiple views. Third, ViewModels encapsulate our Model classes as we have done in our PostIndexViewModel.
Now that we have our shiny new PostIndexViewModel, here's how we use it in our controller action method and our view. First, our refactored Index controller action method.
public class PostController : Controller
{
private readonly SimpleBlogDb _simpleBlogDb = new SimpleBlogDb();
public ActionResult Index()
{
var postIndexViewModel = new PostIndexViewModel();
// Get the top 10 most recent posts.
var posts = from d in _simpleBlogDb.Posts
orderby d.CreatedOn ascending
select d;
postIndexViewModel.Posts = posts;
// Get the top 10 most read posts.
var popularPosts = from p in _simpleBlogDb.PopularPosts
orderby p.ViewedCount descending
select p;
postIndexViewModel.PopularPosts = popularPosts;
return View(postIndexViewModel);
}
}
Note lines 7, 14, and 21. We have completely obviated the need for "magic strings" in our controller action method. And here's our refactored Index view.
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<SimpleBlog.ViewModels.PostIndexViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Index
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<ul class="posts">
<% foreach (var post in Model.Posts)
{ %>
<li class="post">
<h3>
<%: post.Title %>
</h3>
<div class="post-info">
<span>
<%: post.CreatedBy %></span> - <span>
<%: String.Format("{0:g}", post.CreatedOn)%></span>
</div>
<p>
<%: post.Body %>
</p>
</li>
<% } %>
</ul>
<div> <% Model.PopularPosts %> </div>
</asp:Content>
Now that we have completely removed the usage of "magic strings" from our application, we can leverage the C# compiler to compile our views along with our other C# files. By default, in an ASP.NET MVC project, views are not compiled so we need to explicitly enable this property in our project file. Let's open our .csproj file in a notepad or some other text editor. Look for the MvcBuildViews property and set its value to true. Like so,
<MvcBuildViews>false</MvcBuildViews>
Benefits of ViewModel and Strongly Typed Views
The benefit of using this approach to application development in ASP.NET MVC is that our development process is more productive. This is so because of the following
<
ol>
In some cases, errors in magic strings could go undetected for a long time.


