As many aspects of ASP.NET have stabilized and
matured over the years, some interesting new features have appeared. Of
the new features, ASP.NET application of the classic Model-View-Controller (MVC) software development pattern has probably received the most attention of all.
The ASP.NET MVC framework represents an alternative to the ASP.NET Web
Forms environment. Web Forms offers a structured, controls-based
framework for generating Web pages. Using Web Forms can make it feel
like you're developing a desktop or rich client application even though
the application UI is built upon HTML transmitted over a disconnected
protocol. The basis of a Web Forms page is a collection of server-side
controls—each one dedicated to emitting some HTML toward the output
stream that eventually ends up at the client. Web Forms offers
developers great leverage through its ability to handle view state and
its event model. The Microsoft Visual Studio Designer has extensive
support for Web Forms. You can develop entire pages and not have to deal
with much, if any, raw HTML.
By contrast, the MVC
framework works "closer to the metal." That is, as a developer, you're
on the hook to work with some raw HTML. However, rather than leaving you
in the wild to concoct a framework to manage the main application
concerns (data and the UI), the MVC framework incorporates an
industry-recognized software pattern for coordinating the two concerns.
The MVC model draws strict distinctions between an application's data,
its rendering, and its request processing. Each of these concerns is
handled by a separate software component, and together they operate in
concert with each other to handle HTTP requests.
1. The Model-View-Controller (MVC) Architecture
Modern software is complex. As
you've seen so far, even developing Web applications using a framework
that hides as much detail as ASP.NET does can become fairly involved.
Many times, the complexity comes down to a problem of managing multiple
concerns. For example, a typical ASP.NET application involves dealing
with a data source (often a database), making sure the HTML rendered by
the application is in sync with the application state, and managing the incoming and outgoing message traffic.
By itself, ASP.NET has separate
components for managing these concerns. ADO, LINQ, and the entity
framework work well for talking to a database. ASP.NET data binding and
the data-bound controls help to keep the client view of the data
current. Together with the ASP.NET pipeline, the ASP.NET control architecture hides the details of managing incoming and outgoing message
traffic. Although these features of ASP.NET make Web development very
approachable, there are other approaches to Web development. MVC offers an alternative means for handling HTTP requests.
The MVC
pattern is tailor-made for Web applications. MVC divides the three main
concerns of a typical Web application (managing data, keeping the
visual aspect of an application in sync with its internal state,
managing message traffic) and handles each through three separate
components: a model, a view, and a controller. The model handles data
access and management and application state, the view handles the visual
representation of the application state, and the controller manages
message traffic.
The MVC
model component is responsible for maintaining application state, as
well as sometimes hosting code not tied directly to the view.
Application state is often managed through a persistent database. In an
MVC-based application, the model encapsulates low-level database access.
For example, the model for a human resources application might include
an Employee
class that represents rows from a table of employee information in a
human resources database. It might also include a collection of Employee classes in an in-memory structure.
MVC view components render
the application's user interface. This might include some controls (for
example, to display and edit data). These controls are usually tied to
the model data. For instance, an application might display separate
views for showing employee data and for editing employee data. The
details view might simply render the details in read-only form, while
the editing view might include controls for editing the employee
information fields.
Finally, MVC
controller components manage interactions with the end user. Although
the view component is responsible for rendering, rendering remains
distinct from user interaction. Within the context of ASP.NET, managing
user interaction means managing Web traffic, updating the model (the
application state), and ultimately managing the UI (that is, emitting the correct HTML).
Figure 1
illustrates the relationships between all three components. Notice that
the controller talks to the model and the view. That is, the controller
updates the model as necessary, and it also interacts with the view
when rendering. The view talks with the model to make sure it's
displaying the most current application state.
2. ASP.NET and MVC
MVC came to ASP.NET fairly
recently. You can think of ASP.NET as a very loosely coupled set of
classes working together to handle requests. ASP.NET includes a pipeline
that acts as a substrate with different kinds of handlers hooked on to
it. The pipeline is configured so that requests for various file types
go to their correct handlers.
As useful as ASP.NET is for
handling Web requests, ASP.NET is not quite a true framework. ASP.NET
Web Forms mingles the concerns of the Web developer. MVC distinguishes
itself as a framework by drawing a clear separation between the concerns
of Web developers. Remember, models handle application state, views
handle rendering, and controllers handle interactions with the end user.
The ASP.NET MVC framework
coexists with the other parts of ASP.NET. The framework operates
independently of the standard .aspx and .ascx files, master pages, and
Global.asax files. MVC also works with the ASP.NET Forms Authentication
and the standard membership and roles providers. MVC has complete access
to the existing data cache and output cache, as well as the existing
data providers. Developers can mix and match any of these other features
of ASP.NET with the MVC framework.
To support MVC's coexistence
with ASP.NET, MVC looks to flexibility as a primary design goal. MVC is
intended to be customizable all around. For example, the code generated
by Visual Studio for an MVC-based
application includes a standard routing table for helping the
application figure out how to handle requests. Although the
out-of-the-box routing mechanism works fairly well most of the time, it
might not be the best for all situations. Changing the routing policy is
relatively straightforward in an MVC application.
By moving all of the MVC routing architecture into the controller, you can easily swap routing policies. This leads to some distinct advantages over typical ASP.NET
development. For example, the MVC URL mapping keeps strange URLs hidden
from the end user. URL mappings are pushed into the framework, so you
can spare your users from seeing messy URL names. Strange URLs, such as /contacts/edit/3256,
can be mapped cleanly and internally. At first glance, this might seem
like a small feature. However, it does help clean up Web UIs when long,
ugly URLs can be stashed away, making room for some very clever routing
scenarios. For example, applications using the MVC framework do not need
to include extensions, which makes it easy for MVC to support naming
schemes for Search Engine Optimization (SEO) and Representational State
Transfer (REST) for services.
The MVC framework still uses
existing ASP.NET file types, such as .aspx files, .ascx files, and
.master files. MVC uses these markup files as view templates.
They support the same inline coding syntax (that is, <%= %>
snippets). However, rather than each interaction posting back to the
server directly, MVC routes interactions to a Controller
class. This makes MVC applications much easier to test in the general
sense, and to use specifically with test-driven design (TDD) techniques
if you prefer. Classic ASP.NET Web Forms by their very nature cannot
directly support automated unit testing.
Finally, all the other features
of ASP.NET remain intact while using MVC: The cache is still there,
output caching is available, session state still works, the provider
architecture is still there, and configuration works the same.
3. ASP.NET MVC vs. Web Forms
The ASP.NET MVC framework is
fundamentally different from ASP.NET Web Forms. MVC makes a very clear
distinction between data sources, program interaction with the data, and
the presentation of data. MVC enforces a separation of concerns,
whereas that sort of separation is something you'd have to build into an
ASP.NET Web Forms application explicitly.
MVC eschews some of the other
features of standard Web Forms. For example, ASP.NET MVC does not
support view state directly (that feature really stems from server-side
controls). As a result, you won't see any hidden fields showing up in
pages rendered by the MVC framework.
One of the most prominent places you'll notice that MVC differs from Web Forms is in the area of handling postback
events. In MVC, events are routed through a routing table rather than
through the singular server-side controls. With Web Forms, however,
routing typically occurs through specific event handlers placed on a
page.
The MVC framework
distinguishes between data, presentation, and program logic, allowing
for more isolation between components. This leads to easier testing
and debugging. In fact, the ASP.NET MVC framework supports test-driven
development very well. This becomes a huge advantage for projects built
and supported by large teams.
Because MVC does not
rely on certain features, such as view state and server-based controls,
more onus is placed on the developer to produce correct HTML. Although
this means more responsibility for the developer, it also gives
developers much more direct control over how the HTML is rendered.
Finally, ASP.NET Web
Forms and server-side controls handle specific events, making it
difficult to follow the execution path of a Web Forms–based application.
MVC differs significantly because all requests pass through a single
point in the application—the routing
table. With use of a routing table, developers can control request
routing at a single point rather than at ad-hoc points on the page (that
is, the event handlers).
4. MVC and Testing
The MVC framework's separation of functionality into specific areas of responsibility makes testing MVC
applications much easier than is testing of Web Forms applications.
Although the Web Forms model clearly improved the Web programming
paradigm for Microsoft developers by separating the concerns of
presentation (user interface) and program logic, the Web Forms model
still mixes several other concerns. Data access is usually mixed right
in with the rest of the program code. For example, if you code your own
authentication scheme, you might perform a user lookup directly when a
postback occurs because the user clicked the login button. The lookup
code is usually right there in the code-beside file. As another example,
requests are routed directly back to the .aspx file that's in play.
Without MVC, there's no way to perform any alternate routing.
The MVC framework separates these other concerns, making for a much more modular architecture that accommodates unit
testing. Testing typical ASP.NET programs usually means clicking
through all the controls and UI elements on a page to make sure they
work. Then, when something doesn't work, you need to track it down and
fix it. The MVC framework supports test-driven development where you
define the requirements of code first, and even write test cases prior
to writing the code. At that point, you can run user interactions in the
MVC framework individually without running the entire application. With
this capability, you can unit test individual parts of the application
using any of the currently available testing frameworks, such as MS Test
and NUnit.