A Quick Introduction to ASP.NET MVC
ASP.NET MVC is a framework for building web applications that applies the general Model View Controller pattern to the ASP.NET framework. Let's break that down by first looking at how ASP.NET MVC and the ASP.NET framework are related.
How ASP.NET MVC Fits in with ASP.NET
When ASP.NET 1.0 was first released in 2002, it was easy to think of ASP.NET and Web Forms as one and the same thing. ASP.NET has always supported two layers of abstraction, though:
The mainstream method of developing with ASP.NET included the whole Web Forms stack—taking advantage of drag-and-drop controls, semi-magical statefulness, and wonderful server controls while dealing with the complications behind the scenes (an often confusing page life cycle, less than optimal HTML, and so on).
However, there was always the possibility of getting below all that—responding directly to HTTP requests, building out web frameworks just the way you wanted them to work, crafting beautiful HTML—using Handlers, Modules, and other handwritten code. You could do it, but it was painful; there just wasn't a built-in pattern that supported any of those things. It wasn't for lack of patterns in the broader computer science world, though. By the time ASP.NET MVC was announced in 2007, the MVC pattern was becoming one of the most popular ways of building web frameworks.
The MVC Pattern
Model-View-Controller (MVC) has been an important architectural pattern in computer science for many years. Originally named Thing-Model-View-Editor in 1979, it was later simplified to Model-View-Controller. It is a powerful and elegant means of separating concerns within an application (for example, separating data access logic from display logic) and applies itself extremely well to web applications. Its explicit separation of concerns does add a small amount of extra complexity to an application's design, but the extraordinary benefits outweigh the extra effort. It has been used in dozens of frameworks since its introduction. You'll find MVC in Java and C++, on Mac and on Windows, and inside literally dozens of frameworks.
The MVC separates the user interface of an application into three main aspects:
MVC as a User Interface Pattern
Notice that we're referred to MVC as a pattern for the User Interface. The MVC pattern presents a solution for handling user interaction, but says nothing about how you will handle other application concerns like data access, service interactions, etc. It's helpful to keep this in mind as you approach MVC: it is a useful pattern, but likely one of many patterns you will use in developing an application.
MVC as Applied to Web Frameworks
The MVC pattern is used frequently in web programming. With ASP.NET MVC, it's translated roughly as:
It's important to keep in mind that MVC is a high-level architectural pattern, and its application varies depending on use. ASP.NET MVC is contextualized both to the problem domain (a stateless web environment) and the host system (ASP.NET).
Occasionally I talk to developers who have used the MVC pattern in very different environments, and they get confused, frustrated, or both (confustrated?) because they assume that ASP.NET MVC works the exact same way it worked in their mainframe account processing system fifteen years ago. It doesn't, and that's a good thing—ASP.NET MVC is focused on providing a great web development framework using the MVC pattern and running on the .NET platform, and that contextualization is part of what makes it great.
ASP.NET MVC relies on many of the same core strategies that the other MVC platforms use, plus it offers the benefits of compiled and managed code and exploits newer .NET language features such as lambdas and dynamic and anonymous types. At its heart, though, ASP.NET applies the fundamental tenets found in most MVC-based web frameworks:
The Road to MVC 3
Two short years have seen three major releases of ASP.NET MVC and several more interim releases. In order to understand ASP.NET MVC 3, it's important to understand how we got here. This section describes the contents and background of each of the three major ASP.NET MVC releases.
ASP.NET MVC 1 Overview
In February 2007, Scott Guthrie (“ScottGu”) of Microsoft sketched out the core of ASP.NET MVC while flying on a plane to a conference on the East Coast of the United States. It was a simple application, containing a few hundred lines of code, but the promise and potential it offered for parts of the Microsoft web developer audience was huge.
As the legend goes, at the Austin ALT.NET conference in October 2007 in Redmond, Washington, ScottGu showed a group of developers “this cool thing I wrote on a plane” and asked if they saw the need and what they thought of it. It was a hit. In fact, many people were involved with the original prototype, codenamed Scalene. Eilon Lipton e-mailed the first prototype to the team in September 2007, and he and ScottGu bounced prototypes, code, and ideas back and forth.
Even before the official release, it was clear that ASP.NET MVC wasn't your standard Microsoft product. The development cycle was highly interactive: there were nine preview releases before the official release, unit tests were made available, and the code shipped under an open source license. All of these highlighted a philosophy that placed a high value in community interaction throughout the development process. The end result was that the official MVC 1.0 release—including code and unit tests—had already been used and reviewed by the developers who would be using it. ASP.NET MVC 1.0 was released on 13 March 2009.
ASP.NET MVC 2 Overview
ASP.NET MVC 2 was released just one year later, in March 2010. Some of the main features in MVC 2 included:
There were also lots of API enhancements and “pro” features, based on feedback from developers building a variety of applications on ASP.NET MVC 1, such as:
One important precedent set by the MVC 2 release was that there were very few breaking changes. I think this is a testament to the architectural design of ASP.NET MVC, which allows for a lot of extensibility without requiring core changes.
ASP.NET MVC 3 Overview
ASP.NET MVC 3 (generally abbreviated as MVC 3 from now on) shipped just 10 months after MVC 2, driven by the release date for Web Matrix. If MVC 3 came in a box, it might say something like this on the front:
For those who have used previous versions of MVC, we'll start with a quick look at some of these major features.
If you're new to ASP.NET MVC, don't be concerned if some of these features don't make a lot of sense right now; we'll be covering them in a lot more detail throughout the book.
Razor View Engine
Razor is the first major update to rendering HTML since ASP.NET 1.0 shipped almost a decade ago. The default view engine used in MVC 1 and 2 was commonly called the Web Forms View Engine, because it uses the same ASPX/ASCX/MASTER files and syntax used in Web Forms. It works, but it was designed to support editing controls in a graphical editor, and that legacy shows. An example of this syntax in a Web Forms page is shown here:
<%@ Page Language="C#" MasterPageFile="∼/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<MvcMusicStore.ViewModels.StoreBrowseViewModel>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Browse Albums </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <div class="genre"> <h3><em><%: Model.Genre.Name %></em> Albums</h3> <ul id="album-list"> <% foreach (var album in Model.Albums) { %> <li> <a href="<%: Url.Action("Details", new { id = album.AlbumId }) %>"> <img alt="<%: album.Title %>" src="<%: album.AlbumArtUrl %>" /> <span><%: album.Title %></span> </a> </li> <% } %> </ul> </div> </asp:Content>
Razor was designed specifically as a view engine syntax. It has one main focus: code-focused templating for HTML generation. Here's how that same markup would be generated using Razor:
@model MvcMusicStore.Models.Genre @{ViewBag.Title = "Browse Albums";} <div class="genre"> <h3><em>@Model.Name</em> Albums</h3> <ul id="album-list"> @foreach (var album in Model.Albums) { <li> <a href="@Url.Action("Details", new { id = album.AlbumId })"> <img alt="@album.Title" src="@album.AlbumArtUrl" /> <span>@album.Title</span> </a> </li> } </ul> </div>
The Razor syntax is easier to type, and easier to read. Razor doesn't have the XML-like heavy syntax of the Web Forms view engine.
We've talked about how working with the Razor syntax feels different. To put this in more quantifiable terms, let's look at the team's design goals in creating the Razor syntax:
@foreach (var album in Model.Albums) { <li> <a href="@Url.Action("Details", new { id = album.AlbumId })"> <img alt="@album.Title" src="@album.AlbumArtUrl" /> <span>@album.Title</span> </a> </li> }
You only needed to signify the end of a code block for the loop—in the cases where model properties were being emitted, only the @ character was needed to signify the transition from markup to code, and the Razor engine automatically detected the transition back to markup.
Razor also simplifies markup with an improvement on the Master Pages concept—called Layouts—that is both more flexible and requires less code.
I kept […] going cross-eyed when I was trying to figure out what the syntax rules were for Razor until someone said stop thinking about it, just type an “at” sign and start writing code and I realize that there really is no Razor.
—HANSELMINUTES #249: ON WEBMATRIX WITH ROB CONERY http://hanselminutes.com/default.aspx?showid=268
This is just a quick highlight of some of the reasons that Razor makes writing View code really easy and, dare I say, fun. We'll talk about Razor in a lot more depth in Chapter 3.
Validation Improvements
Validation is an important part of building web applications, but it's never fun. I've always wanted to spend as little time as possible writing validation code, as long as I was confident that it worked correctly.
MVC 2's attribute-driven validation system removed a lot of the pain from this process by replacing repetitive imperative code with declarative code. However, support was focused on a short list of top validation scenarios. There were plenty of cases where you'd get outside of the “happy path” and have to write a fair amount more code. MVC 3 extends the validation support to cover most scenarios you're likely to encounter. For more information on validation in ASP.NET MVC, see chapter 6.
.NET 4 Data Annotation Support
MVC 2 was compiled against .NET 3.5 and thus didn't support any of the .NET 4 Data Annotations enhancements. MVC 3 picks up some new, very useful validation features available due to .NET 4 support. Some examples include:
Streamlined Validation with Improved Model Validation
MVC 3's support for the .NET 4 IValidatableObject interface deserves individual recognition. You can extend your model validation in just about any conceivable way by implementing this interface on your model class and implementing the Validate method, as shown in the following code:
public class VerifiedMessage : IValidatableObject { public string Message { get; set; } public string AgentKey { get; set; } public string Hash { get; set; } public IEnumerable<ValidationResult> Validate( ValidationContext validationContext) { if (SecurityService.ComputeHash(Message, AgentKey) != Hash) yield return new ValidationResult("Agent compromised"); } }
Rich JavaScript Support
JavaScript is an important part of any modern web application. ASP.NET MVC 3 adds some significant support for client-side development, following current standards for top quality JavaScript integration. For more information on the new JavaScript related features in ASP.NET MVC 3, see Chapter 8.
Unobtrusive JavaScript
Unobtrusive JavaScript is a general term that conveys a general philosophy, similar to the term REST (for Representational State Transfer). The high-level description is that unobtrusive JavaScript doesn't affect your page markup. For example, rather than hooking in via event attributes like onclick and onsubmit, the unobtrusive JavaScript attaches to elements by their ID or class.
Unobtrusive JavaScript makes a lot of sense when you consider that your HTML document is just that—a document. It's got semantic meaning, and all of it—the tag structure, element attributes, and so on—should have a precise meaning. Strewing JavaScript gunk across the page to facilitate interaction (I'm looking at you, doPostBack!) harms the content of the document.
MVC 3 supports unobtrusive JavaScript in two ways:
jQuery Validation
MVC 2 shipped with jQuery, but used Microsoft Ajax for validation. MVC 3 completed the transition to using jQuery for Ajax support by converting the validation support to run on the popular jQuery Validation plugin. The combination of Unobtrusive JavaScript support (discussed previously) and jQuery validation using the standard plugin system means that the validation is both extremely flexible and can benefit from the huge jQuery community.
Client-side validation is now turned on by default for new MVC 3 projects, and can be enabled site-wide with a web.config setting or by code in global.asax for upgraded projects.
JSON Binding
MVC 3 includes JSON (JavaScript Object Notation) binding support via the new JsonValueProviderFactory, enabling your action methods to accept and model-bind data in JSON format. This is especially useful in advanced Ajax scenarios like client templates and data binding that need to post data back to the server.
Advanced Features
So far, we've looked at how MVC 3 makes a lot of simple-but-mind-numbing tasks like view templates and validation simpler. MVC 3 has also made some big improvements in simplifying more sophisticated application-level tasks with support for dependency resolution and global action filters.
Dependency Resolution
ASP.NET MVC 3 introduces a new concept called a dependency resolver, which greatly simplifies the use of dependency injection in your applications. This makes it easier to decouple application components, which makes them more configurable and easier to test.
Support has been added for the following scenarios:
This is a big enough topic that we've devoted an entire new chapter (Chapter 11) to it.
Global Action Filters
MVC 2 action filters gave you hooks to execute code before or after an action method ran. They were implemented as custom attributes that could be applied to controller actions or to an entire controller. MVC 2 included some filters in the box, like the Authorize attribute.
MVC 3 extends this with global action filters, which apply to all action methods in your application. This is especially useful for application infrastructure concerns like error handling and logging.
MVC 3 Feature Summary: Easier at All Levels
They're great features, but if I was designing the box, I'd just put this on it:
This is a quick introductory summary, and we'll be covering these and other MVC 3 features throughout the book. If you'd like an online summary of what's new in MVC 3 (perhaps to convince your boss that you should move all your projects to MVC 3 as soon as possible), see the list at http://asp.net/mvc/mvc3#overview.