The Model, the View, and the Dictionary

An object model for the view is better than a plain dictionary

CoreCoder

Languages: C#

ASP.NET VERSIONS: MVC

The Model, the View, and the Dictionary

An object model for the view is better than a plain dictionary

By Dino Esposito

ASP.NET MVC brings a blast of fresh air to the world of ASP.NET programming and revolutionizes established and consolidated patterns and practices in web application development. ASP.NET MVC forces you to apply a web-specific variation to the classic Model-View-Controller pattern (MVC) in every page you write.

In ASP.NET MVC, you design URLs around the use-case diagrams resulting from preliminary analysis of user requirements. Such URLs don't map to server page files but are associated with server-side actions and subsequent results. In this article, I'll discuss how results may flow into the view after the requested action has completed. ASP.NET MVC provides built-in tools you can use. I'll analyze and contrast the characteristics of each.

The (Well-Known?) MVC Dynamics

Much has been written about ASP.NET MVC since the first CTP in the fall of 2007. Most of this writing emphasizes the benefits of the MVC pattern versus the Page Controller model typical of ASP.NET Web Forms. It's hard to state that the MVC pattern is superior to the Page Controller pattern, which has fueled the ASP.NET platform for years. A much easier point to sustain is that the MVC pattern simplifies the implementation of features that more and more developers consider essential today. Separation of concerns and testability are two of the most popular features.

The MVC pattern was neither formalized for the ASP.NET MVC platform nor for the web as a whole. Instead, the MVC pattern was devised two decades ago as a general paradigm to lead toward more structured code. At the time, applications were monolithic blocks of code where everything took place within the front end. The MVC pattern taught developers to think of applications as the combined effort of three actors: the controller, the view, and the model.

The view, which is the front end, receives any user input and forwards such commands to the controller. The controller decides what to do, and in doing so it interacts with the application model. Any action taken by the controller then updates the model. The view receives changes from the model and refreshes itself.

In a nutshell, this is the true dynamic of MVC. And if you think about it for a moment, you can't help but realize that this is quite different from how ASP.NET MVC performs. Figure 1 shows the sequence diagram for the MVC pattern.

Figure 1: Sequence diagram for the classic MVC interaction model

The MVC Pattern for the Web

The web was still in the works when the first paper presenting the MVC paradigm came out around 1980, so it's no surprise that the MVC model requires significant updates to work for a web application. When developing Java Server Pages (JSP), Sun reworked and adapted the MVC paradigm for the web. The name of the resulting pattern is Model2, and it's what in the Microsoft space today is generically labeled as MVC. Figure 2 shows the sequence diagram for the Model2 pattern and explains very well how things work in ASP.NET MVC.

Figure 2: Sequence diagram for the ASP.NET MVC interaction model

Even a quick comparison of Figure 1 and Figure 2 proves that significant differences exist between the interaction model of the two patterns. In particular, in classic MVC the view and model know each other and the two are tied together using an observer relationship. In ASP.NET MVC, the controller acts like a mediator between the two. The controller first commands a task and receives fresh data; next, it explicitly passes up-to-date data to refresh the user interface down to the view. View and model don't know each other. View and controller are related but largely independent and autonomous, which guarantees ease of testing.

What's the Model in ASP.NET MVC?

Originally, the model actor was described as the collection of data being worked on in the view and this definition justified the link between view and model in classic MVC. In ASP.NET MVC, the view receives data directly from the controller in a format that may vary quite a bit. As we'll see in a moment, data may flow into the view through a general-purpose dictionary or through a strongly typed object model. Is this data container the incarnation of the model actor in ASP.NET MVC?

Originally, in MVC the data worked on in the view coincided with the application data model. Today, in a multi-layered solution the two elements are often quite different. The view-model is often significantly different from the application data model. In WPF and Silverlight, in fact, the popular Model-View-ViewModel pattern (MVVM) is founded on this basic fact. The view-model is sometimes made of data transfer objects that decouple the view from the application data model. So whether the model actor is the view-model or the application data model remains an open point and is mostly a matter of personal perspective. Much more concretely tied to ASP.NET MVC programming is how data flows into the view.

The ViewData Dictionary

In ASP.NET MVC the essence of a request is executing an action. The details of the action are contained in the URL in a purely RESTful manner. Any HTTP request ends with the execution of a method defined on a controller class. A controller class inherits from the System.Web.Mvc.Controller class which, in turn, inherits from ControllerBase. In ControllerBase, you'll find a property named ViewData, which is defined as:

public abstract class ControllerBase : MarshalByRefObject, IController

{

:

public ViewDataDictionary ViewData { get; set; }

}

The ViewData property represents a built-in container used for passing data between a controller and a view. The property is of type ViewDataDictionary, namely a plain .NET class that implements the IDictionary interface and looks and behaves like a classic name/value pair, enumerable dictionary.

.

public class ViewDataDictionary : IDictionary,

ICollection>,

IEnumerable>,

IEnumerable

{

:

}

It's not by mere chance that the ViewData property is defined on the ControllerBase class and, as such, is available to any custom controller you may have. The idea is that once the controller has executed a given action, it gets any significant results to be shown to the user and packs it into the ViewData container. The following code snippet, which you get with any ASP.NET MVC project template, shows the process:

public class HomeController : Controller

{

public ActionResult Index()

{

this.ViewData["Message"] = "Welcome to ASP.NET MVC!";

return this.View();

}

public ActionResult About()

{

return this.View();

}

}

Any controller's method performs its own task, stuffs return values into the ViewData dictionary, then triggers the process that generates an updated response for the user. Generating an updated response is a step that involves the view engine and is triggered via one of the overloaded View functions.

The ViewData dictionary is definitely the object that contains the representation of the view-model the data being worked on in the view.

How ViewData Flows Into the View

In ASP.NET MVC, the view actor is symbolized by an HTML page. With the expression "generating the view," one typically refers to the process that takes a layout (i.e., an HTML template) and some data (i.e., the content of ViewData) and produces a response for the browser. Shape and color of the view's layout depends on the currently selected view engine.

The view engine is a pluggable component of the ASP.NET MVC runtime environment that assembles together layout and data to produce a response mostly HTML. The default view engine requires that the layout has the form of an ASPX file. It uses the markup information there as the HTML template to fill with data in the ViewData dictionary. Other view engines, though, may support a different syntax for the layout.

The view engine is triggered by the View function on the Controller class. There are quite a few distinct overloads of the View function. Here's the source code of the most configurable of all:

protected internal virtual ViewResult View(string viewName, string masterName, object model)

{

if (model != null)

{

base.ViewData.Model = model;

}

ViewResult result = new ViewResult();

result.ViewName = viewName;

result.MasterName = masterName;

result.ViewData = base.ViewData;

result.TempData = base.TempData;

return result;

}

As you can see, the content of the ViewData is copied into the ViewResult object and makes its way to the ASP.NET MVC runtime shell where the request is processed. The runtime uses the ViewResult object to retrieve the active view engine and make it work.

Anything Better Than a Dictionary?

A dictionary is a plain collection of name/value pairs with perhaps some additional capabilities such as sorting and filtering. Any data you store in a dictionary is treated as an object and requires casting and boxing to be worked on. A dictionary is definitely not something you would call strongly typed. At the same time, a dictionary is straightforward to use and works well.

A while back, when I introduced the ViewDataDictionary class, a small but important detail passed somewhat unnoticed. With all stock dictionary classes available in the .NET Framework, why did the development team assemble yet another dictionary class?

The ViewDataDictionary is unique because it also features a Model property, as shown below:

public class ViewDataDictionary : IDictionary,

ICollection>,

IEnumerable>,

IEnumerable

{

public object Model { get; set; }

:

}

The Model property is an alternative and object-oriented way of passing data to the view object. Instead of fitting flat data into a dictionary, you can shape a custom object that faithfully represents the data the view expects. In other words, the Model property just represents your chance of creating a view-model object that is unique for each view. If you intend to support the Model property, you have to make it clear by deriving the code-behind class of the view class (in the standard Web Forms based view engine):

public partial class YourPage : ViewPage

{

:

}

If you don't use a code-behind class, you achieve the same goal with the following page directive in the view source file:

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>

Figure 3 shows the dialog box that in Visual Studio 2008 helps you add a view with a strongly typed model attached.

Figure 3: Adding a new view to an ASP.NET MVC project in Visual Studio 2008

Design Considerations

The MVC pattern is quite loose about a number of implementation aspects, including how data should be passed down to the view engine. The web variation of MVC we're considering here doesn't mandate a specific format either. A dictionary like ViewData is therefore an excellent solution because it's flexible enough to accommodate any number of values of any type. Unfortunately, a dictionary is a generic container of System.Object components. The ViewData dictionary is good enough for quick-and-dirty or short-lived sites; it becomes rather inadequate as the complexity of the view (and the number of views) grows beyond a threshold.

When you start having tens of distinct values to pass on to a view, the same flexibility that allows you to quickly add a new entry, or rename an existing one, becomes your worst enemy. You are left alone to track item names and values; you get no help from IntelliSense and compilers.

The only proven way to deal with complexity in software is appropriate design. As far as MVC views are concerned, the definition of a view-model object for each view helps tracking and setting exactly what's really needed by the view. The definition of the view model class is entirely up to you. However, the ASP.NET MVC framework provides facilities and is designed around the idea that you might be using a view-model object.

I suggest you define a class for each view you add, choosing an appropriate naming convention to avoid duplicates and achieve readability. I use a combination of controller and view names. For example, the view-model object for a view invoked by method Index on Home controller is named HomeIndexViewModel. The template for a controller method becomes the following:

public ActionResult Index()

{

// Perform the requested task and get any necessary data

object data =

// Pack data for the view

SamplesIndexViewModel model = new SamplesIndexViewModel();

PopulateModel(model, data);

// Stores the viewmodel object into the transfer dictionary

ViewData.Model = model;

// Trigger the view

return View();

}

You first retrieve any data to pass. Next, you create an instance of the view-model class and copy any raw data into its set of properties tailor-made for the view elements. The final step is passing data to the view. This can be done in either of two ways. Typically, you copy the view-model instance into the Model property of the ViewData. As an alternative, you pass the view-model object as an argument to the View function:

return View("index", model);

In the view markup, you retrieve the view-model object using the this.ViewData.Model expression. However, a convenience property also exists on the ViewPage class that reduces the expression to just this.Model.

The Beauty of MVC

The beauty of MVC is that the controller of the action does its own work and then yields to a distinct object to update the user interface. The beauty of the MVC implementation in ASP.NET MVC is that the view object doesn't have to retrieve fresh data itself, but receives it directly from the controller. This article discussed two ways of packaging data for the view using a dictionary or using a strongly typed custom object.

Dino Esposito is an architect at IDesign and specializes mainly in ASP.NET, AJAX and RIA solutions. Dino co-authored the best-seller Microsoft .NET: Architecting Applications for the Enterprise (Microsoft Press, 2008) and the just-released twin book Microsoft ASP.NET and AJAX: Architecting Web Applications (Microsoft Press, 2009).

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish