Yan-Feng

记录经历、收藏经典、分享经验

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Overview

Add a note hereThis 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?

Add a note hereA 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.

Add a note hereAs 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 (the authors, as of this writing, all work for Microsoft). 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!

Add a note hereYou 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

Add a note hereSome 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.

Add a note hereTake a moment and remember the state of development on the Microsoft platform before ASP.NET was released in January of 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, while 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.

Add a note hereDevelopers 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.

Add a note hereFast forward six 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.

Add a note hereThe 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 understanding what you're losing, and how your development style will change as a result.

Add a note herePresumably, Dear Reader, 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 six years by creating an incredibly (even deceptively) simple ASP.NET Web Forms application.

Add a note hereA Basic Web Forms Application

Add a note hereHead over to Visual Studio and go to File ð New Project and create a new ASP.NET Web Application in Visual Studio. This should be a Web Forms application, not an ASP.NET MVC application. Now, open up the default.aspx file and drag a Button, a Label, and a TextBox over onto the design surface, as shown in Figure 3-1. Don't worry — this is not about Hello World, it's about exploring the "plumbing" of a Web Forms application.

Image from book
Add a note hereFigure 3-1

Add a note hereNext, simply double-click 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.

Add a note hereRemember 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.

Add a note hereASP.NET Web Forms explicitly decided as a programming model that it would:

  • Add a note hereRepresent a page as a "control tree," where each control was accessible via the programmer on the server side.

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

  • Add a note hereMake state management as transparent as possible by offering options like the Session, Cache and most significantly, ViewState.

Add a note hereLet'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.

Add a note hereListing 3-1
Image from book

Add a note hereASPX

Add a note here<%@ 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>

Add a note hereCode-Behind

Add a note herepublic partial class _Default : System.Web.UI.Page{   protected void TextBox1_TextChanged(object sender, EventArgs e)   {      Label1.Text = "This text is different from before!";   }}
Image from book

Add a note hereIf 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).

Image from book
Add a note hereFigure 3-2

Add a note hereYou 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 on your behalf for two reasons:

  • Add a note hereOne, because if it was handled automatically by Web Forms, it likely isn't handled automatically by ASP.NET MVC.

  • Add a note hereTwo, 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.

Add a note hereLet'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.

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

Add a note here<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=Button1type=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>

Add a note hereThere are three things in this HTML that are specific to ASP.NET Web Forms:

  • Add a note hereNotice 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.

  • Add a note hereYou 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.

  • Add a note hereThere'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.

Add a note hereThere'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.

Add a note hereThe most significant concept in Web Forms is the idea that your page will have a lifecycle and raise events!

Add a note hereThe Importance of Events

Add a note hereYou 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.

Add a note hereIn 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.

Image from book
Add a note hereFigure 3-3

Add a note hereThe fact that Web Forms is storing the state of the view enables the possibility of a "changed" event. If you want to learn more about the innards ViewState, including ways to optimize it, certainly check out Professional ASP.NET 3.5 from Wrox.

Add a note hereIf you run the application, your initial page load will look like Figure 3-4.

Image from book
Add a note hereFigure 3-4

Add a note hereEnter some text in the textbox and click the button; the results will look something like Figure 3-5.

Image from book
Add a note hereFigure 3-5

Add a note hereThis 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?

The Leak: Where Web Forms Doesn't Exactly Fit

Add a note hereThere are a number of really attractive aspects of the sample you just looked at:

  • Add a note hereThe IDE has a powerful visual designer that abstracted away the HTML completely.

  • Add a note hereYou 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.

  • Add a note hereThe values of the textbox were "persisted" for you over a medium (HTTP) that is stateless.

Add a note hereIn 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?

Add a note hereWhen 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.

Add a note hereThe 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.

Important 

Add a note hereProduct Team Aside

Add a note hereOne of the main issues that faced the .NET team was that the current language set at Microsoft was either too complex (C++) or too "basic" (VB) to work properly with their new platform. They realized quickly that they needed to appeal to two camps of developers — those with a more embedded computer science background (who predominantly used C++) and those who were more focused on end-user applications (the VB6-ers).

Add a note hereTo address this they created a whole new language, which they dubbed "COOL" — C-Like Object Oriented Language (which is now known as C#) and also "extended" VB into what's now known as VB.NET. Both languages are used quite prevalently, with VB.NET edging C# out slightly. There exists a bit of a "ribbing" between language camps, with the C# folks generally taking a "down the nose" view of VB.NET.

Add a note hereThe VB.NET camp, however, will cite Linus Torvalds usually in defense of their language choice:

Add a note hereFor example, I personally believe that Visual Basic did more for programming than Object-Oriented Languages did. Yet people laugh at VB and say it's a bad language, and they've been talking about OO languages for decades.

Add a note hereAnd no, Visual Basic wasn't a great language, but I think the easy database interfaces in VB were fundamentally more important than object orientation is, for example.

Add a note hereASP.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.

Add a note hereWeb 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.

Add a note hereViewState

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

Add a note hereIf 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 choosing to complain about bloat using the default settings.

Add a note hereControlling Your Angle Brackets

Add a note hereWhile ASP.NET Web Forms offers a sophisticated Control Adapter model, so developers can change the way controls render themselves, it's been said 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, while ASP.NET has made some strides, it can't be said that you have absolute control over your HTML using Web Forms.

Add a note hereDifferent 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, and the results just don't work well together.

Add a note hereClient IDs

Add a note hereCertain server-side controls in ASP.NET are naming containers and implement the INamingContainer interface. This interface exists so that the controls can provide these unique naming scopes for their child controls. The goal is that these controls will have unique IDs that might conflict with other controls around the page. This sounds like a good idea until your page become so sufficiently complicated that you start getting generated control names like:

Add a note herectl00$ContentPlaceHolder1$UserControl1$TextBox1

Add a note hereNot 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.

Add a note hereASP.NET 4.0 includes a feature to give developers back control over the client IDs of their server-side controls. Until then, this remains a point of confusion and contention for many Web Forms developers.

Add a note hereTesting

Add a note hereWeb 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 lifecycle 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 believes differently.

 

Back to Basics: ASP.NET MVC Believes

Add a note hereWe'll spend this whole book discussing the "point" of MVC, but here are its guiding tenets:

  1. Add a note hereBe extensible, maintainable, and flexible.

  2. Add a note hereBe testable.

  3. Add a note hereGet out of the user's way when necessary.

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

Add a note hereStated 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, think that this can be a significant strength, and hopefully this book will convince you as well.

Add a note hereOrchestration Versus Composing

Add a note hereSometimes 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.

Add a note hereIn the Web Forms example above, you dragged some controls on 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.

Add a note hereASP.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.

Add a note hereThe 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 tradeoffs. Pick the vehicle, ahem, Web Framework, that makes you happy.

Add a note hereScottHa has called ASP.NET MVC "Web Forms Unplugged." If this kind of development framework sounds like your cup of tea, then read on!

Add a note hereSeparation of Concerns: What It Means

Add a note hereSeparation 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 its good at — its concern — while maintaining as little knowledge of the other parts as possible.

Add a note hereMVC 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.

Add a note hereWeb Forms has been criticized for effectively merging Controller and 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.

Add a note hereASP.NET MVC tries to embrace this thinking as much as possible, and we hope to encourage you to continue separating the concerns of your applications as you compose them from smaller and more focused pieces.

Add a note hereApproaches to Maintainability

Add a note hereIf 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?

Add a note hereA 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.

Add a note hereMaintainability goes beyond unit testing, however. The design patterns you use (which are discussed further in Chapter 12) 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."

Important 

Add a note hereProduct Team Aside

Add a note hereRob has worked with a client for more than eight years, supporting the same web site (up until he started working for Microsoft). It's a fairly simple support application, which also sells parts to the end user. The application grew over the years from ASP Classic to ASP.NET 1.0, and as of a year ago graduated to ASP.NET 2.0.

Add a note hereThe application was completely rewritten three times in order to take advantage of changes in the platform, and also to add some much-needed functionality. The upgrades went fairly smoothly, however, some better design patterns (and more loosely coupled code) could have lightened the load a bit on the rewrites of course, not completely removing the need for the last one to ASP.NET 2.0.

Add a note hereAn application is an organic thing — much like a child or a favorite pet. They will stay healthy with some love and attention (and food and water) but will need to be supported over time. In the same way that you make your children go to school and eat their vegetables (so they can grow healthy and strong), you owe it to your application to make it easily fixable, testable, and maintainable. A nice way to think about this is that it is like fixing a car. Many car nuts would much prefer to fix a Ford truck than a Nissan sports car because the Ford truck has a lot of room in which to work (and hang your shoplight) and each part is of a standard fit and size.

Add a note hereASP.NET MVC embraces testable and maintainable patterns fully — a subject that is discussed in detail in Chapter 11.

Caring About Testability

Add a note hereTesting 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.

Add a note hereUnit 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.

Add a note hereUnit 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 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.

Add a note hereThere 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 on in Chapter 11).

Add a note hereAnother 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.

Add a note hereLeveraging 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).

Important 

Add a note hereProduct Team Aside

Add a note hereRob is currently working on a project called the "MVC Storefront," which details the creation of an ecommerce application using ASP.NET MVC and TDD (www.asp.net/learn/MVC-videos). This was Rob's first foray into the world of TDD and as such he learned a great deal about creating a highly testable design.

Add a note hereAt first the process seemed very laborious, in fact the word "ceremonious" came to mind a couple of times as there is a lot of work up front when focusing on testability. But as the project grew, and the need to refactor the systems came along (which it does in every project), Rob began to appreciate the growing battery of tests in his test project.

Add a note hereAt one point, Rob refactored the project's shopping cart completely, opting to use a "order as shopping cart" approach. This was quite a deep refactor, and touched just about every system in the application. Normally this would be a matter of holding your breath and watching what breaks; instead it became a matter of fixing all the broken tests (which there were plenty of) and adding just a few more and the work was finished. The best part about this process was the level of confidence Rob had that his application would work as it had before the refactoring.

Add a note hereBy 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

Add a note hereNot 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.

Add a note hereThis Looks Like Classic ASP from 1999!

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

Add a note here"1999 called and they want their Classic ASP Spaghetti Code back!"

Add a note hereIt 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!

Add a note hereOf 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.

Add a note hereWho Moved My <asp:Cheese runat="server"}>

Add a note hereThe 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.

Add a note hereBy 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 Form developers. Because of this, you might be tempted to use some Web Form 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 likemight work just fine (such as the Literal control), but in general, ASP.NET MVC was not designed to support the Control model.

Add a note hereASP.NET MVC includes a number of ways to encapsulate rendered portions of HTML via either partial views or partial rendering with AJAX. You'll learn about those in Chapter 6 and 7, respectively.

Add a note hereYet Another Web Framework

Add a note hereWell, 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's got it 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 feel good at the same time.

Add a note hereASP.NET MVC is built on ASP.NET itself. Perhaps it's 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.

Add a note hereIn 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.

Add a note hereLet's take apart the default application and see how it works.

 

Why "(ASP.NET > ASP.NET MVC) == True"

Add a note hereCreating your first MVC application is fairly straightforward. You can use any version of Visual Studio 2008 to create the basic application, including Express, Standard, Professional, or Team Edition.

Add a note hereThe 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.

Add a note hereWhat 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 web site 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 Files\Microsoft ASP.NET.

Add a note hereAfter you've installed ASP.NET MVC, you're ready to create an ASP.NET MVC application:

  1. Add a note hereStart by opening up Visual Studio 2008 by selecting File ð New Project.

  2. Add a note hereFrom the New Project dialog box (see Figure 3-6), select ASP.NET MVC Web Application.

  3. Add a note herePick 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-6).

  4. Add a note hereBy 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.

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

    Important 

    Add a note hereProduct Team Aside

    Add a note hereScottHa likes to say in presentations that this dialog has two options, "Yes, I want Unit Tests" or "No, I suck." Unit testing is important, and it's one of the key tenets of ASP. NET MVC. You'll learn about testable patterns in Chapter 11.

    Add a note hereThis dialog is owned by the ASP.NET MVC team, not by Visual Studio. Therefore, it has an extensibility point so that third parties (or you!) can add their own unit-testing project templates. You can learn more about this extensibility point at www.asp.net/mvc.

  5. Add a note hereClick 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.

Image from book
Add a note hereFigure 3-6
Image from book
Add a note hereFigure 3-7
Image from book
Add a note hereFigure 3-8

Add a note hereIn 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.

Add a note hereConvention Over Configuration

Add a note hereThis concept was made popular by Ruby on Rails a few years back, and essentially means:

Add a note here"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."

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

  • Add a note hereControllers

  • Add a note hereModels

  • Add a note hereViews

Add a note hereYou don't have to set these folder names in the Web.config — 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.

Add a note hereThis 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).

Add a note hereASP.NET MVC's conventions are pretty straightforward. This is what is expected of your application's structure:

  • Add a note hereThere is a single Controllers directory that holds your Controller classes.

  • Add a note hereEach Controller's class name ends with "Controller" — "ProductController," "HomeController," etc. and lives in the "Controllers" directory.

  • Add a note hereThere is a single Views directory for all the Views of your application.

  • Add a note hereViews 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.

  • Add a note hereAll 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.

Add a note hereIf 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).

Image from book
Add a note hereFigure 3-9

Add a note hereThere are two controllers, "HomeController" and "AccountController" in the Controllers directory, and a number of Views in the Views directory. The following discussion focuses on the Views under /Views/Home named "About" and "Index."

Add a note hereWhile there is no convention that is expected of you with respect to what you name your Views, you can lean on 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.

Add a note hereYou 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:

Add a note herereturn View();

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

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

    Add a note herepublic ActionResult Foo(){    ViewData["Title"] = "Foo Page";    return View();}
  2. Add a note hereHaving 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.

    Add a note hereThe 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).

    Add a note hereSee 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. Add a note hereNow, change the relative URL in your browser's address bar from / to /Home/Foo. Things will get interesting as shown in Figure 3-6. 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!

    Add a note hereSystem.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

    Add a note hereThe 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.

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

    Add a note herepublic ActionResult Foo(){    ViewData["Title"] = "Foo Page";    return View("Index");}
  5. Add a note hereStart your application again, and visit /Home/Foo again. The Index View is rendered, and the Title string appears in the browser's title.

  6. Add a note hereSwitch 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.

Image from book
Add a note hereFigure 3-10
Image from book
Add a note hereFigure 3-11

Add a note hereYour First, er, Third, Request

Add a note hereYour instance of Visual Studio should look more or less like Figure 3-12.

Image from book
Add a note hereFigure 3-12

Add a note hereSpend 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?

Add a note hereYou visited /Home/Foo in the browser, and now you're magically sitting on a breakpoint inside of Foo action method. The Call Stack tool window confirms this, but doesn't tell you enough. How did we get here? Right-click 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.

Important 

Add a note hereProduct Team Aside

Add a note hereScottHa likes to refer to Show External Code as one of the "Stop lying to me, Visual Studio" options. He's not a fan of information hiding, or The Matrix. Keanu Reeves' horrible acting can't ruin ASP.NET MVC, though. At least, he's pretty sure it can't. Here's hoping.

Add a note hereThere's so much information, in fact, that the authors have taken it upon themselves 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.

Image from book
Add a note hereFigure 3-13

Add a note hereStarting 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.

Add a note hereThe 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.

Add a note hereThe fact that ASP.NET MVC is implemented as an HttpHandler is comforting. It's comforting 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.

Important 

Add a note hereProduct Team Aside

Add a note hereScottHa says he finds great comfort in this discovery. If there's less magic in ASP.NET MVC, that means he'll be able to understand it. If ASP.NET MVC is an HttpHandler, and we've written lots of those, then it's less magical than we thought! It's also nice to see that ASP.NET itself was flexible and extensible enough to allow something like ASP.NET MVC to be created.

Add a note hereAnother 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.

Add a note hereThe Request Lifecycle

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

Add a note hereInside 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.

Add a note hereRemember 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.

Add a note hereThe /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.

Add a note hereControllers 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.

Add a note hereThe Controller passes 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

Add a note hereASP.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 build 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 all there. All this makes up the larger thing we call ASP.NET, and clearly, "ASP.NET > ASP.NET MVC."

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

Add a note hereYou'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.

Add a note hereHello MVC World!

posted on 2010-06-23 16:25  Yan-Feng  阅读(432)  评论(0编辑  收藏  举报