Chapter 3. ASP.NET > ASP.NET MVC

This is a very difficult chapter to write. It's not difficult technically, nor is there a lack of things to say; it's the subject matter that needs to be addressed: Is ASP.NET MVC better than Web Forms?

This is a volatile subject, to be sure, and the authors understand very well that this subject is not a comfortable one for most developers who have been working with ASP.NET Web Forms for a long time. Unfortunately, it lies at the very heart of this book — and is most likely a question you're trying to answer right now.

As with all approaches to application architecture, much of the answer is subjective. The authors happen to think that ASP.NET MVC is absolutely wonderful, but please don't take our word for it just because we said so. Most importantly, Microsoft is not suggesting that ASP.NET MVC is better than, nor will it replace, ASP.NET Web Forms. In fact, both ASP.NET Web Forms and ASP.NET MVC are fundamental parts of ASP.NET, and both will continue to be promoted, available, supported, and loved for the foreseeable future!

You will need to make up your own mind on this matter, and that's what this chapter is all about — giving you the information you need to decide if ASP.NET MVC is, indeed, a better web framework for you. Before you get started, however, please find a comfortable place to sit, and do your best to clear your mind of preconceptions. The authors will try to offer some informed opinions — without beating you over the head with dictates — so you can decide for yourself if ASP.NET MVC is for you.

ABSTRACTION: WHAT WEB FORMS DOES WELL

Some people will consider ASP.NET MVC a step backward. ASP.NET Web Forms did a great deal of work to hide the realities of the Web. HTTP is a fundamentally stateless protocol, and HTML can be a difficult markup language to learn. In some ways, ASP.NET Web Forms tries to hide both of these realities behind Visual Studio and behind the ASP.NET Web Forms subsystem.

Take a moment and remember the state of development on the Microsoft platform before ASP.NET was released in January 2002. Desktop developers programmed in Visual Basic, and web developers used what is now called "Classic" ASP (Active Server Pages). ASP was a simple scripting language, whereas Visual Basic was a more complete development environment with an IDE that touted a sophisticated drag-and-drop design process for creating forms. Visual Basic introduced a control and component model that made development easier than ever.

Developers became used to the idea that they could write a button onto a form in the Visual Basic designer, double-click that button, and have a Button_Click event wired up automatically. When ASP.NET was introduced, it offered this kind of functionality for web development. This was huge, and its significance shouldn't be underestimated. While ASP.NET has been maligned by some for hiding too much, it made web development accessible to a large number of developers who were having trouble wrapping their heads around the details of the HTML/HTTP development model. ASP.NET brought this familiar control and event model to web development.

Fast forward eight plus years later, and the introduction of an alternative has got some Web Forms developers nervous. ASP.NET MVC feels like a step backward because it takes away some powerful functionality that Web Forms developers have come to count on. It's important for you as an ASP.NET developer — MVC or Web Forms (or a hybrid, as you'll see in Chapter 12) — to understand the pros and cons of the two technologies so that you can make the right decisions for your projects.

The authors are postponing the obligatory "Hello MVC World" example entirely, as we, along with ScottGu, turned that idea on its head with a complete working application in the first chapter. Instead, we're spending this chapter talking about the problems that ASP.NET Web Forms solves, as well as how the Web Forms and ASP.NET MVC mindsets differ. The goal is not just for you to appreciate what's useful about Web Forms, but also to better understand what you're losing and how your development style will change as a result.

Presumably, you have some familiarity with ASP.NET Web Forms, and you're interested in learning more about ASP.NET MVC. It's a cliché, but depending on your goals, less sometimes really is more. In the following sections, let's take a look at some of the things that Web Forms does well, wrap our minds around ASP.NET MVC's very different model, and remind ourselves exactly what's been happening under the covers of Web Forms for the last eight years by creating an incredibly (even deceptively) simple ASP.NET Web Forms application.

A Basic Web Forms Application

Head over to Visual Studio, go to File

A Basic Web Forms Application
FIGURE 3-1

Figure 3.1. FIGURE 3-1

Next, simply double-click on the TextBox. Notice that you are taken to the Web Form's code-behind, and your cursor is positioned in the middle of a TextChanged event. This is a simple action you've taken, but it has profound implications. Sit back and drink in the simplicity of what you did, and think about what is being hidden.

Remember that HTTP is a completely stateless protocol. The browser does a GET request for a page, the user types in a TextBox and submits an HTML Form, sending a POST to the server. As far as the server is concerned, the GET and the POST are not related at all. They are distinct and discrete. It's up to the programmer and the programming model to correlate the two events and choose how they are related.

ASP.NET Web Forms explicitly decided as a programming model that it would:

  • Represent a Page as a control tree, where each control was accessible via the programmer on the server side.

  • Give these server-side controls events like their desktop counterparts and, thus, hide as much HTTP and HTML as is reasonable.

  • Make state management as transparent as possible by offering options like the Session, Cache, and most significantly, ViewState.

Let's make two changes. First, add some initial text to the TextBox in the Designer. Next, add a single line of code to the TextChanged event in the code-behind that updates the Label if the text in the TextBox has changed. Your code will look something like Listing 3-1. Code-behind is shown in Listing 3-2.

Example 3.1. 3-1.aspx

ASPX

<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="TextBox1" runat="server"
OnTextChanged="TextBox1_TextChanged">
Initial Text</asp:TextBox>
        <asp:Button ID="Button1" runat="server" Text="Button" />
        <p>
            <asp:Label ID="Label1" runat="server" Text=""></asp:Label>
        </p>
    </div>
    </form>
</body>
</html>

Example 3.2. 3-2.aspx.cs

CODE-BEHIND
public partial class _Default : System.Web.UI.Page
{
   protected void TextBox1_TextChanged(object sender, EventArgs e)
   {
      Label1.Text = "This text is different from before!";
   }
}

If you look at the Properties pane in Visual Studio while the TextBox is selected, you'll see the events available to the TextBox and the event you've hooked up (see Figure 3-2).

FIGURE 3-2

Figure 3.2. FIGURE 3-2

You might ask yourself, "Why does any of this matter to someone reading a Professional book on ASP.NET MVC?" You should care about what Web Forms does for two reasons:

  • One, because if it was handled automatically by Web Forms, it likely isn't handled automatically by ASP.NET MVC

  • Two, so you'll know what you're missing. As Chapter 12 discusses, you will likely need Web Forms again in your work, and you'll appreciate some of these abstractions when building hybrid applications.

Let's take a look at the work that has to happen under the covers to make that TextChanged event fire, and talk about why this is so extraordinary.

When the page described in Listing 3-1 was rendered, the resulting HTML was a little more complex and included some fields and markup that we didn't explicitly create when we laid out the page.

<HEAD><TITLE>Untitled Page</TITLE></HEAD>
<BODY>
<FORM id=form1 name=form1 action=default.aspx method=post>
<DIV>
<INPUT id=__VIEWSTATE type=hidden value=/wEPDwUJNzg3NjcwMjQzZGQ=
  name=__VIEWSTATE>
</DIV>
<DIV>
<INPUT id=TextBox1 value="Initial Text" name=TextBox1> <INPUT id=Button1
  type=submit value=Button name=Button1>
<P><SPAN id=Label1></SPAN></P>
</DIV>
<DIV><INPUT id=__EVENTVALIDATION type=hidden value=/wEWAwKMgPC6BQLs0bLrBgKM54rGBg==
 name=__EVENTVALIDATION> </DIV></FORM></BODY>
Code snippet 3-3.htm

There are three things in this HTML that are specific to ASP.NET Web Forms:

  • Notice that the <form> is going to post back to default.aspx, rather than to another page. While ASP.NET Web Forms does support the concept of cross-page postbacks, the vast majority of ASP.NET pages post back to themselves, delivering changes by the user to the page, and enabling the concept of eventing.

  • You have a chunk of ViewState on the page, and you can see it rendered in a hidden input control. At this point, there's no server-side state being maintained by ASP.NET; ViewState maintains the state of the rendered view.

  • There's another hidden input control called EventValidation. This was a feature added in ASP.NET 2.0 to check incoming Form POST values for validity. It's a hash of possible values and aims to prevent injection attacks.

There's a lot of infrastructure going on here for just a simple page. However, remember where ASP.NET Web Forms is coming from. It's attempting to abstract away HTTP and much of HTML and provides a control model for working with pages; thus, it's providing sophisticated mechanisms to make the developer's life easier.

The most significant concept in Web Forms is the idea that your Page will have a life cycle and raise events!

The Importance of Events

You expect the TextChanged event to be raised, but how can ASP.NET tell you if some text has changed without knowing the initial state of the textbox? In this case, the TextBox control saves its state, and that state doesn't sit on the server side but on the client side. This is huge. Why on the client? Because the web server has no way of knowing when the page it just delivered to a browser will, if ever, be posted back. You could certainly try to hold the state on the server, but how long should you hold it? If the state were large, how could you scale? That's where ViewState comes in. The state of the initial view is serialized and stuck in the Page that you just delivered. It's returned to the server when the Page is posted back, and that state is used to decide to raise events.

In fact, all the controls on a Page can save their state to a shared state bag, and the result is the custom-encoded, then Base-64-encoded, often encrypted, chunk of data that you call ViewState. At this point, there's enough information in the ViewState to let ASP.NET know if you change the value of the TextBox. You can partially decode ViewState by using tools like Fritz Onion's ViewStateDecoder, as shown in Figure 3-3. You can download ViewStateDecoder from http://alt.pluralsight.com/tools.aspx.

FIGURE 3-3

Figure 3.3. FIGURE 3-3

The fact that Web Forms is storing the state of the view enables the possibility of a "changed" event.

Note

If you want to learn more about the innards of ViewState, including ways to optimize it, check out Professional ASP.NET 4 In C# and VB by Bill Evjen, Scott Hanselman, and Devin Rader (Wrox, 2010; ISBN: 978-0-470-50220-4).

If you run the application, your initial page load will look like Figure 3-4.

Enter some text in the textbox and click the button; the results will look something like Figure 3-5.

This is an exceedingly simple application, but it quickly illustrates how ASP.NET Web Forms has layered an eventing and control system on top of a protocol and markup language that simply does not support events in the way that desktop developers are used to. This is powerful stuff, but is it always useful?

FIGURE 3-4

Figure 3.4. FIGURE 3-4

FIGURE 3-5

Figure 3.5. FIGURE 3-5

THE LEAK: WHERE WEB FORMS DOESN'T EXACTLY FIT

There are several really attractive aspects of the sample you just looked at:

  • The IDE has a powerful visual designer that abstracted away the HTML completely.

  • You were able to double-click a button or double-click a textbox and have events easily and automatically hooked up, even though server-side events are not a Web, HTTP, or HTML concept.

  • The values of the textbox were persisted for you over a medium (HTTP) that is stateless.

In short, the development experience is more like Windows Form development rather than web development, and that's precisely what the creators of ASP.NET hoped for. But why did they do this?

When ASP.NET was being created (known as ASP+ at the time), Microsoft wanted to create a web development experience that felt comfortable to the arsenal of Rapid Application Development (RAD) developers out there. These developers were used to a certain development experience, driven by the concept of the Component Object Model (COM), wherein complex logic (visual and logical) is encapsulated in components.

The Visual Basic IDE consisted largely of dragging and dropping controls on a form, double-clicking, and "wiring events." By offering the same development experience across platforms, Microsoft would automatically enable its largest developer base as web developers. This approach by Microsoft was very strategic, as they understood that the Web would play a significant role in the future of software, and as a company, their tools needed to be at the center of it.

ASP.NET Web Forms owes a lot to VB6 and other RAD tools like Delphi. However, as is common with all major abstractions, sometimes Web Forms leaks, and things don't go as you expected. Sometimes Web Forms doesn't fit.

Web Forms almost completely hides HTTP from the developer. Unless you're debugging a fairly low-level issue, you can happily develop a complex database-centric application with Web Forms and never see an HTTP header. Unless you're seeing performance problems with ViewState, you can happily take advantage of multiple complex events on the server side as the user interacts with the Page on the client side. Unless you're interested in controlling all your HTML tags, you can drag-and-drop third-party controls on a rich design surface in Visual Studio and interact with them using SmartTags and wizards.

ViewState

ViewState is powerful, but it has its drawbacks. Because ViewState is enabled for all controls by default, sometimes your Web Forms will generate more ViewState than is required. This becomes a real problem with complicated pages and with certain controls like the DataGrid that are amazingly powerful but lean heavily on ViewState for that power.

If you don't need a TextBox to throw a TextChanged event, you could certainly turn off the ViewState for just that control. Unfortunately, it is rare that developers optimize their pages for ViewState size; instead, they choose to complain about bloat using the default settings.

Controlling Your Angle Brackets

While ASP.NET Web Forms offers a sophisticated Control Adapter model, so developers can change the way controls render themselves, it's been said that the abstraction is complex for some developers: "Why can't these controls get out of my way?" This has led to the development of controls that offer a more template-based approach, like the new ASP.NET 3.5 ListView control. However, although ASP.NET has made some strides, it can't be said that you have absolute control over your HTML using Web Forms.

Different controls render their HTML different ways, and when you introduce third-party controls into the process, you might be disillusioned to find that the HTML markup generated by Company A's widget is different enough from Company B's that the results just don't work well together.

Client IDs

Controls in ASP.NET need to have unique IDs so that they won't conflict with other controls on the Page. To accomplish this, certain controls function as naming containers by implementing the INamingContainer interface. This interface exists so that the controls can provide these unique naming scopes for their child controls. This sounds like a good idea until your Page becomes so complicated that you start getting generated control names like ctl00$ContentPlaceHolder1$UserControl1$TextBox1.

Not only are these kinds of control names difficult to read, but, when used in loops, they bloat the size of the page and make it exceedingly difficult to use JavaScript client-side libraries like jQuery to get a hold of your controls.

Testing

Web Forms was developed before .NET and .NET developers began to embrace unit testing, Test Driven Development, and Mocking Frameworks. Web Forms implementations of HttpRequest,HttpResponse,HttpContext, and other HTTP-related classes are very concrete, making it difficult to "lie" to Web Forms. It's nearly impossible to run a Web Form through its life cycle outside of IIS without using a sophisticated profiler/mocking tool like TypeMock. Testing a Web Forms application can be challenging. ASP.NET Web Forms is written with the expectation that it will always be run inside the context of IIS. ASP.NET MVC, however, believes differently.

BACK TO BASICS: ASP.NET MVC BELIEVES...

We'll spend this whole book discussing the point of MVC, but here are its guiding tenets:

  1. Be extensible, maintainable, and flexible.

  2. Be testable.

  3. Get out of the user's way when necessary.

It's the essence of number three that is discussed in this section, as it is often misunderstood and engenders a lot of the FUD ("fear, uncertainty, and doubt") around ASP.NET MVC.

Stated simply, ASP.NET MVC doesn't do anything to try to hide either HTTP or HTML from you. This is an important point, considering that Web Forms has worked so hard to hide these. It is this point that causes a lot of people to think that ASP.NET MVC is harder to use than Web Forms. In reality, it simply hides less of the reality of web development. We, the authors, believe that this can be a significant strength, and we hope that this book will convince you as well.

Orchestration versus Composing

Sometimes programmers use musical metaphors to describe what it feels like to create with code. We'll use a few now, and, hopefully, they'll work for you as they do for us.

In the Web Forms example above, you dragged some controls onto the design surface, double-clicked, and wrote a single line of code. The control abstraction in the example is so complete that the task became much less about coding and much more about orchestration. Stated differently, you're orchestrating the interactions and relationships between high-level things, rather than composing at a lower level from scratch. Web Forms is often about "orchestrating" an application using drag-and-drop components, and some light eventing code.

ASP.NET MVC is focused more on composing applications with smaller abstractions. You'll focus not just on the user-facing end result of the application, but also on the application's testability, its flexibility and extensibility. The app should be aesthetically pleasing not just for a user to use, but also for a developer to read.

The authors certainly dig ASP.NET MVC and think it's a better framework for our style of development, but there's no qualitative judgment here. ASP.NET MVC is different from Web Forms in the way a motorcycle is different from a car. Each offers its own strengths. Motorcycles go fast but aren't so good for carrying groceries. Cars are roomy and carry families nicely but get lousy gas mileage. There are always trade-offs. Pick the vehicle, ahem, Web Framework, that makes you happy.

Scott Hanselman ("ScottHa") has called ASP.NET MVC Web Forms Unplugged. If this kind of development framework sounds like your cup of tea, then read on!

Separation of Concerns: What It Means

Separation of concerns is the most important guiding tenet to remember when developing with the MVC pattern. As programs get more and more complex, it's increasingly important to modularize your code, making sure that the interests of each module are separate. Each module should focus on what it is good at — its concern — while maintaining as little knowledge of the other parts as possible.

MVC is, as a pattern, one that naturally separates concerns. The Model knows nothing about the View. The View doesn't know there's a Controller. The Controller knows a little more, as it knows about the existence of a View and how to use a Model, but ideally that's as deep as it goes. The MVC pattern guides you towards building independent modules that have small and well-defined focus.

Web Forms has been criticized for effectively merging the controller and the view via its Page Controller model and code-behind files. Event handlers in Web Forms have not only the power of a controller but also intimate knowledge of the view down to the smallest control.

ASP.NET MVC embraces the principle of separation of concerns as much as possible. We hope to encourage you to do the same in your applications, as you compose them from smaller and more focused pieces.

Approaches to Maintainability

If you read any development blogs or happen to go to conferences, you've heard the term maintainability thrown down as an absolute must for any application. There could probably be no blander term for a concept as important as this. A maintainable application is one that is easy to change and fix as needed. This may seem as bland as the word itself, but think back to an application you wrote four, five, or even ten years ago. What if you had to change out a core component of that application? What if a bug came up that was really obscure — how would you find it and change it? Would it be a simple matter?

A proponent of TDD (Test Driven Development is discussed in Chapter 10) would argue that if you have enough tests, finding and fixing a bug is a very simple matter and almost guarantees (if you have enough tests) that you don't introduce new bugs into the system with your fix.

Maintainability goes beyond unit testing, however. The design patterns (which are discussed further in Chapter 12) you use to structure your application will ultimately lend themselves to long-term maintenance and help you avoid a wholesale application update — also known as The Great Rewrite.

CARING ABOUT TESTABILITY

Testing your code for accuracy and errors is at the core of good software development. Recently, whenever the concept of unit testing has been brought up (with respect to ASP.NET), it's usually in the context of Test Driven Development (TDD; discussed in Chapter 10), but they are two very different things.

Unit testing as a concept should be part of your everyday development life — no matter if you're a practitioner of TDD or not. As you probably already know, the goal of unit testing is to test the outcome of a granular routine in your application, with the belief that if every "unit" of the application is tested, the application as a whole will be as "correct" and error-free as possible.

Unit testing will only work, however, if each test that you write is able to work with a very specific bit of functionality without dependencies on other processes. For instance, you may have an ecommerce application and want to test the shopping cart methods (add item, remove item, etc.), and your application may be storing the cart information in a database after each change is made. This presents a problem when testing the shopping cart because you don't want to have to involve data access code, which could fail because of connection or query issues. This scenario could present a false failure (which isn't good) — meaning that your logic in your cart may be sound, but the test could still fail because of other reasons that are not part of that logic. In order to have a good unit test, that test must fail only if the logic you're testing fails — if it fails for other reasons, then you don't have a good test.

There are many ways to deal with external dependencies in your code, which are discussed in detail in Chapter 11, including mocking (faking the presence of an external system) and the use of stubs (creating a dummy external system). To get around the data access issue with respect to the previous shopping cart example, you could create a stub of a data repository and interact with it instead of SQL Server, which will free you from data access errors in your testing (again, we'll have more about patterns like this one in Chapter 11).

Another scenario where testability comes in is working with the HttpContext (accessing Request.Form, Reponse.Cookies, User.Identity, etc.) while creating your application Controllers. HttpContext has long been the bane of testers because you can't access it from your test application (HttpContext is only available in a Web setting — test projects are simple executables) and therefore would cause false failures. This is where mocking really shines, in that it allows you to craft a fictional environment in which to test your application's logic. An example of this is testing the login routing of your application. You can mock a form post and add some fake values to Request.Form in order to simulate a user submitting a username and password to your Controller.

Leveraging the concepts of mocking and stubbing requires some effort on your part, however, to structure your application design as loosely as possible. There are many approaches to this, but the most common centers around working with interfaces as much as possible, avoiding singletons and static methods, and offering constructor overloads to your business logic classes (we discuss this and more in Chapter 12).

By focusing on testability, you also make it easier to write more tests, and, in general (if you're a good test writer), more tests are almost always a good thing.

COMMON REACTIONS TO ASP.NET MVC

Not everyone who sees ASP.NET MVC immediately loves it. In fact, some folks have pretty immediate visceral negative reactions. Here's a few you might also have had and what we think about them.

This Looks Like Classic ASP from 1999!

After seeing ASP.NET MVC for the first time, a conference attendee said to ScottHa:

1999 called and they want their Classic ASP Spaghetti Code back!

It was funny, but not really fair and balanced. This was a reaction to seeing the markup in an ASP.NET MVC View using the WebFormsViewEngine. ASP.NET MVC uses the <% %> syntax by default within Views. You'll learn more about Views in Chapter 6, but for now it's important to compare apples with apples. When we were all coding Classic ASP, the Model, View, and Controller were all in a single ASP file!

Of course, as with all languages and frameworks, you can write garbage in any language using any library. However, ASP.NET MVC also supports pluggable third-party and alternative ViewEngines (as you'll see in Chapter 6) that will give you complete flexibility. If you think some markup looks like spaghetti, you're completely empowered to swap it out with something that works for your sense of aesthetics.

Who Moved My <asp:Cheese runat="server"}>?

The lack of server-side controls is often disconcerting to folks new to ASP.NET MVC. This is a bit more subtle issue, though, that will become clear as you move through the book.

By default, ASP.NET MVC has a default ViewEngine named WebFormViewEngine, which uses the ViewPage class to render views. ViewPage derives from the same Page class well known to and loved by Web Forms developers. Because of this, you might be tempted to use some Web Forms controls in the view page via the Visual Studio designer. Resist this temptation. Some controls that do not rely on ViewState, PostBacks, Events, and the like might work just fine (such as the Literal control), but in general, ASP.NET MVC was not designed to support the Control model.

ASP.NET MVC includes several ways to encapsulate rendered portions of HTML via either partial views or partial rendering with AJAX. You'll learn about those in Chapters 6 and 7, respectively.

Yet Another Web Framework

Well, we actually have no defense for this one. Yep, ASP.NET MVC is "Yet Another Web Framework." It's inspired by Yet Other Web Frameworks like Rails, Django, and MonoRail, but it has its own .NET 3.5 and LINQ-embracing style. There will always be another web framework. The idea is to find one that makes you productive and makes you feel good at the same time.

ASP.NET MVC is built on ASP.NET itself. Perhaps this is an obvious statement, but it's worth reiterating. In fact, ASP.NET MVC is built on constructs and subsystems you're probably familiar with, like HttpModules and HttpHandlers. It's built with the same public APIs that you've used to create ASP.NET applications. That's also useful to note because people often assume that frameworks from Microsoft like ASP.NET MVC use internal or private methods or assemblies. ScottHa takes great comfort, actually, in the fact that Phil and his team have created something that plays by the rules.

In fact, the ASP.NET MVC team has pushed for some previously closed APIs to be made public so that they can add features to the next-version ASP.NET MVC. When these APIs are opened, all developers will be able to use them — not just the ASP.NET team.

Let's take apart the default application and see how it works.

WHY "(ASP.NET > ASP.NET MVC) == TRUE"

Creating your first MVC application is fairly straightforward. You can use any version of Visual Studio 2008 or Visual Studio 2010 to create the basic application, including Standard, Professional, Team Edition, or Visual Web Developer Express.

The first order of business is to install the MVC Framework on your development box. Start at www.asp.net/mvc by downloading the latest release. If you like living on the edge, you can often get ASP.NET MVC future releases at www.codeplex.com/aspnet.

What you're downloading is a set of Visual Studio project templates that will create your ASP.NET MVC web application for you. You've used these before — every new ASP.NET website and ASP.NET web application is based on a set of templates. The templates will be installed in Visual Studio, and the reference assemblies will be installed in C:Program FilesMicrosoft ASP.NET.

After you've installed ASP.NET MVC, you're ready to create an ASP.NET MVC application:

  1. Start by opening Visual Studio 2008 by selecting File

    WHY "(ASP.NET > ASP.NET MVC) == TRUE"
  2. From the "New Project" dialog box (see Figure 3-6), select ASP.NET MVC 2 Web Application.

    FIGURE 3-6

    Figure 3.6. FIGURE 3-6

  3. Pick your project name and where it's going to live on disk, and click OK. The Create Unit Test Project dialog will appear (see Figure 3-7).

    FIGURE 3-7

    Figure 3.7. FIGURE 3-7

  4. By default the Test framework dropdown list includes Visual Studio Unit Test as an option. Selecting Yes (see Figure 3-7) will create a Solution that includes not only a basic ASP.NET MVC project but also an additional MSTest Unit Test project.

    Note

    MSTest is not available in Visual Web Developer 2008 Express.

    If you've installed a third-party unit-testing framework like MbUnit or NUnit, you'll have additional options in this dialog.

  5. Click OK, and you will have a solution with projects that look like Figure 3-8. Note that, while this is an ASP.NET application, along with a standard class library, there are some additional folders you haven't seen before.

    FIGURE 3-8

    Figure 3.8. FIGURE 3-8

In fact, there are quite a few more directories in the application that you might be used to; this is by design. ASP.NET MVC, like other MVC frameworks, relies heavily on the idea that you can reduce effort and code by relying on some basic structural rules in your application. Ruby on Rails expresses this powerful idea very succinctly: convention over configuration.

Convention over Configuration

The convention over configuration concept was made popular by Ruby on Rails a few years back, and essentially means:

We know, by now, how to build a web application. Let's roll that experience into the framework so we don't have to configure absolutely everything, again.

You can see this concept at work in ASP.NET MVC by taking a look at the three core directories that make the application work:

  • Controllers

  • Models

  • Views

You don't have to set these folder names in the web.config file — they are just expected to be there by convention. This saves you the work of having to edit an XML file like your web.config, for example, in order to explicitly tell the MVC Engine, "You can find my controllers in the Controllers directory" — it already knows. It's convention.

This isn't meant to be magical. Well, actually, it is; it's just not meant to be black magic, as Phil calls it — the kind of magic where you may not get the outcome you expected (and moreover can actually harm you).

ASP.NET MVC's conventions are pretty straightforward. This is what is expected of your application's structure:

  • There is a single Controllers directory that holds your Controller classes.

  • Each Controller's class name ends with ControllerProductController, HomeController, and so on, and lives in the "Controllers" directory.

  • There is a single Views directory for all the Views of your application.

  • Views that Controllers use live in a subdirectory of the Views main directory and are named according to the controller name (minus Controller). For example, the views for the ProductController discussed earlier would live in /Views/Product.

  • All reusable UI elements live in a similar structure above, but in a Shared directory off of, the root. You'll hear more about Views in Chapter 6.

If you take a deeper, expanded look at the initial structure of the sample application, you can see these conventions at work (see Figure 3-9).

FIGURE 3-9

Figure 3.9. FIGURE 3-9

There are two controllers, HomeController and AccountController in the Controllers directory, and several Views in the Views directory. The following discussion focuses on the Views under /Views/Home named About and Index.

While there is no convention that is expected of you with respect to what you name your Views, you can lean on the ASP.NET MVC convention that you give your View the same name as your Action. This also makes it easier for other developers to review and understand your application.

You can see this convention in action in the way that the template creates the Index and About views. These are also the names of the Controller actions that are called, and the code to render these views is simply:

return View();
Code snippet 3-4.cs

That can be a little confusing. Let's see a clear example by changing the application a little, then digging in:

  1. Open up HomeController.cs and copy/paste the About method and create a duplication, called Foo as shown here:

    public ActionResult Foo()
    {
        ViewData["Title"] = "Foo Page";
        return View();
    }
    Code snippet 3-5.cs
  2. Having made this one small addition, start your application. You will be prompted to modify your web.config file to enable debugging. Click OK to have Visual Studio automatically make the change for you.

    The ASP.NET Development Web Server will automatically select a high port number, and your browser will be launched. Your browser will end up navigating to an address like http://localhost:67890 (see Figure 3-10).

    FIGURE 3-10

    Figure 3.10. FIGURE 3-10

    See how there's no .aspx extension? ASP.NET MVC puts you in full control of your URLs, and you'll learn about this in depth in Chapter 4, coming up next.

  3. Now, change the relative URL in your browser's address bar from "/" to "/Home/Foo." Things will get interesting, as shown in Figure 3-11. Remember that we're just returning the result of the call to View in our Foo method. As you're in the Foo method of HomeController, the system is looking for a View called Foo in a number of locations. ASP.NET MVC is smart enough to give you an error message that you can actually do something useful with. It's really quite refreshing!

    System.InvalidOperationException: The view 'Foo' could not be located
    at these paths:
    ~/Views/Home/Foo.aspx,
    ~/Views/Home/Foo.ascx,
    ~/Views/Shared/Foo.aspx,
    ~/Views/Shared/Foo.ascx
    Code snippet 3-6.txt

    The error message lists (see Figure 3-11) the locations where the system looked for Views, in the order searched. It gives you enough information to infer the naming convention for Views. First, it looks in a directory under /Views with the name of the current Controller, in this case Home, then it looks in /Views/Shared. The WebFormsViewEngine that ASP.NET MVC uses by default looks for .aspx pages, then .ascx files. You'll learn about how custom ViewEngines work in Chapter 6.

    FIGURE 3-11

    Figure 3.11. FIGURE 3-11

  4. Go back into HomeController.cs, and change the call to View in the Foo method to include the name of a View as a parameter.

    public ActionResult Foo()
    {
        ViewData["Title"] = "Foo Page";
        return View("Index");
    }
    Code snippet FILENAME
  5. Start your application again, and visit /Home/Foo again. The Index View is rendered, and the Title string appears in the browser's title.

  6. Switch back over to Visual Studio, and set a breakpoint on the line that returns the result of View. Refresh your browser, confirming that you're still at /Home/Foo, and let us dig in.

Your First, er, Third, Request

Your instance of Visual Studio should look more or less like Figure 3-12.

FIGURE 3-12

Figure 3.12. FIGURE 3-12

Spend a moment looking at Visual Studio (or the figure, if you like), and try to determine what it is telling you. How did you get here? Where are you?

You visited/Home/Foo in the browser, and now you're magically sitting on a breakpoint inside of the Foo action method. The Call Stack tool window confirms this, but doesn't tell you enough. How did you get here? Right-click on the whitespace of the call stack, and select "Show External Code." You might also drag the Call Stack tool window and "tear it off" Visual Studio in order to better analyze the crush of information that's going to be revealed.

There's so much information, in fact, that we have taken it upon ourselves to circle some important bits in Figure 3-13. Remember that call stacks are read from bottom to top, where the bottom is where you started and the top is the line you are currently debugging. In this call stack, there are some parts that are more significant than others.

FIGURE 3-13

Figure 3.13. FIGURE 3-13

Starting at the bottom, you can see that the execution thread is chosen and the HttpWorkerRequest is being dispatched and handled by ASP.NET — specifically by System.Web.HttpRuntime. This is the beginning of ASP.NET. Note that this is System.Web, and you're inside System.Web.dll — nothing MVC-specific has happened yet. If you're already familiar with Web Forms, you might find it useful to remember what is ASP.NET proper, where it ends, and where ASP.NET MVC starts.

The first significant thing happens (remember, you're reading from bottom to top) in the callout in Figure 3-13. What can you learn from this single stack frame? ASP.NET MVC is built on ASP.NET with HttpHandlers and HttpModules. That's where MVC get its hooks in.

The fact that ASP.NET MVC is implemented as an HttpHandler is comforting. It's good to know that the team "played by the rules" when writing it. There's no internal knowledge or secrets in the design of ASP.NET MVC. It's written using the same public constructs and APIs that we all have available to us.

Another thing you can glean from these discoveries is that because ASP.NET MVC uses HttpHandlers (and HttpModules) to do its work, MVC is built on ASP.NET. This might seem like an obvious statement to some, but a very common question is, "Is ASP.NET MVC a whole new ASP.NET?" You can see from Figure 3-13 that it's not. It's built on the same infrastructure — the same core ASP.NET that you've used for years.

The Request Life Cycle

Glance back at Figure 3-12 and then look at that call stack. Remember that you're currently sitting on a breakpoint in the Foo method inside the HomeController. Who created HomeController? Someone had to "new it up." Who called Foo for you? Look to the call stack, my friends.

Inside the MvcHandler's ProcessRequest method an instance of a Controller is created by the DefaultControllerFactory. ASP.NET MVC creates an instance of the HomeController and then calls the Execute method on the Controller. This method, in term, relies on the Controller's action invoker (by default, a ControllerActionInvoker) to actually call the method.

Remember that you opened up a browser and requested /Home/Foo. The ASP.NET MVC application routed the request to an MvcHandler. That Handler created an instance of the HomeController and called the Foo method. ASP.NET MVC handled both object activation and method invocation for you.

The /Home/Foo URL was intercepted by the UrlRoutingModule, which you'll learn about in Chapter 4. That module is responsible for making sure the right URLs go to the right Controllers by parsing the URLs and creating some routing data. The MVC pipeline uses a ControllerFactory and a ControllerActionInvoker to create your controller and call its method, respectively.

Controllers exist to do stuff. What that stuff is, is up to you. They talk to a Model, do calculations, whatever. However, they don't render HTML, and they don't talk to databases. That's separation of concerns. Controllers are concerned with controlling.

The Controller passes Models and ViewData to a View, which is concerned with rendering HTML (or whatever you'd like). That HTML contains links to other URLs, and the cycle continues.

SUMMARY

ASP.NET MVC is a new way to think about writing web applications on ASP.NET. It holds tenets like testability, flexibility, and maintainability dear. However, remember that it's built on top of core ASP.NET services, just like Web Forms. It's a different application model, but Web Forms has more in common with MVC than you might initially think. It's a whole new world, yes, but all the good stuff you know and love like Session, Caching, Membership, the Provider Model, as well as ASP.NET's proven scalability are there. All this makes up the larger thing we call ASP.NET, and clearly, "ASP.NET > ASP.NET MVC."

In fact, the authors think you'll find yourself picking and choosing between Web Forms and MVC depending on the needs of your app. The rest of the book will discuss how you can write, run, test, and understand ASP.NET MVC applications, but all of Chapter 12 is dedicated to writing what we're calling ASP.NET hybrid apps — that is, apps that are both Web Forms and MVC.

You've got more tools to choose from, and it's not an either-or decision. We hope you will continue to enjoy working with ASP.NET as much as we do. We're enjoying it even more now that we have more choices.

Hello, MVC World!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset