Sie sind auf Seite 1von 506

O F F I C I A L

M I C R O S O F T

L E A R N I N G

P R O D U C T

10264A

Developing Web Applications with Microsoft Visual Studio 2010

Volume 1

ii

Developing Web Applications with Microsoft Visual Studio 2010

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places, and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. The names of manufacturers, products, or URLs are provided for informational purposes only and Microsoft makes no representations and warranties, either expressed, implied, or statutory, regarding these manufacturers or the use of the products with any Microsoft technologies. The inclusion of a manufacturer or product does not imply endorsement of Microsoft of the manufacturer or product. Links may be provided to third party sites. Such sites are not under the control of Microsoft and Microsoft is not responsible for the contents of any linked site or any link contained in a linked site, or any changes or updates to such sites. Microsoft is not responsible for webcasting or any other form of transmission received from any linked site. Microsoft is providing these links to you only as a convenience, and the inclusion of any link does not imply endorsement of Microsoft of the site or the products contained therein. 2010 Microsoft Corporation. All rights reserved. Microsoft, and Windows are either registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries. All other trademarks are property of their respective owners.

Product Number: 10264A Part Number: X17-47398 Released: 11/2010

Programming in Visual Basic with Microsoft Visual Studio 2010

iii

iv

Programming in Visual Basic with Microsoft Visual Studio 2010

Programming in Visual Basic with Microsoft Visual Studio 2010

vi

Programming in Visual Basic with Microsoft Visual Studio 2010

Programming in Visual Basic with Microsoft Visual Studio 2010

vii

viii

Programming in Visual Basic with Microsoft Visual Studio 2010

Developing Web Applications with Microsoft Visual Studio 2010

ix

Developing Web Applications with Microsoft Visual Studio 2010

Acknowledgements
Microsoft Learning would like to acknowledge and thank the following for their contribution towards developing this title. Their effort at various stages in the development has ensured that you have a good classroom experience.

Carsten ThomsenSubject Matter Expert


Carsten Thomsen is an independent consultant who has worked since 1990 as a software developer, analyst, architect, and author. He holds a number of Microsoft certifications, including MCTS and MCPD, in various tools and applications, including the Microsoft .NET Framework, Microsoft Visual Basic, Microsoft Visual C#, and Microsoft Office SharePoint Server 2007. He works with architecture, research, analysis, development, and troubleshooting, and spends countless hours with the Windows operating system and many other Microsoft server products, including Hyper-V and SQL Server.

Jeff WashburnSubject Matter Expert


Jeff Washburn is a Director of Microsoft Solutions for Sogeti USA. He specializes in architecting and building enterprise applications for some of the worlds largest international corporations. Jeff has been a Microsoft Certified Trainer and has developed and taught Microsoft curriculum for the last 12 years. In his free time, Jeff is an ice hockey referee and enjoys long distance motorcycling.

Toi WrightSubject Matter Expert


Toi is an independent consultant who has worked as a software developer for over 25 years. She has a Bachelor of Science degree in Computer Science and Engineering from the Massachusetts Institute of Technology, and a Master of Business Administration degree from Carnegie Mellon University. She has been a Microsoft MVP in ASP and ASP.NET since 2005. Toi is responsible for creating a national initiative for Microsoft, and its partners in starting We Are Microsoft, (www.wearemicrosoft.com), a community based partnership between IT professionals and local non-profits. She has been a leader and organizer of technical user groups in the Dallas, Texas area for over 10 years. She is currently the President of the Dallas ASP.Net User Group, www.dallasasp.net. She is the founder of Geeks in Pink, www.geeksinpink.org.

Tiberiu CovaciASP.NET: Developer and Trainer


Tibi started his developer career in 1991, and since 1995 has worked with different Microsoft technologies and platforms. Since 2004, he has been working as an independent trainer, teaching Microsoft Official Curriculum classes, on all levels for .NET programming.

Developing Web Applications with Microsoft Visual Studio 2010

xi

Contents
Module 1: Overview of Web Application Architecture and Design
Lesson 1: Overview of IIS 7.0 Lesson 2: Overview of ASP.NET 4.0 Lesson 3: Introduction to the MVC Framework Lesson 4: Overview of the Request Life Cycle Lab 1: Adventure Works Website Review 1-3 1-15 1-19 1-23 1-28

Module 2: Designing a Web Application


Lesson 1: Web Applications: Case Studies Lesson 2: Web Application Design Essentials Lesson 3: Visual Studio 2010 Tools and Technologies for Web Application Design Lab 2: Redesigning the Adventure Works Website 2-19 2-24 2-3 2-9

Module 3: Developing MVC Models


Lesson 1: Exploring Ways to Create MVC Models Lesson 2: Working with Data in MVC Models Lesson 3: Creating a Data Repository Lab 3: Creating MVC Models 3-3 3-10 3-16 3-30

Module 4: Developing MVC Controllers


Lesson 1: Implementing MVC Controllers Lesson 2: Creating Action Methods Lab 4: Developing MVC Controllers 4-3 4-13 4-29

Module 5: Developing MVC Views


Lesson 1: Implementing MVC Views Lesson 2: Implementing Strongly-Typed MVC Views Lesson 3: Implementing Partial MVC Views Lab 5: Developing MVC Views 5-3 5-14 5-28 5-35

Module 6: Designing for Discoverability


Lesson 1: Search Engine Optimization Lesson 2: Discoverability Files Lesson 3: Using ASP.NET Routing Lab 6: Designing for Discoverability 6-3 6-12 6-22 6-43

Module 7: Writing Server-Side Code for Web Forms


Lesson 1: Overview of the Structure of a Web Application Lesson 2: Controlling View State 7-3 7-10

xii

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 3: Localizing a Web Application Lesson 4: Persisting Data on a Web Forms Page Lesson 5: Validating User Input Lab 7: Writing Server-Side Code for Web Forms

7-16 7-27 7-33 7-42

Module 8: Optimizing Data Management for Web Forms


Lesson 1: Managing Data by Using LINQ to Entities Lesson 2: Using Data Source Controls Lesson 3: Using ASP.NET Dynamic Data Lab 8A: Optimizing Data Management for Web Forms Lab 8B: Optimizing Data Management for Web Forms 8-3 8-18 8-61 8-37 8-77

Module 9: Ensuring Quality by Debugging, Unit Testing, and Refactoring


Lesson 1: Debugging and Refactoring Code Lesson 2: Unit Testing Code Lesson 3: Processing Unhandled Exceptions Lesson 4: Test-Driven Development Lab 9: Debugging, Unit Testing and Refactoring 9-3 9-22 9-30 9-37 9-43

About This Course

xiii

About This Course


This section provides you with a brief description of the course, audience, suggested prerequisites, and course objectives.

Course Description
In this 5-day course, experienced web developers who know the basics of Web Forms development gain more advanced ASP.NET Web Forms and ASP.NET MVC design and development skills. Learning the MVC models and improving web application performance through server-side and client-side programming are the primary focus of this training.

Audience
This audience includes professional web developers who use Microsoft Visual Studio in a team-based, medium to large-sized development environment. Members of the audience have a minimum of two to three years of experience developing web-based applications by using Microsoft Visual Studio and Microsoft ASP.NET. Members of the audience are experienced users of Microsoft Visual Studio 2008 SP1 and newer releases of the Visual Studio product. The audience understands how to use the new features of Visual Studio 2010. Members of the audience should have a minimum of 3 months of experience completing the following web development tasks: Identify the components of a simple ASP.NET 3.5 web application project Create (start) a new ASP.NET web application project Add a server control to a Web Form Configure the basic properties of a server control Build (compile) an ASP.NET Web Forms application Deploy an ASP.NET Web Forms application Add a new Web Form to an ASP.NET Web Forms application Add and configure server controls in the new Web Form Implement code-behind pages in a Web Forms application Create event procedures for ASP.NET server controls Handle Page events in a Web Forms application Debug a web application to view run-time information Debug a web application remotely Enable and implement tracing a web application Add validation controls to a Web Form and configure the validation controls Add validation summary Add appropriate error messages for the validation controls Add and apply a new master page Convert an existing Web Form to a content page Connect to a Microsoft SQL Server database by using the SqlDataSource control

xiv

About This Course

Bind a user control to the data source Modify the source database and verify the changes Load data from an XML file by using LINQ to XML Save data to the database by using LINQ to SQL Display data from the database by using LINQ to SQL Register LINQ to SQL with Dynamic Data Build a Dynamic Data web page Test the Dynamic Data web page Implement partial-page updates using ASP.NET Ajax Display progress when updating a page with partial-rendering Reuse existing functionality exposed by using XML Web Services Create a web reference proxy for an XML web service Call Web Service method from a Web Form by using the web reference proxy Examine how ViewState helps to maintain server control state Create an Application variable and use it maintain state Configure an ASP.NET web application by using the Web.config file Publish a Microsoft ASP.NET web application to a website Implement Windows and Forms authentication Implement File and URL authorization

Student Prerequisites
In addition to their professional web development experience, students who attend this training should have the following technical knowledge: An understanding of the problem-solving techniques that apply to software development, including the following principles of software development: Modern software development models Typical phases of a software development life cycle Concepts of event-driven programming Concepts of object-oriented programming Creating use-case diagrams Designing and building a user interface Developing a structured application

A basic understanding of web, macro, and Windows scripting techniques, and some hands-on experience writing scripts. A general understanding of the purpose, function, and features of the following .NET Framework topics: Common Language Runtime (CLR) .NET Framework class library

About This Course

xv

Common Type System Component interoperation Cross-Language interoperability Assemblies in the CLR Application domains Run-time hosts supported by the .NET Framework

Experience using Visual Studio 2008 or Visual Studio 2010 in the following task areas: Declaring and initializing typed variables using the CamelCase naming convention Using arithmetic, relational, and logical operators in code statements Using branching statements to control code execution Using looping statements to iterate through collections or repeat steps until a specified condition is met Creating classes and methods to establish the basic structure of an application Using methods and events to implement the programming logic of an application Identifying syntax and logic errors Accessing and managing data from a data source

Experience in object-oriented design and development as follows: Creating and accessing classes and class properties Creating and accessing methods and overloaded methods Implementing inheritance, base classes, and abstract classes Declaring, raising, and handling events Responding to and throwing exceptions Implementing interfaces and polymorphism Implementing shared and static members Implementing generics Creating components and class libraries

Experience in N-Tier application design and development as follows: Managing a software development process Controlling input at the user interface level in Windows client and web applications Debugging, tracing, and profiling .NET applications Monitoring and logging .NET applications Implementing basic testing best practices Performing basic Data Access tasks with LINQ Basics of LINQ to XML Basics of LINQ to Entities Basics of LINQ to SQL

xvi

About This Course

Implementing basic security best practices in .NET applications Basics of Code Access Security (CAS) Basics of Role-based security Basics of Cryptography Services

Implementing basic service calls Basics of creating and consuming XML Web Services Basics of creating and consuming WCF Services

Using .NET configuration files Deploying .NET Framework applications using ClickOnce and the MS Installer

Course Objectives
After completing this course, students will be able to: Describe the underlying architecture and design of a web application. Apply best practices and make appropriate trade-offs based on business requirements when designing a web application. Develop MVC models, controllers, and views. Optimize the design of a web application for discoverability by search engines. Write server-side code for Web Forms. Optimize data management for Web Forms. Ensure quality by debugging, unit testing, and refactoring. Secure a web application. Apply Master pages and CSS for a consistent application user interface (UI). Develop client-side scripts and services for a responsive, rich, and interactive UI. Implement advanced Ajax in a web application. Deploy a web application.

Course Outline
This section provides an outline of the course: Module 1, Overview of Web Application Architecture and Design, explains the underlying architecture and design of a web application. Module 2, Designing a Web Application, explains the best practices and trade-offs that you need to make when designing a web application. Module 3, Developing MVC Models, explains the MVC development model (Models, Controllers, and Views), and how to create the models that are used to access and modify the data in a data source. Module 4, Developing MVC Controllers, explains how to create the controllers that are used to respond to communications from the user, and to implement the application flow and logic. Module 5, Developing MVC Views, explains how to create the views that are used to expose the application UI. Students will also learn to manage pre-action and post-action behavior of controller action methods using the included action filters provided as part of MVC.

About This Course

xvii

Module 6, Designing for Discoverability, explains how to optimize the design of a website for discoverability by search engines. Module 7, Writing Server-Side Code for Web Forms, explains the advanced features of server side coding and technologies. Module 8, Optimizing Data Management for Web Forms, explains some of the ways to optimize and display data management tasks for a Web Forms-based application using Dynamic Data, Data Binding, Linq To Entities, server-side controls, and server-side code. Module 9, Ensuring Quality by Debugging, Unit Testing, and Refactoring, explains how to perform check-in testing for Web Forms and MVC applications, as well as how to use the built-in debugging capabilities of Visual Studio 2010. Module 10, Securing a Web Application, explains how to mitigate common security threats and implement the essentials of web security in both MVC and Web Forms applications. Module 11, Applying Master Pages and CSS, explains how to apply master pages and CSS for a consistent application UI. Module 12, Developing Client-side Scripts and Services, explains how to develop client-side scripts and services for a responsive, rich, and interactive application UI. Module 13, Implementing Advanced Ajax in a Web Application, explains how to add a rich user experience to web applications using the Microsoft Ajax Library and the jQuery JavaScript Library. Module 14, ASP.NET Deployments, explains how to plan, configure, and perform deployment tasks associated with a production website. Students will also learn about the website life cycle as it pertains to deployment. Module 15, Developing a Web Application by Using Silverlight, introduces students to Silverlight by having them integrate a Silverlight module into an existing ASP.NET application.

xviii

About This Course

Course Materials
The following materials are included with your kit: Course Handbook A succinct classroom learning guide that provides all the critical technical information in a crisp, tightly-focused format, which is just right for an effective in-class learning experience. Lessons: Guide you through the learning objectives and provide the key points that are critical to the success of the in-class learning experience. Labs: Provide a real-world, hands-on platform for you to apply the knowledge and skills learned in the module. Module Reviews and Takeaways: Provide improved on-the-job reference material to boost knowledge and skills retention. Lab Answer Keys: Provide step-by-step lab solution guidance at your finger tips when its needed.

Course Companion Content on the http://www.microsoft.com/learning/companionmoc/ Site: Searchable, easy-to-navigate digital content with integrated premium on-line resources designed to supplement the Course Handbook. Modules: Include companion content, such as questions and answers, detailed demo steps and additional reading links, for each lesson. Additionally, they include Lab Review questions and answers and Module Reviews and Takeaways sections, which contain the review questions and answers, best practices, common issues and troubleshooting tips with answers, and real-world issues and scenarios with answers. Resources: Include well-categorized additional resources that give you immediate access to the most up-to-date premium content on TechNet, MSDN, Microsoft Press

Student Course files on the http://www.microsoft.com/learning/companionmoc/ Site: Includes the Allfiles.exe, a self-extracting executable file that contains all the files required for the labs and demonstrations. Course evaluation At the end of the course, you will have the opportunity to complete an online evaluation to provide feedback on the course, training facility, and instructor. To provide additional comments or feedback on the course, send e-mail to support@mscourseware.com. To inquire about the Microsoft Certification Program, send e-mail to mcphelp@microsoft.com.

About This Course

xix

Virtual Machine Environment


This section provides the information for setting up the classroom environment to support the business scenario of the course.

Virtual Machine Configuration


In this course, you will use Microsoft Hyper-V to perform the labs. The following table shows the role of each virtual machine used in this course. Virtual machine 10264A-GEN-DEV Role Stand-alone machine

Software Configuration
The following software is installed on each virtual machine: Visual Studio 2010 Ultimate (including .NET Framework 4.0) Microsoft Silverlight 4 Microsoft Silverlight 4 Tools for Visual Studio 2010 Windows Internet Explorer 8 Microsoft SQL Server 2008 R2 Express Microsoft SQL Server 2008 R2 Management Studio Express IIS Search Engine Optimization (SEO) Toolkit

Course Files
There are files associated with the labs in this course. The lab files are located in the folder on the student computers.

Classroom Setup
Each classroom computer will have the same virtual machine configured in the same way.

Course Hardware Level


To ensure a satisfactory student experience, Microsoft Learning requires a minimum equipment configuration for trainer and student computers in all Microsoft Certified Partner for Learning Solutions (CPLS) classrooms in which Official Microsoft Learning Product courseware are taught.

xx

About This Course

Overview of Web Application Architecture and Design

1-1

Module 1
Overview of Web Application Architecture and Design
Contents:
Lesson 1: Overview of IIS 7.0 Lesson 2: Overview of ASP.NET 4.0 Lesson 3: Introduction to the MVC Framework Lesson 4: Overview of the Request Life Cycle Lab 1: Exploring the Adventure Works Website 1-3 1-15 1-19 1-23 1-28

1-2

Developing Web Applications with Microsoft Visual Studio 2010

Module Overview

An understanding of how the technology that runs your web application handles requests and returns content to your users is important when determining your web applications architecture and design. Understanding how web applications function will also assist you in supporting your application once it is completed and released to your user community. This module will introduce you to the key concepts of building web applications in .NET Framework 4.0. After completing this module, you will become familiar with the life cycle of events that occur when a request is made in both Web Forms and MVC. You will also learn how you can work with the life cycle of events to manipulate the content that is displayed to your users.

Overview of Web Application Architecture and Design

1-3

Lesson 1

Overview of IIS 7.0

Internet Information Services (IIS) 7.0 is the engine that runs your ASP.NET Web Forms and MVC applications. Understanding how IIS 7.0 works will help you support and deliver your applications to your users when they are released.

Lesson Objectives:
Describe the key features of IIS 7.0. Describe the underlying architecture of IIS 7.0. Administer a website by using IIS Manager.

1-4

Developing Web Applications with Microsoft Visual Studio 2010

Key Features of IIS 7.0

IIS 7.0 is a modern, flexible, and secure web server designed to meet any hosting need that you may have to deliver content to the web. IIS is built on a modular architecture that allows you to implement features and functionality that you need, and turn off what you do not need. Following are some key features of IIS 7.0.

Modular Architecture
IIS 7.0 is built upon new architecture that is different from previous versions of IIS. Rather than including the core functionality in the server itself, IIS 7.0 is built upon a web server engine to which you can add or remove components, called modules, depending on your needs. Modules are individual features that the server uses to process requests. For example, IIS uses configuration modules to access application configuration files and cache modules to manage cache activity.

New Configuration Store


IIS 7.0 uses a new configuration store that replaces the metabase model in IIS 6. The new configuration store will be familiar to developers used to the .NET XML-based .config format. IIS 7.0 uses a central configuration file named applicationHost.config located in %WINDIR%\System32\InetSrv\Config\. The file applicationHost.config contains global settings for each of the modules in IIS 7.0. Any property set in this file applies to all sites hosted by IIS. In addition to the central file, web.config files can appear at any level of a hosted site or web applications hierarchy that can override the global settings in the central file for the applicable scope of the web.config file (site, application, and directory).

Management
IIS Manager allows you to manage each site and web application that IIS is hosting on a local or remote machine. IIS Manager separates the management of your hosted sites and applications following the

Overview of Web Application Architecture and Design

1-5

modular nature of IIS 7.0. When you open IIS Manager, you will see your options separated by domain, such as ASP.NET, IIS, and Management. The management options are accessible by icons that represent the features that you can manage, such as Authentication, Logging, and Output Caching. The IIS Manager for IIS 7.0 follows the modular architecture by breaking up features into distinct modules that can be managed separately. Question: Which benefits are offered by the modular IIS architecture? Name at least one.

1-6

Developing Web Applications with Microsoft Visual Studio 2010

Architecture of ASP.NET on IIS 7.0

IIS 7.0 employs a new modular architecture that is very different from previous versions of IIS. The core modules are categorized according to the functionality for which they are responsible. The preceding illustration shows some of IISs core modules and their responsibilities, such as Security and Management. Gaining a deeper understanding of IISs core modules and its modular architecture will allow you to take advantage of built-in features that do not need to be created in your web application. Each module concerns itself with a specific piece of functionality. As an example, the Basic Authentication Module performs basic forms authentication. The categories by which these modules are grouped in the illustration make up the core functionality of IIS.

Security
Includes all modules that are concerned with authentication, authorization, and securing resources.

Application Development
Includes all modules that are concerned with processing custom-developed application logic, such as ASP.NET.

Health and Diagnostics


Includes all modules that are concerned with monitoring the health and state of the server. Its applications are grouped as Health and Diagnostics.

FTP Publishing
Includes all modules that are concerned with FTP transmission and publishing.

Performance
Includes all modules that are concerned with increasing performance, such as compression.

Overview of Web Application Architecture and Design

1-7

Management
Includes all modules that provide administration and management functionality.

Common HTTP Web Server Components


Includes all modules that provide HTTP request and response processing.

Windows Process Activation Service (WAS)


Includes all modules that provide Windows Process Activation Service (WAS) functionality. WAS allows IIS to serve non-HTTP or non-HTTPS requests.

1-8

Developing Web Applications with Microsoft Visual Studio 2010

ASP.NET Enhancements for IIS 7.0

In IIS 7.0, ASP.NET integration is significantly improved. IIS 7.0 enhances existing applications and allows new applications to take advantage of ASP.NET features in a variety of new ways.

All Content Types Supported


In the past, ASP.NET functionality such as Forms authentication, roles, URL authorization, and output caching were only available to ASP.NET content types such as ASPX pages. Static files, classic ASP pages, and other content types could not benefit from these services. In IIS 7.0, all ASP.NET services are provided uniformly to all content. For example, you can protect all of your web content, including images and classic ASP pages, with your existing ASP.NET access control solution built on ASP.NET Forms authentication, membership, and login controls.

Fully Extend IIS with ASP.NET


Previous versions of IIS frequently required server extensibility to be developed by using the native ISAPI filter or extension extensibility mode, due to the runtime limitations of ASP.NET. IIS 7.0 allows ASP.NET modules to plug in directly to the server pipeline, with the same runtime fidelity as modules developed with the native (C++) server API. ASP.NET modules can execute in all run-time stages of the request-processing pipeline, and can execute in any order with respect to native modules. The ASP.NET API is also expanded to allow more control over request processing than was previously possible.

Unified Server Runtime


Tighter ASP.NET integration also unifies many of the features between IIS 7.0 and ASP.NET. IIS 7.0 provides a unified configuration for IIS and ASP.NET modules and handlers. Many other features, including custom errors and tracing, have been unified to allow better management and cohesive application design.

Overview of Web Application Architecture and Design

1-9

Demonstration: Administering IIS 7.0 by Using IIS Manager

This demonstration will illustrate the many features of IIS, and show how to administer its functions. These features include: Creating a new website Authentication Permissions Connection strings Application settings Starting and stopping a site Recycling the Application pool

Create a New Website


1. On the Start menu, point to Administrative Tools, right-click Internet Information Services (IIS) Manager, and then click Run as administrator. 2. 3. In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then click Yes.

In Internet Information Services (IIS) Manager, expand 10264A-GEN-DEV (10264A-GENDEV\Admin), and then expand Sites. Right-click Sites, and then click Add Web Site.

1-10

Developing Web Applications with Microsoft Visual Studio 2010

4.

In the Add Web Site dialog box, specify the settings as shown in the following sample. You will need to create the demo subfolder in the C:\inetpub\ folder.

5.

Click OK.

Change Authentication
1. In the Connections pane, click Demo.

2.

In the Demo Home pane, in the IIS section, double-click Authentication.

3.

In the Authentication pane, right-click Basic Authentication, and then click Enable.

Overview of Web Application Architecture and Design

1-11

Edit Permissions
1. 2. 3. In the Connections pane, click Demo. In the Actions pane, click Edit Permissions. In the demo Properties dialog box, click Security.

4. 5. 6. 7. 8.

Click Edit. In the Permissions for demo dialog box, click Add. In the Select Users or Groups dialog box, in the Enter the object names to select box, type IIS_IUSRS, click Check Names, and then click OK. In the Permissions for demo dialog box, click OK. In the demo Properties dialog box, click OK.

Set Connection String


1. 2. In the Connections pane, click Default Web Site, and then click Demo. In the Demo Home pane, in the ASP.NET section, double-click Connection Strings.

3. 4.

In the Actions pane, click Add. In the Add Connection String dialog box, specify the settings as shown in the following illustration.

1-12

Developing Web Applications with Microsoft Visual Studio 2010

5. 6. 7.

Click OK. In the Connection Strings pane, click Content View. In the Demo Content pane, click web.config.

Note: A web.config file is added to the websites root directory. 8. 9. In the Connections pane, right-click Demo, and then click Explore. In Windows Explorer, double-click web.config.

Note: In Microsoft Visual Studio 2010, you can see the new connection string added to the web.config file. 10. Close Microsoft Visual Studio 2010. 11. Close Windows Explorer.

Specify Application Settings


1. 2. 3. In the Connections pane, click Default Web Site, and then click Demo. In the Demo Content pane, click Features View. In the Demo Home pane, in the ASP.NET section, double-click Application Settings..

Overview of Web Application Architecture and Design

1-13

4. 5.

In the Actions pane, click Add. In the Add Application Setting dialog box, specify the settings per the following.

6. 7.

Click OK. In Windows Explorer, double-click web.config.

Note: In Microsoft Visual Studio 2010, you can see the new application setting added to the web.config file. 8. 9. Close Microsoft Visual Studio 2010. Close Windows Explorer.

Restart the Website


1. 2. In the Connections pane, click Default Web Site, and then click Demo. In Actions pane, in the Manage Web Site section, click Restart.

Recycle an Application Pool


1. In the Connections pane, click Application Pools.

1-14

Developing Web Applications with Microsoft Visual Studio 2010

2. 3.

In the Application Pools pane, click DefaultAppPool, and then in the Actions pane, in the Application Pool Tasks section, click Recycle. Close Internet Information Services (IIS) Manager.

Overview of Web Application Architecture and Design

1-15

Lesson 2

Overview of ASP.NET 4.0

ASP.NET 4.0 is the latest .NET framework for building web applications. The features of ASP.NET 4.0 allow you to quickly create compelling web applications that perform and scale to meet the demands of your users.

1-16

Developing Web Applications with Microsoft Visual Studio 2010

ASP.NET 4.0 Architecture

ASP.NET is an engine for processing web requests from beginning to end, and is much more than just Web Forms, Web/WCF Services, and MVC. ASP.NET is a web request-processing engine. Incoming requests are processed and pass through an internal pipeline to an endpoint, where you, as the developer, can attach logic to process the request further.

ASP.NET Components Caching


ASP.NET provides two different kinds of caching: output and application data caching. Output caching stores dynamic page and control content for quick responses without having to process the response dynamically. Application data caching allows you to programmatically store arbitrary objects such as data sets in server memory so that an application can access the object without having to hit the data store.

Pages
Pages refer to Web Forms pages. This provides the functionality necessary to process Web Forms.

Profile
ASP.NET Profiles give you the ability to provide profile functionality to your users. Profiles allow you to store user metadata in your application. Typical uses of Profiles would be to store the full name, address, and other pertinent information that can be attached to a user.

Intrinsic Objects
Intrinsic objects are objects that are automatically created and attached to core objects used in processing requests to ASP.NET resources. An example of an Intrinsic Object is the Request object, which is defined as a property of the HttpContext object.

Overview of Web Application Architecture and Design

1-17

Modules
ASP.NET Modules are components that implement and plug themselves into the ASP.NET requestprocessing pipeline by registering for certain events. When the event occurs, ASP.NET invokes the module so that it can further process the request.

Controls
ASP.NET controls refers to Server Controls that are used in Web Forms projects. Controls are HTML form elements that abstract the markup and allow you to separate the processing from your page.

Roles
ASP.NET Roles gives you built-in functionality to create roles for your users, and to restrict content according to the role of the user that is accessing the site.

Handlers
HTTP Handlers are .NET components that can act as a target for incoming HTTP requests.

Globalization
ASP.NET has built in components to develop applications that function for multiple cultures.

Master Pages
ASP.NET Master Pages allow you to organize your design into templates, and to restrict content to locations that you assign.

Membership
ASP.NET Membership provides built-in functionality to implement site members and provide login and user tracking features.

1-18

Developing Web Applications with Microsoft Visual Studio 2010

New Features in ASP.NET 4.0

ASP.NET 4.0 includes several new features such as extensible output caching, compressible serialized session state, and performance monitoring for individual applications. New features in ASP.NET include: Extensible ASP.NET 4.0 output caching ASP.NET 4.0 adds extensibility to output caching that enables you to configure one or more custom output-cache providers. Output-cache providers can use any storage medium to persist HTML content. Compressible serialized session state ASP.NET 4.0 adds a new compression option for session-state providers. When the compressionEnabled configuration option is set to true, ASP.NET compresses serialized session state. Performance monitoring for individual applications in a single worker process ASP.NET 4.0 adds resource-monitoring functionality in the CLR. When enabled, administrators have a more granular view of the resource consumption of individual applications. Routing ASP.NET 4.0 adds built-in support for using routing with Web Forms. Routing allows you configure an application to accept request URLs that do not map to physical files. Question: How is compression of serialized session state enabled?

Overview of Web Application Architecture and Design

1-19

Lesson 3

Introduction to the MVC Framework

MVC describes the design pattern Model-View-Controller, which was created to separate the concerns of data structures (M), presentation (V), and application logic (C). ASP.NET MVC is a framework for developing web applications built on top of ASP.NET. The ASP.NET MVC Framework allows you to build web applications using the latest advances in web application development. MVC separates the concerns of data handling, request/response processing, and view rendering to keep your design clean and easy to follow.

Lesson Objectives:
Describe the MVC network.

1-20

Developing Web Applications with Microsoft Visual Studio 2010

What is the MVC Framework?

The MVC Framework was designed according to the MVC pattern, which is a framework for developing web applications built on top of ASP.NET. The MVC Framework, in accordance with the MVC pattern, attempts to separate the concerns of data structures (Model), presentation (View), and business logic (Controller) into distinct components, that together can complete the functionality in a web application. The components of an ASP.NET MVC solution are:

Model
The Model portion of MVC includes all data structures. Your data structures may be dictated by an ORM (Object-Relational Mapping), such as LINQ to Entities, or you may be accessing data directly through requests to your data store. Your data structure objects and data access logic are included in the Model.

View
The View portion of MVC includes all pages, master pages, and shared visual components, such as user controls.

Controller
The Controller contains all the application logic necessary to form a response to a request, such as making requests against Model objects for specific data necessary to fulfill a request, and then feeding that data to the View to display it to the user. Question: What advantages are there in separating the concerns of data structures, presentation, and application logic?

Overview of Web Application Architecture and Design

1-21

Demonstration: Exploring an MVC Application

If you understand the architecture of one ASP.NET MVC application, all other MVC applications will be familiar to you. Due to the convention used in MVC applications, all model objects are contained in the Models folder, all views are contained in the Views folder, and all controllers are contained in the Controllers folder. In addition, all controller class or object names are suffixed with Controller; for example, HomeController for the controller Home.

Exploring the Adventure Works MVC Application


1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Create a new MVC project. a. b. c. d. In the Start Page Microsoft Visual Studio window, on the File menu, click New Project, or press CTRL+SHIFT+N. In the New Project dialog box, in the left pane, in the Installed Templates section, expand Visual C# or Visual Basic, and then click Web. In the New Project dialog box, in the middle pane, click ASP.NET MVC 2 Web Application. In the New Project dialog box, in the middle pane, in the Name box, type DemoMvcApplication, in the Location box, type D:\Demofiles\Module 01\Demo 02, and then click OK.

3. 4.

In the Create Unit Test dialog box, select the No, do not create a unit test project option, and then click OK. View the Controllers folder. In Solution Explorer, expand the Controllers folder.

1-22

Developing Web Applications with Microsoft Visual Studio 2010

Note: Observe that the code files all have the suffix Controller. 5. View the Models folder 6. In Solution Explorer, expand the Models folder.

View all the code in the AccountModels code file. a. b. c. In Solution Explorer, double-click the AccountModels.cs or AccountModels.vb code file. In the AccountModels.cs or AccountModels.vb window, press CTRL+M, CTRL+L. Scroll down and show the different regions of code.

Note: The model code file contains the data structures for this web application and classes that control logic for working with the data store. d. 7. In the AccountModels.cs or AccountModels.vb window, click the Close button.

View the Views folder. In Solution Explorer, expand the Views folder.

Note: Several folders share their name with the names of the controllers in the Controllers folder. 8. View the Views/Shared folder. In Solution Explorer, expand the Views/Shared folder.

Note: The Shared folder contains master pages, user controls, and pages shared across the MVC web application. 9. Close Microsoft Visual Studio 2010. In the DemoMvcApplication - Microsoft Visual Studio 2010 window, click the Close Button.

Question: What other elements did you recognize in the MVC solution?

Overview of Web Application Architecture and Design

1-23

Lesson 4

Overview of the Request Life Cycle

The Request life cycle is composed of the series of events that transpire when processing a web request to your web application. Web Forms and MVC handle these requests differently. These differences will affect how you must implement code to handle these events.

Lesson Objectives:
Describe the life cycle of a Web Forms request. Describe the life cycle of a MVC request. Describe the differences between the life cycle of a Web Forms and MVC request.

1-24

Developing Web Applications with Microsoft Visual Studio 2010

Life Cycle of a Web Forms Request

The Web Forms Page Event Life Cycle


1. 2. 3. 4. 5. 6. 7. 8. 9. The Web Forms page event life cycle begins with a request to a Page resource. The HTTP handler processes the request and initializes the correct Page resource to handle the request. The page initializes, and all server controls in the page raise their initialization events as well. On postbacks (when a HTTP Post request is received), Postback Data (data that is available in the form) is loaded. The page loads and all server controls raise their Load event. On postbacks, the RaisePostBackEvent event is raised that can be accessed programmatically. The view state is saved and the event is raised. The page and all server controls are rendered into markup (HTML) and returned to the web server. The web server returns the rendered response.

Question: What is postback data?

Overview of Web Application Architecture and Design

1-25

Life Cycle of an MVC Request

The MVC Request Event Life Cycle


1. 2. 3. 4. 5. 6. The browser initiates a request. ASP.NET Routing routes the request to the appropriate resource, initiates the necessary controller, and invokes the action on the controller. The controller requests the necessary data from the model and does a lookup to determine the view that is required to render the response. The controller passes the viewdata built from the data structure given by the model to the view. The view takes the viewdata and renders the response. The rendered response is passed back to the browser.

Question: What is the first step of an MVC request?

1-26

Developing Web Applications with Microsoft Visual Studio 2010

Comparison of the Web Forms and MVC Request Life Cycles

The life cycle of Web Forms and MVC requests differs significantly. The Web Forms request life cycle is wrapped entirely around the concept of a Web Forms page. The ASP.NET runtime provides a mapped HTTP handler that passes requests to the appropriate Page resource. MVC uses routing based on the URL of the request to map its handler to the controller that will handle the request. In Web Forms, the page handles the entire process of requesting the necessary data structure needed to provide the content requested and the rendering of the response itself. MVC uses the controller to manage bringing together the resources needed to create a response. The controller requests the necessary data structure from the model, looks up the view necessary to form the response, and passes the viewdata created from the data structure provided by the model to the view, which renders the response. Question: In what other ways do the request life cycles differ between Web Forms and MVC?

Overview of Web Application Architecture and Design

1-27

Working with the Web Forms Page Life Cycle

The events that occur during the Web Forms page life cycle can be manipulated to process the request according to your needs during the Web Forms page life cycle. Often you need to handle and inject new functionality into the page life cycle to handle different scenarios. For example, you may want to handle a postback request that requires action to be taken on form data differently than you would if the request is a new request for the page. Often this processing is handled during the pages Load event as shown in the following example.
[Visual C#] protected void Page_Load(object sender, EventArgs e) { }

[Visual Basic] Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load End Sub

Question: What other scenarios can you imagine where you would need to use events in the pages life cycle to process the page correctly?

1-28

Developing Web Applications with Microsoft Visual Studio 2010

Lab 1: Exploring the Adventure Works Website

Objectives:
Describe the Adventure Works website. Explain code differences between Web Forms and MVC. Describe the request life cycle for both Web Forms and MVC.

Introduction
In this lab, you will review the existing Adventure Works website and become familiar with its design. Furthermore, you will compare how application development by using Web Forms differs from application development by using the MVC framework. Finally, you will explore how to create controls dynamically by adding an advertisement on the page.

Overview of Web Application Architecture and Design

1-29

Lab Scenario

As a web developer at Adventure Works, you have worked extensively with ASP.NET 2.0. However, you have limited experience with ASP.NET 4.0. You need to further explore the features of ASP.NET 4.0 to accomplish the goals set by management for the new Adventure Works website. As a first step toward this end, you want to examine the MVC framework and understand how it compares with the Web Forms programming model.

1-30

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 1: Exploring the Adventure Works Website


The main tasks for this exercise are as follows: 1. 2. 3. 4. 5. 6. 7. 8. Open the AdventureWorks solution in Visual Studio 2010. Start the web application. Browse the products list. Add products to the shopping cart. Place an order. Explore the life cycle of a Web Forms page. Open the AdventureWorksMvc solution in Visual Studio 2010. Explore the life cycle of an MVC request.

Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. 2. 3. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution at the following location. Programming Language Microsoft Visual C# Microsoft Visual Basic Location D:\Lab Files\CS\Lab 01\Starter\WebForms D:\Lab Files\VB\Lab 01\Starter\WebForms

Task 2: Start the web application


Run the AdventureWorks solution in Debug mode.

Task 3: Browse the products list


In the Product Categories list, select Bib-Shorts, and then click the Submit button. Note: Observe the products available in the Bib-Shorts product category.

Task 4: Add products to the shopping cart


1. 2. Add one pair of Mens Bib-Shorts, size M, to the shopping cart. Continue shopping.

Task 5: Place an order


1. 2. Open the shopping cart. Place the order.

Task 6: Explore the life cycle of a Web Forms page


1. 2. 3. Switch to Visual Studio 2010 with the AdventureWorks solution open. Open the Default.aspx Web Form in Code view. Place a breakpoint at the beginning of the Page_Load method.

Overview of Web Application Architecture and Design

1-31

4. 5.

Switch to Windows Internet Explorer. Open the Home page.

Note: The debugger reaches your breakpoint in the Page_Load method. 6. 7. Step through the web application startup until you reach the end of Page_Load method. Continue the web application.

Note: The URL displayed in the address bar of Internet Explorer includes the name of the Web Form or page (Default.aspx) displayed. 8. Close Windows Internet Explorer.

Task 7: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. Open a second instance of Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution at the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 01\Starter\MVC D:\Lab Files\VB\Lab 01\Starter\MVC

Task 8: Explore the life cycle of an MVC request


1. 2. 3. 4. 5. 6. In the Controllers folder, open the HomeController.cs or HomeController.vb file. Notice the methods that are available and the way they relate to the actions that are available to the user. Close the HomeController.cs or HomeController.vb file. Open the Global.asax file. Place a breakpoint at the beginning of the Application_Start method. Run the AdventureWorksMvc solution in Debug mode.

Note: The debugger reaches the breakpoint in the Application_Start method. 7. 8. 9. Examine the static/Shared RegisterRoutes method. Step through the web application startup until you reach the last line of code in the Index action method of the Home controller. Continue the web application.

Note: The URL displayed in the address bar of Internet Explorer does not include the name of the page (Index.aspx) displayed. 10. Close Windows Internet Explorer.

1-32

Developing Web Applications with Microsoft Visual Studio 2010

Results: After completing this exercise, you should have reviewed the Adventure Works website by adding products to your shopping cart and checking out. You should also have reviewed the Page and MVC request life cycles by placing breakpoints in methods that execute during the life cycle.

Overview of Web Application Architecture and Design

1-33

Exercise 2: Comparing Web Forms and MVC


The main tasks for this exercise are as follows: 1. 2. 3. View the AdventureWorks solution in Visual Studio 2010. Examine the markup and code found in the Default.aspx Web Forms page. View AdventureWorksMvc solution in Visual Studio 2010. 1. 2. Examine the markup and code used for rendering the default MVC page. Discuss as a group the differences in the way Web Forms and MVC responds and delivers content to a request.

Task 1: View the AdventureWorks solution in Visual Studio 2010


Switch to the Visual Studio 2010 instance with the AdventureWorks solution open.

Task 2: Examine the markup and code found in the Default.aspx Web Forms page
1. 2. Examine the code in the Default.aspx.cs or Default.aspx.vb code file. Examine the markup in the Default.aspx Web Form.

Task 3: View AdventureWorksMvc solution Microsoft Visual Studio 2010


Switch to the Visual Studio 2010 instance with the AdventureWorksMvc solution open.

Task 4: Examine the markup and code used for rendering the default MVC page
1. Open the Adventure Works MVC project at the following location: Language C# Visual Basic 2. 3. Location D:\Lab Files\CS\Lab 01\Starter\MVC D:\Lab Files\VB\Lab 01\Starter\MVC

Examine the code in the HomeController.cs or HomeController.vb code file. Examine the markup in the Index.aspx page.

Task 5: Discuss as a group the differences in the way Web Forms and MVC responds and
delivers content to a request
In the classroom, discuss the differences between the page life cycles of the two different web application models, Web Forms and MVC, including the page-centric Web Forms request vs. the MVC routing, the use of server controls in Web Forms vs. HTML controls, and MVC helper methods.

Results: After completing this exercise, you should have reviewed the code in a Web Forms and MVC page, and discussed the differences as a class.

1-34

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 3: Working with the Request Life Cycle


The main tasks for this exercise are as follows:
1. 2.

Exploring the life cycle of a Web Forms page. Exploring the life cycle of a MVC request.

Task 1: Explore the life cycle of a Web Forms page


1. 2. 3. 4. 5. 6. Switch to the Visual Studio 2010 instance with the AdventureWorks solution open. View the Default.aspx Web Form. Locate the Content control with the ContentPlaceHolderID property set to MainContent. Add the following Label control markup before any other content in the Content control.
<asp:Label ID="lblAdvertisement" runat="server" />

View the code-behind file for the Default Web Form. In the Page_Load method, add the following code at the beginning of the method. [Visual C#]
lblAdvertisement.Text = "My advertisement here";

[Visual Basic]
lblAdvertisement.Text = "My advertisement here"

7.

Run the web application and view the rendered Default.aspx page.

Note: During the pages Load event, the text is added to the lblAdvertisement Label control. 8. 9. Close Windows Internet Explorer. Close Visual Studio 2010.

Task 2: Explore the life cycle of a MVC request


1. 2. 3. 4. Switch to the Visual Studio 2010 instance with the AdventureWorks solution open. Open the Views\Home\Index.aspx view. Locate the Content control with the ContentPlaceHolderID property value of MainContent. Add the following code before any content in the Content control. [Visual C#]
<p><%= ViewData["Advertisement"] %></p>

[Visual Basic]
<p><%: ViewData("Advertisement") %></p>

5.

Open the file Controllers\HomeController.cs or Controllers\HomeController.vb. In Solution Explorer, expand Controllers, and then double-click HomeController.cs or HomeController.vb.

6. 7.

Locate the Index method in the file. Add the following code at the beginning of the Index method. [Visual C#]

Overview of Web Application Architecture and Design

1-35

ViewData["Advertisement"] = "My advertisement here";

[Visual Basic]
ViewData("Advertisement") = "My advertisement here"

8.

Run the web application and view the rendered Index.aspx view.

Note: During the controllers Index action method, the text is added to Index view by using the ViewData. 9. Close Windows Internet Explorer.

10. Close Visual Studio 2010.

Task 3: Turn off the virtual machine and revert the changes
1. 2. 3. 4. In Microsoft Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert. In the Revert Virtual Machine dialog box, click Revert.

Results: After completing this exercise, you should have explored the life cycle of both a Web Form and an MVC page, by adding code to write to the page during the page request.

1-36

Developing Web Applications with Microsoft Visual Studio 2010

Module Review and Takeaways

Review Questions
1. 2. 3. 4. 5. What are some of the key features of IIS 7.0? What is the purpose of the Adventure Works website? What does it mean when we say that the architecture of IIS 7.0 is modular? What is the MVC framework? How do the Web Forms and MVC request life cycles differ?

Real-world Issues and Scenarios


You have been asked to provide system status messages and error messages to users in your web application. How can you dynamically provide these messages to your users?

Designing a Web Application

2-1

Module 2
Designing a Web Application
Contents:
Lesson 1: Web Applications: Case Studies Lesson 2: Web Application Design Essentials Lesson 3: Visual Studio 2010 Tools and Technologies for Web Application Design Lab 2: Redesigning the Adventure Works Website 2-3 2-9 2-19 2-24

2-2

Developing Web Applications with Microsoft Visual Studio 2010

Module Overview

The design of a web application plays a key role in its adoption and continued use by its users. Beyond the consideration of having people use your application is the ability to support it quickly and easily, and add new features, when required. Whether providing a consistent design for users or creating an easily supportable product, design should be at the center of consideration when starting a web application project. This module will introduce business scenarios, best practices, and options that are available for the design of web applications. Topics that will be covered include the needs of e-commerce sites vs. other business and information sites, essentials of designing web applications with ASP.NET, such as deciding between Web Forms and Model-View-Controller (MVC), and some of the tools and technologies available using Microsoft Visual Studio 2010 for creating web applications.

Designing a Web Application

2-3

Lesson 1

Web Applications: Case Studies

Web applications come in many varieties and fulfill many needs that may or may not apply directly to achieving the objective. This lesson will discuss the strategies used in different business scenarios, what the unique characteristics of web applications are, and define the process of designing a web application.

Lesson Objectives:
After completing this lesson, you will be able to: Identify major types of web applications. Describe the process of designing a web application. Identify web application design considerations. Describe differences in the design of various types of web applications. Apply guidelines for documenting the design of a web application.

2-4

Developing Web Applications with Microsoft Visual Studio 2010

Discussion: Overview of Web Applications and Their Characteristics

Recognizing similarities between types of web applications will help you quickly understand the audience for whom you are designing a website, and also help you to learn from the lessons of others who have developed web applications over the years. This lesson will cover four different common web application types (e-commerce, blog, news/information, and business/non e-commerce) that you will encounter frequently, and be asked to design. This knowledge will assist you in fitting a web application that you are asked to design into a common mold so that you can quickly recognize the challenges you will face.

E-Commerce Site (Shopping Cart)


All e-commerce sites have key features in common with one another, they are: Ability to search for products Ability to view product details A shopping cart that allows you to store items for purchase and continue shopping Some sort of checkout functionality that allows you to purchase your selected items

Without these key features, an e-commerce site would not be successful. Keep these features in mind when you are asked to design e-commerce sites, and be sure to notice similarities and differences between e-commerce sites when you are shopping on the web. Key considerations for e-commerce sites include: Security: When taking payments and storing sensitive customer information, such as addresses, security is a primary concern. You want your customers to feel secure and trust that you have their best interests at heart when they shop at your site. You can do this by providing secure logon and checkout functionality based on best practices, such as only using security certifications through reputable companies. Ease of managing and introducing new products: Any e-commerce site will have products being introduced, updated, and removed from the site on a regular basis. This functionality needs to be very simple for an administrator to accomplish. Working directly with the people who will administrate the

Designing a Web Application

2-5

site, and learning what their workflow is will help you deliver features that will keep the site running smoothly. Simple workflow from search to checkout, for keeping your customers from leaving for another competitors site: Any distraction from finding and purchasing the products your ecommerce site has to offer is enough to cause a user to leave the site and look elsewhere. Concentrate on making the workflow from selection to purchase as simple and pain-free as possible.

Blog Site
All blog sites have key features in common with one another, they are: Ability to add, edit, manage, and publish posts (articles) Ability to categorize posts for easy searching Ability for readers to comment on published posts Ability for authors to administrate content and comments

A blog would hardly be a blog without these key features. At times, you may be asked to design a web application where a blog is just one feature in a larger picture. Many business and information sites also include blogs as a way to communicate to their readers and customers. A blog web application is very simple at its core. It is a question of the extent to which it is expanded that sets its complexity. Features such as spam protection, tagging, and custom widgets can quickly expand the scope of the project. Key considerations for blog sites include: Rich content editing features for authors and administrators: The easier it is for authors to publish content for a blog site, the more quickly the site will gain readership and become successful. As important as it is to make the site easy for readers, it is more important to make it a good experience for the authors that will be working with the web application the most often. Simple search functionality for readers: It should be simple for readers to find content that interests them. This can be done by categorizing posts (so that readers can quickly find common themes), and by adding tagging (so that readers can quickly find posts on a particular topic). Controls on comments and contributing to keep spam to a minimum: Blog sites invite abuse from spammers if there are not protections set from the beginning. Design the blog to allow for moderation of comments if the administrator sets the option and be sure to give the administrator control to close commenting and delete offending comments if necessary.

News/Information Site
All news/information sites have key features in common with one another, they are: Very dense presentation of content Content provided in column layout Categorization of content so that it is easy to find what you are looking for

A news/information site would not be recognized if it did not have that typical newspaper layout, and provide very dense presentation of content (meaning there is quite a bit more content on the screen than on a typical site). Content is also categorized so that the user can find the information that interests him or her as quickly as possible, such as weather or sports. Key considerations for news/information sites include: Advertising: Typically, news/information sites sell advertising for revenue. Keeping this in mind while designing will allow you to add advertising to the web application without having it look like an afterthought.

2-6

Developing Web Applications with Microsoft Visual Studio 2010

Ability to adapt design to trends quickly: The designs and layouts used in news/information sites change more often than in other sites. The ability to change a design and layout quickly will give you an edge. Rich content editing features for authors and administrators: Just as with blogs sites, content is everything with news/information sites. Authors and administrators need to be able to quickly add, edit, delete, and publish their articles.

Business Site (Non E-commerce)


All business sites have key features in common with one another, they are: Strongly branded designs Designs and content that try to send a message about the business Access to information on the business, and contact information for further questions

Business sites are typically very straightforward and change less often than the other three common web application types. The content is carefully crafted to send the message the organization would like their customers/clients to see. Business sites are typically strongly branded, with emphasis on logos and colors that correlate to the business and the message being broadcast. Key considerations for business sites include: Emphasis on design: From the beginning, emphasis will be on design. Typically, you will work with a marketing group or key executives to form the image of the site being presented. Take the time to understand the business goals and design to meet them. Simple navigation: Typically, business sites are not very dense with information. There are very few pages and links required. As such, keep the navigation as simple as possible. Easy to find contact information: Concentrate on making the information available very easy to find. Make the contact information for the business obvious and not hidden.

Question: What are some further variations on websites that were not covered? Question: While not being an exact fit, do these four types of websites relate to the previous questions answers in some ways?

Designing a Web Application

2-7

Overview of the Web Application Design Process

The design of a web application should address the goals outlined for it, and apply the requirements given to meet those goals. By following a design process, even loosely, you will be much closer to hitting the goals of the web application than if you dive right into building your solution from the start. The design process typically fits within the vision and planning steps of the development process. There isnt necessarily a wrong way to conduct your design process during these two steps, as long as it is before you start building your product. How you conduct the design process during one project may be different in another. Do what feels right, and be sure to do it before you begin building the product. The design process workflow: Identify business goals Determine requirements Create a design specification to support your findings

Identify Business Goals


The first step in a successful design is to solidify the goal you are working towards achieving. This requires you to work with business leaders to determine what it is that the web application should achieve for the organization. Without this knowledge, it is hard to design an application successfully that will meet the needs of the organization.

Determine Requirements
After the goals for the project have been identified, the project team needs to define the requirements that are necessary to meet those goals. The requirements developed during this phase will shape the architecture of the product to a large degree.

2-8

Developing Web Applications with Microsoft Visual Studio 2010

Example: If one of the goals determined for the project is that it must be delivered in a very short timeframe, that would likely lead to architecture and platform decisions that will impact the development of the product.

Create Design Specification


Now that you understand the goal that you are trying to achieve and what is required to achieve it, you are in a position to write a design specification. A design specification should contain all of the information that you have gathered during the design process, and describe it in language that anyone from either the technical or the business teams can understand. Design specifications themselves can be a complex topic, with many opinions on the correct format and language. The correct way to document your design is what works best for your project team and organization. Question: Have you participated in a project that did not fully specify the design of your project as described in this topic? If so, what were the ramifications? What could have been done differently? Question: In your experience, in which activities of the design process did you participate? Do you feel it was beneficial towards your understanding of the goals and requirements of the solution?

Designing a Web Application

2-9

Lesson 2

Web Application Design Essentials

Each web application has a focus that leans towards one of the common types covered in Lesson 1. The common types each have design considerations that should be well covered during the first two steps of the design process (understanding business goals and determining requirements). Understanding the considerations that are common to each type will assist you in speeding up the design process itself, while not missing requirements that may be key for a type of web application. Understanding each of the considerations for these web application types will also assist you in deciding on which ASP.NET framework to build your web application. Web Forms and MVC both have strengths and weaknesses that may fit well with a given business scenario and web application type. Making the right decision between these frameworks for a particular web application type can save you time during your development process.

Lesson Objectives:
After completing this lesson, you will be able to: Identify common design considerations for each of the website types covered in Lesson 1. Identify the key differences between Web Forms and MVC. Apply guidelines for determining when to use Web Forms and MVC. Identify factors to be considered when using Web Forms with MVC.

2-10

Developing Web Applications with Microsoft Visual Studio 2010

Common Design Considerations

During the design process of your web application, the following considerations are likely to play a role in the design decisions that you make. The type of web application that you are designing determines the importance of each consideration. The five considerations are: Security Scalability and reliability (availability) Search Engine Optimization (SEO) Localization Accessibility

Security
Security is the level of importance and effort you are willing to put toward securing data and the administration features of your application. Every web application will require some level of security. Some web application types require much more focus on this consideration, such as e-commerce sites, where sensitive information may be stored. Importance of consideration by web application type (highest importance listed first): E-commerce News/Information Business/Non E-commerce Blog

Designing a Web Application

2-11

Scalability and Reliability (Availability)


Scalability is concerned with the ability of your web application to scale when demand requires more resources. Reliability is concerned with the ability of your web application to survive resource outages, such as a single server failure. Often scalability and reliability are closely linked, as the ability to recover from the loss of resources requires the ability of your web application to spread its processing across more than one single point of failure. Importance of consideration by web application type: News/Information E-Commerce Blog Business/Non E-Commerce

More information on the subject of scalability and reliability as it relates to web applications can be found in the documentation for IIS (Internet Information Server) and Microsoft SQL Server. Both of these platforms provide built-in scalability and reliability services.

Search Engine Optimization (SEO)


SEO is concerned with the ease with which automated search engine crawlers can traverse your site. Automated search engine crawlers follow links that are available in your site and save key information about the content of your site on each page. This information is stored and is searchable by users who are interested in the topics that your site may cover. Automated search engine crawlers can be very picky about the layout of your site, and the way that you place content. If you do not follow the standards and norms of web application design, you may find that search engines are not indexing your site as efficiently as they might, leading to fewer visitors through keyword searches. Importance of consideration by web application type: News/Information E-Commerce Blog Business/Non E-Commerce

Each search engine provides documentation on the standards and practices that lead to optimal indexing for that search engine.

Localization
Localization is concerned with providing your content to your users in multiple languages. Providing your content in several languages can expand your potential user base dramatically. Importance of consideration by web application type: E-Commerce Business/Non E-Commerce

2-12

Developing Web Applications with Microsoft Visual Studio 2010

News/Information Blog

For more information on localization options in ASP.NET solutions, see the ASP.NET Globalization and Localization page on MSDN at http://go.microsoft.com/fwlink/?LinkID=203984&clcid=0x409.

Accessibility
Accessibility is concerned with providing interfaces that allow disabled individuals the opportunity to use your web application. Accessibility is typically much easier to include in your solution if it is added as a requirement from the inception of the project, rather than attempting to add it later. As the web becomes a more pervasive and important medium to all people, accessibility becomes more important so that everyone has an opportunity to participate on the web. Importance of consideration by web application type: E-Commerce Business/Non E-Commerce News/Information Blog

For more information on considering accessibility in your design, see the Evaluating Web Sites for Accessibility page from the WC3, at http://go.microsoft.com/fwlink/?LinkID=203953&clcid=0x409. Question: How does security play a role in every type of web application? Question: How do scalability and reliability relate to one another?

Designing a Web Application

2-13

Discussion: Web Forms and MVC

Successful web applications can be built on both Web Forms and MVC. Web Forms and MVC have different approaches on the design and development of your web application. Web Forms and MVC share similarities, given that they are both built on top of ASP.NET. Their differences are in how they approach separating concerns and delivering content when requested. Web Forms attempts to model the life cycle of desktop applications by maintaining state across web pages and user activity. MVC stays with the stateless model of web applications and separates concerns through the model-view-controller pattern.

Web Forms
Built on top of ASP.NET Supports rapid application development (RAD) Supports Drag-and-drop development HTML generated by the controls Event driven Only one form element Supports client side settings storage (viewstate) Hard to test

Web Forms are designed for rapid application development (RAD), using controls. These controls define code that runs on the server and generates HTML that the clients browser can render. The key benefits offered by Web Forms are the separation of HTML interface design from application logic, a large suite of server-side controls, and rich data binding.

2-14

Developing Web Applications with Microsoft Visual Studio 2010

Web Forms will be immediately familiar to anyone who has developed Windows Forms applications. It is designed to be event-driven and to maintain the state of the session through the stateless medium of the web. Some of the key features in Web Forms are seen as both an asset and a deficit. The concept of viewstate provided by Web Forms allows you to maintain a clients state throughout the clients entire session with the application. This feature can be very powerful, but also can be very taxing on resources, and goes against the grain of the typical paradigm of web development as a stateless platform. Combining the concept of viewstate with server-side controls and postback behavior leads to a framework that is very hard to test. Those who are interested in TDD (Test-Driven Development) will not find Web Forms to be TDD friendly.

MVC
Built on top of ASP.NET Complete control over the generated HTML Separation of concerns (Model-View-Controller) Easy to test No postback or viewstate

MVC takes a different approach to web development than Web Forms. The acronym MVC stands for model-view-controller. MVC is a pattern that can be extended to more than just web application development. It is a solid pattern for any application architecture that seeks to separate the concerns involved in presentation, logic, and data manipulation. With MVC, there is no concept of viewstate and postback. You also have complete control over your presentation, which can be both a blessing and a curse for some developers. Along with the concept of separation of concern that is built into the MVC pattern, ASP.NET MVC is also very testable right out of the box. For a team that is interested in practicing TDD, they will find MVC to be very friendly. Question: What features, common or different, do you see in both the Web Forms and MVC frameworks that would benefit your development efforts?

Designing a Web Application

2-15

Guidelines for Determining When to Use Web Forms and When to Use MVC

There are several considerations that you need to keep in mind when deciding between Web Forms and MVC for your project, such as product domain, business requirements, and personal preference. Different scenarios may lead you towards one choice over the other. Ultimately, very successful applications have been written on both platforms. You cannot go wrong, but you might find that one suits you and your situation better than the other does.

Guidelines
You can use the following considerations as guidelines for choosing between Web Forms and MVC: Internet vs. intranet: If you are working on a web application that will be available strictly over the intranet, many of the considerations that lend themselves towards MVC will not be as important. Considerations such as search engine optimization (SEO), localization, and accessibility will be less important with a typical intranet web application. In this scenario, the strengths of Web Forms, such as rapid application development (RAD) and the large library of available server controls, may be the deciding factor. Control over markup: MVC gives you strict control over your markup. Depending on how important SEO is as a consideration for your web application, MVC may be the best option for you if strict control over markup is a priority. Web Forms abstracts much of the markup that will be generated with server controls that create the markup for you, so that you do not have to. Familiarity with patterns: MVC strictly utilizes the model-view-controller pattern. Web Forms allows you to use many patterns to separate concerns, such as MVP, model-view-presenter. You have many more options using Web Forms in deciding the patterns you will use to separate business logic, data access, and presentation from one another. Depending on your level of comfort with the MVC pattern, you may choose MVC or Web Forms based on your familiarity. RAD: Web Forms was written with RAD (rapid application development) in mind. If you are facing very tight schedules, it may be the framework of choice given your scenario. While those that are comfortable with the MVC pattern will quickly develop quality solutions, it is hard to compete with

2-16

Developing Web Applications with Microsoft Visual Studio 2010

the vast library of available server-side controls available for Web Forms where the rendered HTML is done for you. Personal preference: For developers who are familiar with Windows Forms development, Web Forms will be much easier to use. Web Forms were developed with the Windows Forms developer in mind. Web Forms allows them to transition easily to the web, working in the same paradigm. Other developers that are new to ASP.NET may be more familiar with the concepts of the MVC pattern. Familiarity with the pattern you are working with can be a strong incentive in deciding between Web Forms and MVC. A successful design can be created using Web Forms or MVC; your level of comfort with the pattern implemented is a strong factor when deciding which framework to use.

Question: What solutions in your experience may have benefited from implementation using MVC? Question: What key features of Web Forms that you use frequently might you miss when developing with MVC?

Designing a Web Application

2-17

Considerations for Using Web Forms with MVC

Although there are some specific features of Web Forms that are not compatible with MVC, some features are of ASP.NET are fully compatible with both Web Forms and MVC. This topic will review some of the key features of ASP.NET that are compatible with both Web Forms and MVC and the common features of Web Forms that are incompatible with MVC. Understanding these differences will help you determine the correct course of action when converting Web Form functionality to MVC.

Compatible Features
Many features are shared among both Web Forms and MVC. The following highlights the more common compatible features. Membership: ASP.NET Membership allows you to configure security quickly for your web application. Authentication: ASP.NET Forms Authentication allows you to configure user logon/logoff quickly. Roles: ASP.NET Roles allows you to couple the membership and authentication features with the ability to add authorization functionality to your application. Configuration: ASP.NET configuration features, such as Application Settings and Connection Strings allow you to store static information that your application uses in an XML configuration that is easily accessible throughout your application.

Incompatible Features
Some features are handled differently between Web Forms and MVC. The following sections highlight the more common features, and explain how those features differ from one another. Server-side controls (GridView, Repeater, DataList, and so on): Server side controls, such as GridView, are not compatible with MVC. The functionality that these controls rely on is not available in MVC, such as postback and viewstate. Viewstate: Viewstate as a concept is not present in MVC. MVC provides a stateless model of interaction between the client and server.

2-18

Developing Web Applications with Microsoft Visual Studio 2010

Page Event life cycle: Without the concept of viewstate, MVC also does not implement the Page Event life cycle as it exists in Web Forms. No Page_Load events can be used to process and manipulate the page or data involved. This functionality is handled in the controller in the MVC paradigm.

Designing a Web Application

2-19

Lesson 3

Visual Studio 2010 Tools and Technologies for Web Application Design

Microsoft provides several tools and technologies that assist taking the design specification that you create and implementing it in your web application. These tools include design tools built into Visual Studio 2010 and the IIS SEO Toolkit. The Enterprise Library is a collection of reusable software components called application blocks. Each block is designed to assist you with common development challenges.

Lesson Objectives:
After completing this lesson, you will be able to: Describe the design tools available in Visual Studio 2010. Describe what the Enterprise Library is. Describe the key blocks of the Enterprise Library. Describe what the IIS SEO Toolkit is.

2-20

Developing Web Applications with Microsoft Visual Studio 2010

Overview of the Design View in Visual Studio 2010

Visual Studio 2010 provides a Design view of the pages of your web application that shows you what your page will look like as you implement your design. The design view shows you any master pages and nested master pages that are implemented in your page, so that you see exactly what you would see when you view the page in a browser. In the Design view, each control has a button attached that allows you to configure that control further. The image on the slide shows you this functionality for a ListBox control. The Toolbox window allows you to drag and drop controls into your design. Simply select the control that you want to place in your page and drag it to where you want the control to be placed in the page. Except for very simple pages, you will use a combination of the Source and Design views to implement your design specification for a page. The Source view gives you direct access to the markup for the page (HTML, CSS, JavaScript), and the Design view gives you a rendered view of your page as you create it. You can select the view to display from the menu on the bottom of the screen, as shown in the following image.

Question: What value does the Design view bring to your development process?

Designing a Web Application

2-21

Enterprise Library

The Enterprise Library is a collection of reusable components (application blocks), which provide developers with solutions for commonly needed functionality in an application. Functionality such as encryption, logging, exception handling, and data access is addressed in the Enterprise Library. The implementation of each application block in the library is built on Microsofts proven best practices for .NET application development. The blocks are available to use as is, or to extend for custom implementations to meet your specific needs.

Key Blocks of the Enterprise Library


Cryptography application block: The Cryptography application block includes features that simplify the implementation of typical cryptographic functions in your applications. Functions such as encryption, hashing, and comparing hash values for validation are all included in the library. Data Access application block: The Data Access application block provides features that simplify accessing and manipulating data. Tasks such as connection management and caching parameters are built into the library, as well as reading data from a data source and passing data through an application layer. You can execute stored procedures using built-in functionality, as well as write inline SQL to query your data source directly. Exception Handling application block:The Exception Handling application block assists with the always-present chore of handling exceptions through a uniform strategy for processing exceptions throughout all layers of your architecture. Using this application block, you can create exceptionhandling policies that are defined and maintained at an administrative level, so that support and changing of these policies can be accomplished without changing application block code. Logging application block: The Logging application block provides common logging functions. Using this application block, you can write to a number of locations, including an email message, the event log, a database, a message queue, a text file, and custom locations that you define. You can specify consistent logging throughout your application, to many destinations, using a common interface. Configuration of the logging application block can be accomplished using a custom

2-22

Developing Web Applications with Microsoft Visual Studio 2010

configuration interface available in Visual Studio that makes it very easy to customize logging for your needs. Question: What benefits can you see to using the Enterprise Library as a consistent interface for common tasks that your applications require?

Designing a Web Application

2-23

IIS SEO Toolkit

Search Engine Optimization (SEO) is the act of optimizing your web applications markup (HTML) so that search engines can index it easily and properly. A significant portion of your sites traffic can be driven through searches, and implementing proper SEO allows the information that you want available to your audience to be properly indexed for searching through a search engine. When your site is indexed properly, every available result that should be shown for your site for a given keyword is available.

Robots.txt and Sitemap.xml Files


The IIS SEO Toolkit provides features for creating and configuring robots.txt and sitemap.xml files for your site. Robots.txt is a file that sits in your sites root folder that every search engine uses to direct their indexing. The robots.txt file tells a search engine what it can and cannot crawl when indexing your site. Properly configuring your robots.txt file will ensure that the information that you want to be indexed will be indexed by search engines. The Sitemap.xml file provides a map of your site for a search engine crawler. This allows the crawler to access areas of your site that it might not have without the sitemap. Properly configuring a sitemap.xml file ensures that the search engines crawler will index your entire site.

Site Analysis
The Site Analysis feature crawls your site as if it were a search engine crawler, and then reports on issues that it found in the files and markup contained in your site. By running the Site Analysis tool, you will find and correct potential issues that will stop a search engine crawler from properly attributing relevance to your content and possibly halting the indexing of your site altogether. Question: What value do the robots.txt and sitemap.xml files provide? Question: How does the Site Analysis tool help you understand how a search engine crawler will react to the content of your site?

2-24

Developing Web Applications with Microsoft Visual Studio 2010

Lab 2: Redesigning the Adventure Works Website

Note: Tasks in this lab will be the same regardless of the programming language your solution is using.

Objectives:
After completing this lab, you will be able to: Draw diagrams showing the overall architecture and page flow of the Adventure Works website. Identify which pages of the website will use Web Forms, and which pages will use MVC, based on business requirements. Add MVC capabilities to the existing website.

Introduction
In this lab, you will first capture your understanding of the current Adventure Works website by diagramming its overall architecture and page flow. You will then review the business requirements set by management, and recommend which pages of the website will use Web Forms, and which pages will use MVC. You will also do the groundwork necessary for adding MVC capabilities to the existing website so that you can get started as soon as Management approval comes through.

Designing a Web Application

2-25

Lab Scenario

Now that you have a better understanding of Web Forms and MVC, you can see the benefits of using MVC to develop some pages of the Adventure Works website. Your next task is to create a proposal detailing recommendations for redesigning the website. Your proposal needs to describe the structure of the current website and recommend an appropriate programming model for developing the pages of the redesigned website. Keep in mind that you are operating on a tight budget, so you need to consider the costs and benefits of your decisions before making recommendations. The proposal should also enumerate the rationale underlying your recommendations to help management assess them.

2-26

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 1: Reviewing the Adventure Works Website Structure


The main tasks for this exercise are as follows: Open the AdventureWorks solution in Visual Studio 2010. Examine the code and markup location and purpose. Draw a diagram showing the overall architecture. Draw a diagram showing the page flow. Discuss your findings with the class.

Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. 2. 3. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution at the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 02\Solution\Exercise 01 D:\Lab Files\VB\Lab 02\Solution\Exercise 01

Task 2: Examine the code and markup location and purpose


Analyze the solution and determine its intent and structure.

Task 3: Draw a diagram showing the overall architecture


On a sheet of paper, draw a diagram describing the overall Adventure Works website architecture, based on your analysis.

Task 4: Draw a diagram showing the page flow


On a sheet of paper, draw a diagram showing the page flow of the AdventureWorks web application, based on your analysis.

Task 5: Discuss your findings with the class


Discuss the diagrams created amongst the class.

Results: After completing this exercise, you should have created two diagrams describing the existing architecture and page flow of the AdventureWorks web application.

Designing a Web Application

2-27

Exercise 2: Redesigning the Adventure Works Website


The main tasks for this exercise are as follows: Read the requirements document. Determine which pages will use Web Forms and which will use MVC. Discuss your recommendations and their rationale with the class.

Task 1: Read the requirements document


The redesigned AdventureWorks web application must meet the requirements as set by management and listed in the following sections.

Business Requirements and Considerations


Build a responsive, rich, and interactive UI Enhance the performance of existing pages and resolve errors Use URLs that are search engine friendly and facilitate indexing of products by search engines Include a section for blogs Include an administration section to enable the Sales team to manage information stored in the database Secure the blog management pages and the administration section

Functional Requirements: Shopping Cart


List product categories Click a category to display products Display products in a detailed view Add products to the shopping cart Remove products from the shopping cart Submit the shopping cart

Functional Requirements: Blogs


Log on to the website Add a new blog entry Edit and delete blog entries Add anonymous comments Approve comments

Functional Requirements: Administration Section


Log on to the website Manage products Manage product categories Manage sales order headers Manage customers User Interface Requirements

2-28

Developing Web Applications with Microsoft Visual Studio 2010

Display a welcome message on the home page in English or French (Canada) Minimize page refreshes Provide support for easily changing the overall look of the application Reflect the corporate branding and propose two styles based on the corporate colors Display a marketing message on the Product Detail page Display a product advertisement on the blog pages Display a ticker showing biking-related news headlines on the blog pages

Task 2: Determine which pages will use Web Forms and which will use MVC
Based on the requirements given, determine and document which pages will remain Web Forms pages and which will be implemented in MVC.

Task 3: Discuss your recommendations and their rationale with the class
Discuss the recommendations created with the class.

Results: After completing this exercise, you should have reviewed the requirements document for the Adventure Works website, determined which pages will remain Web Forms pages and which will use MVC, and discussed your recommendations and their rationale with the class.

Designing a Web Application

2-29

Exercise 3: Adding MVC Capabilities to the Adventure Works Website


The main tasks for this exercise are as follows: Open the AdventureWorks solution in Visual Studio 2010. Add required assemblies to the project. Add the MVC Assembly references and namespaces to the Web.config file. Map the default MVC request routes. Change project to reflect an MVC Project.

Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution at the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 02\Starter\Exercise 03 D:\Lab Files\VB\Lab 02\Starter\Exercise 03

Task 2: Add required assemblies to the project


1. 2. Add references to the System.Web.Abstractions assembly to the project. Add references to the System.Web.MVC and System.Web.Routing assemblies to the project.

Task 3: Add the MVC Assembly references and namespaces to the Web.config file
1. 2. Open the Web.config file in the root AdventureWorks folder. Add the following text to your Web.config file in their proper sections as shown, this adds the appropriate assemblies to your project and configures special MVC handlers:
<system.web> <compilation debug="true" targetFramework="4.0"> <assemblies> ... <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </assemblies> </compilation> ... <pages> <namespaces> <add namespace="System.Web.Mvc"/> <add namespace="System.Web.Mvc.Ajax"/> <add namespace="System.Web.Mvc.Html"/> <add namespace="System.Web.Routing"/> </namespaces> </pages> <httpHandlers> <add verb="*" path="*.mvc" validate="false" type="System.Web.Mvc.MvcHttpHandler"/> </httpHandlers> </system.web> <system.webServer> ...

2-30

Developing Web Applications with Microsoft Visual Studio 2010

<handlers> <remove name="MvcHttpHandler"/> <add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler"/> </handlers> </system.webServer> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31BF3856AD364E35"/> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/> </dependentAssembly> </assemblyBinding> </runtime>

3.

Save the Web.config file.


[Visual C#] <?xml version="1.0"?> <configuration> <appSettings /> <connectionStrings> <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" /> <add name="AdventureWorksEntities" connectionString="metadata=res://*/mdlAdventureWorks.csdl|res://*/mdlAdventureWorks.ss dl|res://*/mdlAdventureWorks.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\sqlexpress;Initial Catalog=AdventureWorksLT2008R2;Integrated Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" /> </connectionStrings> <system.web> <compilation debug="true" targetFramework="4.0"> <assemblies> <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </assemblies> </compilation> <authentication mode="Forms"> <forms loginUrl="~/Account/Login.aspx" timeout="2880" /> </authentication> <membership> <providers> <clear /> <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" /> </providers> </membership> <profile>

The final Web.config file should appear as follows

Designing a Web Application

2-31

<providers> <clear /> <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" /> </providers> </profile> <roleManager enabled="false"> <providers> <clear /> <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" /> <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" /> </providers> </roleManager> <pages> <namespaces> <add namespace="System.Web.Mvc"/> <add namespace="System.Web.Mvc.Ajax"/> <add namespace="System.Web.Mvc.Html"/> <add namespace="System.Web.Routing"/> </namespaces> </pages> <httpHandlers> <add verb="*" path="*.mvc" validate="false" type="System.Web.Mvc.MvcHttpHandler"/> </httpHandlers> </system.web> <system.webServer> <modules runAllManagedModulesForAllRequests="true" /> <handlers> <remove name="MvcHttpHandler"/> <add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler"/> </handlers> </system.webServer> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31BF3856AD364E35"/> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/> </dependentAssembly> </assemblyBinding> </runtime> </configuration> [Visual Basic] <?xml version="1.0" encoding="utf-8"?> <!-For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <connectionStrings> <add name="ApplicationServices" connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true" providerName="System.Data.SqlClient" /> <add name="AdventureWorksEntities" connectionString="metadata=res://*/mdlAdventureWorks.csdl|res://*/mdlAdventureWorks.ss dl|res://*/mdlAdventureWorks.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=.\sqlexpress;Initial Catalog=AdventureWorksLT2008R2;Integrated

2-32

Developing Web Applications with Microsoft Visual Studio 2010

Security=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" /> </connectionStrings> <system.web> <compilation debug="true" strict="false" explicit="true" targetFramework="4.0"> <assemblies> <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /> <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> </assemblies> </compilation> <authentication mode="Forms"> <forms loginUrl="~/Account/Login.aspx" timeout="2880" /> </authentication> <membership> <providers> <clear /> <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10" applicationName="/" /> </providers> </membership> <profile> <providers> <clear /> <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/" /> </providers> </profile> <roleManager enabled="false"> <providers> <clear /> <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" /> <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" /> </providers> </roleManager> <pages> <namespaces> <add namespace="System.Web.Mvc"/> <add namespace="System.Web.Mvc.Ajax"/> <add namespace="System.Web.Mvc.Html"/> <add namespace="System.Web.Routing"/> </namespaces> </pages> <httpHandlers> <add verb="*" path=".mvc" validate="false" type="System.Web.Mvc.MvcHttpHandler"/> </httpHandlers> </system.web> <system.webServer> <modules runAllManagedModulesForAllRequests="true" /> <handlers>

Designing a Web Application

2-33

<remove name="MvcHttpHandler"/> <add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path=".mvc" type="System.Web.Mvc.MvcHttpHandler"/> </handlers> </system.webServer> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Web.Mvc" PublicKeyToken="31BF3856AD364E35"/> <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0"/> </dependentAssembly> </assemblyBinding> </runtime> </configuration>

Task 4: Map the default MVC request routes


1. Import the System.Web.Mvc and System.Web.Routing namespaces in Global.asax to support MVC request routing.
[Visual C#] using System.Web.Mvc; using System.Web.Routing; [Visual Basic] Imports System.Web.Mvc Imports System.Web.Routing

2.

Create a method named RegisterRoutes to register the MVC routes and exclude routes for existing Web Form pages, handlers, and WCF services.
[Visual C#] public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.IgnoreRoute("{resource}.aspx/{*pathInfo}"); routes.IgnoreRoute("{resource}.svc/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = "" } );

// Parameter defaults

[Visual Basic] Shared Sub RegisterRoutes(ByVal routes As RouteCollection) routes.IgnoreRoute("{resource}.axd/{*pathInfo}") routes.IgnoreRoute("{resource}.aspx/{*pathInfo}") routes.IgnoreRoute("{resource}.svc/{*pathInfo}") routes.MapRoute( "Default", "{controller}/{action}/{id}", New With {.controller = "Home", .action = "Index", .id = ""} ) End Sub

3.

Call the RegisterRoutes in the Application_Start method.


[Visual C#] protected void Application_Start(object sender, EventArgs e) {

2-34

Developing Web Applications with Microsoft Visual Studio 2010

RegisterRoutes(RouteTable.Routes);

[Visual Basic] Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) RegisterRoutes(RouteTable.Routes) End Sub

4.

Save the Global.asax file.

Task 5: Change project to reflect an MVC Project


1. 2. Open the project, AdventureWorks.csproj or AdventureWorks.vbproj file in Notepad for direct editing. Locate the ProjectTypeGuids element.
[Visual C#] <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b00c04f79efbc}</ProjectTypeGuids> [Visual Basic] <ProjectTypeGuids{349c5851-65df-11da-9384-00065b846f21};{F184B08F-C81C-45F6-A57F5ABD9991F28F}</ProjectTypeGuids>

3.

Add the following markup at the beginning of the ProjectTypeGuids element.


{F85E285D-A4E0-4152-9332-AB1D724D3325};

Note: The top of the project file should look like this.
[Visual C#] <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> ... <ProjectGuid>{A8D6241C-680E-42BA-884B-501CC08D3FA9}</ProjectGuid> <ProjectTypeGuids>{F85E285D-A4E0-4152-9332-AB1D724D3325};{349c5851-65df-11da-938400065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids> ... [Visual Basic] <?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> ... <ProjectGuid>{F9BE0786-D923-4DF0-9483-CE13D5D26A1F}</ProjectGuid> <ProjectTypeGuids>{F85E285D-A4E0-4152-9332-AB1D724D3325{349c5851-65df-11da-938400065b846f21};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}</ProjectTypeGuids> ...

4. 5. 6. 7.

Save the project file. Reload the AdventureWorks project. Test the new project type by opening the Add New Item dialog box. Close Visual Studio 2010.

Designing a Web Application

2-35

Task 6: Turn off the virtual machine and revert the changes
1. 2. 3. 4. In Microsoft Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert. In the Revert Virtual Machine dialog box, click Revert.

Results: After completing this exercise, you should have reviewed and documented the existing AdventureWorks Web Forms application architecture and page flow, reviewed requirements documentation and created a plan for redesigning the AdventureWorks application using MVC where it made sense, and added MVC functionality to the existing AdventureWorks application.

2-36

Developing Web Applications with Microsoft Visual Studio 2010

Lab Review

Designing a Web Application

2-37

Module Review and Takeaways

Review Questions
1. 2. 3. 4. 5. 6. 7. What are the stages of the application development process? What value is there in identifying business goals during the design process? How do design considerations factor into your decision to use Web Forms or MVC? What similarities do Web Forms and MVC share? What are some key differences between Web Forms and MVC? Which business scenarios fit well with each framework? What value is there in adding MVC functionality to an existing Web Forms application?

Real-world Issues and Scenarios


1. 2. 3. Your organization maintains that each solution must adapt to a level of code-coverage in its unit tests. Which framework would be the best choice in this scenario? Your organization has determined that search engine optimization needs to be addressed in an existing Web Forms application. What are your options? You are assigned to a new project that requires full accessibility according to standards, which requires strict control of the applications-generated HTML. What is the best architecture for this solution?

2-38

Developing Web Applications with Microsoft Visual Studio 2010

Developing MVC Models

3-1

Module 3
Developing MVC Models
Contents:
Lesson 1: Exploring Ways to Create MVC Models Lesson 2: Working with Data in MVC Models Lesson 3: Creating a Data Repository Lab 3: Creating MVC Models 3-3 3-10 3-16 3-30

3-2

Developing Web Applications with Microsoft Visual Studio 2010

Module Overview

The ASP.NET MVC Framework is Microsofts latest web development framework, built on top of the model-view-controller (MVC) pattern. Based on ASP.NET, it allows the developer to control all aspects of the life cycle of a request. The goal of this module is to cover the model part of the equation. Model represents the domain of the application. Model can be represented in many different ways. In this module, you will learn how to create MVC models using manual classes, LINQ to SQL, and the Entity Framework.

Developing MVC Models

3-3

Lesson 1

Exploring Ways to Create MVC Models

MVC model allows you to represent the domain of the application. MVC models can be created in variety of different ways. Creating an MVC model manually allows the most flexibility, as the developer can choose any approach. However, this flexibility comes with a cost of implementing more code. Microsoft introduced LINQ to SQL object-relational mapper, which maps the database tables to the corresponding classes. LINQ to SQL allows the developer to use designer tools to ease the creation of the classes. LINQ to SQL provided the data source first approach, which means that the database needs to be created before the domain of the application. This later changed when Microsoft introduced the Entity Framework. The Entity Framework, like LINQ to SQL, allows the developers to map their database tables to classes. The Entity Framework also allows the developer to create domain first applications in addition to the data first applications.

Lesson Objectives:
After completing this lesson, you will be able to: Identify different options for creating MVC models. Implement an MVC model manually.

3-4

Developing Web Applications with Microsoft Visual Studio 2010

Overview of MVC

The ASP.NET MVC Framework is an architecture for developing web applications that implements the model-view-controller pattern. Model: Used to manage data or information and notify other elements in the framework when that data changes. View: Represents the User Interface. Controller: The components that handle user interaction, work with models, and select a view to render the UI.

Developing MVC Models

3-5

What is an MVC Model?

The purpose of the MVC model is to represent the domain of the application. It is the responsibility of the model to represent the data as information. Each application has a different model that depends on the domain of the application. The model can be used as a data container to display the information on the web page, although in complex applications, the functionality of the data container can easily be delegated to a ViewModel object. This topic explains how to create models using different approaches.

Purpose of the model in MVC framework


In the MVC framework, a model represents the domain logic of the application. The purpose of the domain is to add meaning to the raw data. The model adds business rules to the application that orchestrate how the application should work. An MVC model does not reflect the data access layer of the application, but resembles the business aspect that makes the application useful.

Various ways of creating MVC models


An MVC model can be implemented in many different ways. An MVC model can be created using simple entity classes. These classes can be handcrafted, or they can be generated by an object-relational mapping tool. By using an object-relational mapping tool, our database tables can be mapped to the classes. This cuts down the amount of work a developer has to do to create model classes.

3-6

Developing Web Applications with Microsoft Visual Studio 2010

Creating an MVC Model

Creating MVC models manually gives the most flexibility to dictate the model, but it ends up being a lot of work since the mapping between the model and the database schema must be hand coded. You must follow the active record pattern, mapping each database table name to the class, and each column in the table to the field in the class. Manually implementing MVC models also makes it difficult to create parentchild relationshipsyou must handle the nested relationships manually, which means when the parent is persisted, you must also persist the children automatically. Another task that needs to be considered when implementing MVC models manually is the dirty tracking (for example, if you have a list of 1,000 objects how will you find out which ones have changed?). In the end, the manual implementation does provide freedom of implementation, but it comes with a high cost of implementing all the details yourself. LINQ to SQL allows you to generate the model classes by using a visual designer tool. LINQ to SQL uses the active record pattern behind the scenes to map the table name to a class and the column names to the fields of the class. This is all performed by using the LINQ to SQL designer, or by decorating the classes with attributes. The designer approach is more applicable since it allows the developer to simply drag and drop the table from the server explorer to the designer surface, and then create the necessary mappings automatically. LINQ to SQL also creates the relationships between the tables, which can also be accessed using the entity classes. LINQ to SQL uses the DataContext object, which is responsible for keeping track of all the entities used in the current session. Unfortunately, LINQ to SQL does not support many-to-many relationships. Although there are few workarounds to fix that problem, they are all cumbersome to implement. The Entity Framework is the latest object-relational mapper introduced by Microsoft. The Entity Framework exposes the same concepts as LINQ to SQL, but extends the functionality in many areas. The Entity Framework designer allows updating the schema without having to drag and drop the tables again to the surface. The Entity Framework supports many-to-many relationships, which arent supported by LINQ to SQL. The Entity Framework also allows the model first approach, which enables the developer to write the model first, and then create the database tables based on the models.

Developing MVC Models

3-7

Creating MVC Models by Using Classes

By creating an MVC model using classes, the developer is in charge of mapping the database schema to the model correctly. The preceding model represents a Blog class that contains two properties: Title and Description. By creating a model manually, the developer is responsible for keeping track of changes, which ends up being a very complicated task. By implementing the MVC model manually, the developer needs to follow the active record pattern to map the table name to the class name, and the table column name to the field name inside the class.

3-8

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Creating an MVC Model by Using Classes

The topic explains how to implement model by using standard Visual C# and Visual Basic classes. The main purpose of the topic is to show that MVC models can be created easily by using plain classes instead of leveraging the power of the object-relational mapper.

Creating an MVC Model Using Classes


1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Create a new ASP.NET MVC 2 Web Application project, with an associated Unit Test project. a. b. In the Start Page Microsoft Visual Studio window, on the File menu, click New Project, or press CTRL+SHIFT+N. In the New Project dialog box, in the left pane, click Visual C# or Visual Basic, in the middle pane, click ASP.NET MVC 2 Web Application, in the Location box, type D:\Demofiles\CS or D:\Demofiles\VB, and then click OK. In the Create Unit Test Project dialog box, ensure the Yes, create a unit test project check box is selected, and then click OK.

c. 3.

Add a new class named Blog to the Models folder. a. b. In Solution Explorer, right-click Models, point to Add and then click New Item, or press CTRL+SHIFT+A. In the Add New Item MvcApplication1 dialog box, in the left pane, click Visual C# or Visual Basic, in the middle pane, click Class, in the Name box, type Blog, and then click Add.

4.

Add the following code to the Blog class.


[Visual C#] public class Blog {

Developing MVC Models

3-9

public string Title { get; set; } public string Description { get; set; }

[Visual Basic] Public Class Blog Private Property Title As String Private Property Description As String End Class

5.

Build the solution, and fix any errors. In the MvcApplication1 Microsoft Visual Studio window, on the Build menu, click Build Solution, or press CTRL+SHIFT+B.

6.

Close Visual Studio 2010. In the MvcApplication1 Microsoft Visual Studio window, click the Close button.

Best Practices: Model should not be concerned about saving itself to the persistent medium, and the data access responsibility should be kept separate from the model.

3-10

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 2

Working with Data in MVC Models

The Model represents the data in the MVC application. There are many methods to handle data within MVC.

Developing MVC Models

3-11

What is LINQ to SQL?

LINQ to SQL is an object-relational mapper created by Microsoft. It leverages the LINQ to Objects support to access the database. The DataContext object of LINQ to SQL is the heart of this technology, which keeps track of all the model objects. The LINQ to SQL technology is based on the Active Record Pattern, which maps the database table name to the class name, and the column name to the class field. LINQ to SQL supports one-to-one and one-to-many relationships. Many-to-many relationship is not supported by default in LINQ to SQL.

3-12

Developing Web Applications with Microsoft Visual Studio 2010

Active Record Pattern

The Active Record Pattern represents a software engineering pattern where the columns of the data source are mapped into the fields of the model object and the table is mapped into a model class. Almost all object-relational mapping tools, including LINQ to SQL and the Entity Framework, use the active record pattern behind the scenes. If you are building an object-relational mapping tool, you should learn the active record pattern. In the following diagram, the Person is a model object.

The fields lastName, firstName, and numberOfDependents are the names of the columns in the database table Persons. The Person class also exposes a couple of methods, including insert and update. It is important to point out that the Person class is not responsible for persisting its state to a data source. The insert method should delegate the work to the appropriate data access interface, which should take action to persist the Person model object into the permanent storage.

Developing MVC Models

3-13

What is the Entity Framework?

The Entity Framework is another Microsoft object-relational tool, which will supersede LINQ to SQL. The main focus of the Entity framework is on the entities rather than the database tables. The Entity framework allows the user to develop the model in different ways. The user can leverage the use of tables and generate the model classes automatically. The mapping between the entity class and the database is performed by using the Active Record Pattern. The user can also create all the classes and relationships before creating the database tables. This is called the model first approach, and it is the default technique when building a domain-centric application. Just like LINQ to SQL, the Entity Framework supports one-toone and one-to-many relationships. In addition, the Entity Framework supports the many-to-many relationship by default, unlike LINQ to SQL. The Entity Framework Visual Designer has been improved as well, and changes made to the database can be easily updated in the designer by using the Refresh Schema feature.

3-14

Developing Web Applications with Microsoft Visual Studio 2010

LINQ to SQL vs. Entity Framework

LINQ to SQL is the Microsoft implementation of the object-relational mapper. LINQ to SQL allows the developer to use the designer to map database tables to classes. This mapping is performed by using the Active Record Pattern. LINQ to SQL also supports entity tracking, which enables the developer to find the altered entities. When you have a large schema, you should use LINQ to SQL instead of manually creating classes. LINQ to SQL also provides the support for deferred query execution, which means the query is only executed when data is accessed. The Entity Framework is Microsofts latest release of an object-relational mapping tool. The Entity Framework supersedes LINQ to SQL technology, as it supports many-to-many relationships and allows the developers to build model-first applications. The Entity Framework also includes a designer that makes it easy to map relationships between tables and classes. It also supports object state tracking, which means modified objects can easily be tracked and updated.

Developing MVC Models

3-15

Data Mapper Pattern

The Data Mapper Pattern is a software design pattern that allows the separation of concerns. The main task of Data Mapper Pattern is to communicate with the database and perform actions on the objects by persisting them to a permanent medium. As discussed earlier, the responsibility of persisting to a permanent medium should not be assigned to the model but to the data mapper classes. By using the data mapper pattern, you are delegating the work to a different layer, and thus following the principals of the separation of concerns. The preceding diagram demonstrates the relationship between the model class and the data mapper. As the diagram shows, the model communicates with the data mapper and the data mapper takes action to persist the model class to a database or any other permanent medium. Question: How is the Data Mapper pattern different from the Active Record pattern?

3-16

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 3

Creating a Data Repository

Accessing data is one of the most important aspects of the application, and can be performed in a wide variety of ways. This lesson discusses the Repository pattern that is used to access and persist information to the database. The lesson also covers different types of validations that can be performed on the MVC model.

Lesson Objectives:
After completing this lesson, you will be able to: Implement the Repository Pattern. Perform model data validation. Catch data type errors. Implement the validation class and handle business rules.

Developing MVC Models

3-17

What is the Repository Pattern?

Although there are many different ways of fetching the data from the database, the Repository pattern is considered the standard when accessing data. The primary responsibility of the repository pattern is to fetch and persist the information to the database, but it must only fetch the information if it is not available in the cache. If the item is found in the cache, then it is returned from there. Otherwise, it is fetched directly from the database.

Understanding the Repository Pattern


The Repository pattern allows the client to perform CRUD (Create, Read, Update, and Delete) operations on the model. When retrieving the model from the storage the repository first checks for the existence of the object in the memory. If the object is not found in memory then it is retrieved from the database and inserted into the memory. The repository pattern uses the Criteria object to filter search result. The user can provide different criteria to retrieve different results from the persistent storage.

3-18

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Creating a Data Repository

This topic focuses on implementing a data repository. The demonstration uses the Entity Framework as the data model. The repository will exhibit persistence and data retrieval methods. 1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the MvcApplication1 solution at the following location. Programming Language Visual C# Visual Basic a. b. Location D:\Demofiles\CS\MvcApplication1 D:\Demofiles\VB\MvcApplication1

In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project, or press CTRL+SHIFT+O. In the Open Project dialog box, in the File name box, type D:\Demofiles\CS\MvcApplication1\MvcApplication1.sln or D:\Demofiles\VB\MvcApplication1\MvcApplication1.sln and then click Open.

3.

Add a new ADO.NET Entity Data Model named MyModel.edmx to the project, and generate the model from database. The model must be added to the Models folder. a. b. c. In Solution Explorer, right-click Models, point to Add, and then click New Item. In the Add New Item MvcApplication1 dialog box, in the left pane, click Data. In the middle pane, click ADO.NET Entity Data Model, in the Name box, type MyModel.edmx, and then click Add.

Developing MVC Models

3-19

d. 4.

In the Entity Data Model Wizard, on the Choose Model Contents page, click Generate from database, and then click Next.

In the Entity Data Model Wizard, on the Choose Your Data Connection page, if the Which data connection should your application use to connect to the database? list, is empty, click New Connection, and create a new connection to the AdventureWorksLT2008R2 database on the .\SQLExpress SQL Server instance. a. b. In the Choose Data Source dialog box, in the Data source list, click Microsoft SQL Server, and then click OK. In the Connection Properties dialog box, in the Server name box, type .\SQLExpress, in the Select or enter a database name list, click AdventureWorksLT2008R2, and then click Continue.

5.

In the Entity Data Model Wizard, on the Choose Your Data Connection page, if the Which data connection should your application use to connect to the database? list, click 10264a-gendev\sqlexpress.AdventureWorksLT2008R2.Sales(LT), and then click Next. Select the Blog and Blogger tables from the database. On the Choose Your Database Objects page, in the Which database objects do you want to include in your model list, expand Tables, select the Blog and Blogger check boxes, and then click Finish.

6.

7.

Add a new data repository class named BlogRepository to the Models folder. a. b. c. In Solution Explorer, right-click Models, point to Add, and then click New Item. In the Add New Item MvcApplication1 dialog box, in the left pane, click Visual C# or Visual Basic. In the middle pane, click Class, in the Name box, type BlogRepository, and then click Add.

8.

Add the following code to the BlogRepository class.


[Visual C#] private AdventureWorksLT2008R2Entities db = new AdventureWorksLT2008R2Entities(); public IQueryable<MvcApplication1.Models.Blog> GetAllBlogs() { return db.Blogs; }

3-20

Developing Web Applications with Microsoft Visual Studio 2010

[Visual Basic] Private db As New AdventureWorksLT2008R2Entities() Public Function GetAllBlogs() As IQueryable(Of MvcApplication1.Blog) Return db.Blogs End Function

In the BlogRepository.cs or BlogRepository.vb window, at the top of the BlogRepository class, type the following code.
[Visual C#] private AdventureWorksLT2008R2Entities db = new AdventureWorksLT2008R2Entities(); public IQueryable<MvcApplication1.Models.Blog> GetAllBlogs() { return db.Blogs; } [Visual Basic] Private AdventureWorksLT2008R2Entities db As New AdventureWorksLT2008R2Entities() Public Function GetAllBlogs() As IQueryable(Of MvcApplication1.Blog) Return db.Blogs End Function

9.

Append the Save method to the BlogRepository class, which is responsible for persisting the Blog object into the database.
[Visual C#] public static void Save(MvcApplication1.Models.Blog blog) { using (var db = new AdventureWorksLT2008R2Entities ()) { if (blog.BloggerID == 0) { db.AddToBlogs(blog); db.SaveChanges(); } } } [Visual Basic] Public Shared Sub Save(ByVal blog As MvcApplication1.Blog) Using db As New AdventureWorksLT2008R2Entities() If blog.BloggerID = 0 Then db.AddToBlogs(blog) db.SaveChanges() End If End Using End Sub

In the BlogRepository.cs or BlogRepository.vb window, append the following code.


[Visual C#] public static void Save(MvcApplication1.Models.Blog blog) { using (var db = new AdventureWorksLT2008R2Entities ()) { if (blog.BloggerID == 0) { db.AddToBlogs(blog); db.SaveChanges(); } }

Developing MVC Models

3-21

} [Visual Basic] Public Shared Sub Save(ByVal blog As MvcApplication1.Blog) Using db As New AdventureWorksLT2008R2Entities() If blog.BloggerID = 0 Then db.AddToBlogs(blog) db.SaveChanges() End If End Using End Sub

10. Delete the Blog class from the Models folder. a. b. In Solution Explorer, in the Models folder, right-click Blog.cs or Blog.vb, and then click Delete. In the Microsoft Visual Studio dialog box, click OK.

11. Build the solution, and fix any errors. In the MvcApplication1 Microsoft Visual Studio window, on the Build menu, click Build Solution, or press CTRL+SHIFT+B.

12. Close Visual Studio 2010. In the MvcApplication1 Microsoft Visual Studio window, click the Close button.

3-22

Developing Web Applications with Microsoft Visual Studio 2010

Data Type Errors Handled by MVC Models

Data type errors are caused when the type supplied by the user does not match the type in the database. A simple scenario is where the user is trying to insert a string value into a field that requires a decimal value. An MVC model developed using the Entity Framework captures these errors by default, and throws the necessary exceptions to notify the user of the associated problems. When the model is created using the Entity Framework designer, it automatically finds out the data type of the field in the database. When persisting the value to the database, the Entity Framework validates the type of the entity with the field type in the database. If the types are incompatible with each other, then an exception is thrown and the user is notified of the problem.

Developing MVC Models

3-23

Business Logic Errors and MVC

It is recommended that you do not use MVC models to handle business logic errors. The main reason for this is that the MVC model associated with LINQ to SQL or the Entity Framework is regenerated on each build. This means any code you implement in the model classes will be lost the next time the project is built. A preferred approach is to write the business logic validation code in a separate class that extends the model class. This will ensure that the custom code implemented by the user is not overwritten on subsequent builds. This can be achieved by using partial classes, which allow you to extend the behavior of the existing classes by creating a class of the same name.

3-24

Developing Web Applications with Microsoft Visual Studio 2010

Extending Model Classes to Add Business Rules

As discussed in the previous topic, adding the business rules directly in the model class is not a good idea since the rules are removed as soon as the project is rebuilt, and the Entity Framework regenerates the model class. For this very reason, the model validation is separated from the actual model class and moved out into a separate class. This separation is performed by leveraging the partial class. In the following implementation, the Blog class has been extended by exposing it as a partial class.
[Visual C#] public partial class Blog { } [Visual Basic] Public Partial Class Blog End Class

Next, the business rule errors caused by our model need to be added. For this, a new class, which handles the business rule errors, will be introduced. This is shown in the following implementation.
[Visual C#] public class BlogMetadata { [Required(ErrorMessage="Title is required")] public object Title { get; set; } [Required(ErrorMessage="Blog is required")] public object Blog { get; set; } } [Visual Basic] Public Class BlogMetadata <Required(ErrorMessage := "Title is required")>

Developing MVC Models

3-25

Public Property Title() As Object <Required(ErrorMessage := "Blog is required")> Public Property Blog() As Object End Class

The BlogMetadata class is responsible for validating the model. The BlogMetadata class exposes the properties upon which the validation will act. These properties include Title and Blog. Each property is decorated with Required attribute, which represents that the value to the property is required by the model. The last step is to tell the Blog class about the BlogMetadata class. This is performed by using the MetadataType attribute on the Blog class, as shown in the following.
[Visual C#] [MetadataType(typeof(BlogMetadata))] public partial class Blog { } <MetadataType(GetType(BlogMetadata))> Public Partial Class Blog End Class

The MetadataType attribute represents the class, which contains the additional behavior for the model class. Question: Why is it not a good idea to implement the business rules in the model class created by using the Entity Framework?

3-26

Developing Web Applications with Microsoft Visual Studio 2010

Handling Business Rule Errors

There are various ways of handling the business rules errors, depending on the implementation of the validation class. Attribute-based validation errors can be handled by creating a validation engine that is responsible for triggering the validation on the model classes. The broken rules can be stored in a list, and an exception can be thrown to notify the view about the errors. In an MVC view, you can use the ValidationMessage and ValidationSummary HtmlHelpers, which can be used to display the errors on the page to the user. The errors can be placed in the ViewData dictionary and then displayed on the view. The ValidationMessage and ValidationSummary HTML helpers can easily be customized by creating a new style and applying to them.

Developing MVC Models

3-27

Model Data Validation

In an MVC application, the model is typically populated by the client using the web page interface. Web applications should never trust any input from the user. Input not validated can result in serious security attacks including SQL injections, cross side scripting attacks and more. The errors can be handled by using data annotations, which allow the developers to decorate or annotate the properties with attributes. The validation rules are automatically enforced whenever MVC performs model-binding operations, not just when saving to a data store. The data annotation attribute classes are located in the System.ComponentModel.DataAnnotations namespace, and importing the namespace makes it easier to use the various attribute classes in your model.
[Visual C#] using System.ComponentModel.DataAnnotations: [Visual Basic] Imports System.ComponentModel.DataAnnotations

If you have a Customer class with ID, Name, Address, PhoneNo and CreditCardNo member fields, you can annotate the class like this, to implement automatic validation.
[Visual C#] public class Customer { private Guid customerID; public Guid ID { get { return customerID; } } [StringLength(80,

3-28

Developing Web Applications with Microsoft Visual Studio 2010

ErrorMessage = "Name must between 5 and 80 characters long.", MinimumLength = 5)] public string Name { get; set; } [StringLength(100, ErrorMessage = "Address must between 5 and 100 characters long.", MinimumLength = 5)] public string Address { get; set; } [DataType(DataType.PhoneNumber)] public string PhoneNo { get; set; } [RegularExpression( "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13})$", ErrorMessage = "The credit card number is invalid.")] public string CreditCardNo { get; set; }

[Visual Basic] Public Class Customer Private customerID As Guid Public ReadOnly Property ID As Guid Get Return customerID End Get End Property <StringLength(80, ErrorMessage:="Name must between 5 and 80 characters long.", MinimumLength:=5)> Public Property Name As String <StringLength(100, ErrorMessage:="Address must between 5 and 100 characters long.", MinimumLength:=5)> Public Property Address As String <DataType(DataType.PhoneNumber)> Public Property PhoneNo As String <RegularExpression( "^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13})$", ErrorMessage:="The credit card number is invalid.")> Public Property CreditCardNo As String End Class

In the code, the StringLengthAttribute class has been used to annotate the Name and Address properties, to ensure the minimum and maximum input length. The DataTypeAttribute class has been used to annotate the PhoneNo property, to make the data type more specific (for example, than what can be retrieved from a database). Finally, the RegularExpressionAttribute class has been used to annotate the CreditCardNo property, to ensure that a valid card number is entered.

Developing MVC Models

3-29

Creating a Data Validation Class

When using LINQ to SQL or the Entity Framework as the data access layer the model classes are automatically generated. This means that any custom code written in those autogenerated files will be overwritten on the next build. For this reason, all validation rules for the model must reside in a separate file. In line with how validation is applied by using a separate file, business rules should also be added in a separate file, containing at least a single class that extends the model. This can be done by applying attributes or by adding validation methods, and invoking them as appropriate. If you are creating your classes manually, start by creating a class similar to the one created in the previous topic, with the required properties, and then annotate the properties as you see fit, to ensure proper input validation.

3-30

Developing Web Applications with Microsoft Visual Studio 2010

Lab 3: Creating MVC Models

Objectives:
After completing this lab, you will be able to: Work with the AdventureWorks database. Use Entity Framework data model. Implement data validation for the MVC models.

Introduction
In this lab, you will create relationships between database tables by using the Database Designer, create an Entity Framework data model, add a data repository, and implement data model validation.

Developing MVC Models

3-31

Lab Scenario

3-32

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 1: Exploring the AdventureWorks Database


The main tasks for this exercise are as follows: 1. 2. 3. 4. Open the AdventureWorksMvc solution in Visual Studio 2010. Open AdventureWorks database. Examine the table schemas. Add Relationships between tables using Diagrams.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. 3. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution at the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 03\Starter\Exercise 01 D:\Lab Files\VB\Lab 03\Starter\Exercise 01

Task 2: Open AdventureWorks database


Open the AdventureWorksLT2008R2 database by using Server Explorer.

Task 3: Examine the table schemas


1. 2. Display the list of tables. Open the Customer (SalesLT) table in the Table Designer.

Developing MVC Models

3-33

3. 4.

Examine the schema of the table. Close the Table Designer.

Task 4: Add Relationships between tables using Diagrams


1. Create a new database diagram containing the Customer and CustomerAddress tables.

Note: The relationship between the Customer and CustomerAddress table is one-to-many, which means a single customer can have multiple addresses.

3-34

Developing Web Applications with Microsoft Visual Studio 2010

2. 3.

Close the Database Designer and do not save the diagram. Close Visual Studio 2010.

Result: After completing this exercise, you should have learned how to use Server Explorer to examine the database schema and view relationships between the tables using database diagrams.

Developing MVC Models

3-35

Exercise 2: Adding an ADO.NET Entity Data Model


The main tasks for this exercise are as follows: 1. 2. 3. 4. Open the AdventureWorksMvc solution in Visual Studio 2010. Add Entity Data Model to the web application. Add data repository. Implement list, select, insert, update, and delete operations.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution at the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 03\Starter\Exercise 02 D:\Lab Files\VB\Lab 03\Starter\Exercise 02

Task 2: Add Entity Data Model to the web application


1. Add a new ADO.NET Entity Data Model named AdventureWorks.edmx to the project, and generate the model from database. The model must be added to the Models folder.

2.

Use the existing AdventureWorksLT2008ConnectionString connection string to connect to the database, and save the connection settings in the Web.config file as AdventureWorksEntities.

3-36

Developing Web Applications with Microsoft Visual Studio 2010

3.

Select the Blog and Blogger tables from the database and name the model namespace AdventureWorksModel.

Developing MVC Models

3-37

4.

Build the solution, and fix any errors.

Task 3: Add data repository


Add a new data repository class named BlogRepository to the Models folder.

Task 4: Implement list, select, insert, update, and delete operations


1. Declare and instantiate a private AdventureWorksEntities object named db in the BlogRepository class.
[Visual C#] private AdventureWorksEntities db = new AdventureWorksEntities(); [Visual Basic] Private db As New AdventureWorksEntities

2.

Add the following method to the BlogRepository class to return a list of all of the blogs.
[Visual C#] public IQueryable<Blog> GetAllBlogs() { return db.Blogs; } [Visual Basic] Public Function GetAllBlogs() As IQueryable(Of Blog) Return db.Blogs End Function

3-38

Developing Web Applications with Microsoft Visual Studio 2010

3.

Add the following method to the BlogRepository class to return a list of all of the blogs for a specific blogger.
[Visual C#] public IQueryable<Blog> GetAllBlogs(int id) { return from blog in db.Blogs where blog.BloggerID == id select blog; } [Visual Basic] Public Function GetAllBlogs(ByVal id As Integer) As IQueryable(Of Blog) Return From blog In db.Blogs Where blog.BloggerID = id Select blog End Function

4.

Add the following method to the BlogRepository class to return a specific blog.
[Visual C#] public Blog GetBlog(int id) { return (from blog in db.Blogs where blog.BlogID == id select blog).SingleOrDefault(); } [Visual Basic] Public Function GetBlog(ByVal id As Integer) As Blog Return (From blog In db.Blogs Where blog.BlogID = id Select blog).SingleOrDefault() End Function

5.

Add the following method to the BlogRepository class to return the name of the blogger.
[Visual C#] public string GetBloggerName(int id) { var bloggerName = (from blogger in db.Bloggers where blogger.BloggerID == id select blogger.Name).FirstOrDefault(); } return bloggerName;

[Visual Basic] Public Function GetBloggerName(ByVal id As Integer) As String Dim bloggerName = (From blogger In db.Bloggers Where blogger.BloggerID = id Select blogger.Name).FirstOrDefault Return bloggerName End Function

6.

Add the following methods to the BlogRepository class to add, update, delete, and save individual blogs.
[Visual C#] public void AddBlog(Blog blog) { db.Blogs.AddObject(blog); }

Developing MVC Models

3-39

public void UpdateBlog(Blog blog) { db.Blogs.ApplyCurrentValues(blog); } public void DeleteBlog(Blog blog) { db.Blogs.DeleteObject(blog); } public void Save() { db.SaveChanges(); } [Visual Basic] Public Sub AddBlog(ByVal blg As Blog) db.Blogs.ApplyCurrentValues(blg) End Sub Public Sub UpdateBlog(ByVal blg As Blog) db.Blogs.Attach(blg) End Sub Public Sub DeleteBlog(ByVal blg As Blog) db.Blogs.DeleteObject(blg) End Sub Public Sub Save() db.SaveChanges() End Sub

7. 8.

Save all modified files. Close Visual Studio 2010.

Result: In this exercise, you added an Entity data model to the web application, connecting it to the existing AdventureWorks database. You also added a repository class and implemented list, select, insert, update, and delete operations in the class.

3-40

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 3: Model Data Validation


The main tasks for this exercise are as follows: 1. 2. 3. Open the AdventureWorksMvc solution in Visual Studio 2010. Add a partial class to the Models folder. Add business rules validation.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution at the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 03\Starter\Exercise 03 D:\Lab Files\VB\Lab 03\Starter\Exercise 03

Task 2: Add a partial class to the Models folder


1. 2. Add a new class named Blog to the Models folder. Make the Blog class partial, by prefixing with the keyword partial/Partial.
[Visual C#] public partial class Blog [Visual Basic] Partial Public Class Blog

3.

Import the System.ComponentModel and System.ComponentModel.DataAnnotations namespaces.


[Visual C#] using System.ComponentModel.DataAnnotations; using System.ComponentModel; [Visual Basic] Imports System.ComponentModel.DataAnnotations Imports System.ComponentModel

Note: In the next section, you will add business rules validation to the partial class.

Task 3: Add business rules validation


1. Add another class named BlogMetadata to the Blog.cs or Blog.vb code file.
[Visual C#] public class Blog_MetaData { [DisplayName("Blog ID")] public object BlogID { get; set; } [DisplayName("Date Posted")] [DisplayFormat(DataFormatString = "{0:d}")] public object DatePosted { get; set; } [Required] public object Title { get; set; }

Developing MVC Models

3-41

[Required] [DisplayName("Blog Entry")] public object BlogEntry { get; set; }

[Visual Basic] Public Class Blog_MetaData <DisplayName("Blog ID")> _ Public Property BlogID As Object <DisplayName("Date Posted")> _ <DisplayFormat(DataFormatString:="{0:d}")> _ Public Property DatePosted As Object <Required()> _ Public Property Title As Object <Required()> <DisplayName("Blog Entry")> _ Public Property BlogEntry As Object End Class

2.

Apply the MetadataType attribute to the Blog class, and reference the Blog_Metadata type as the metadata type.
[Visual C#] [MetadataType(typeof(Blog_MetaData))] public partial class Blog [Visual Basic] <MetadataType(GetType(Blog_MetaData))> Partial Public Class Blog

3. 4.

Build the solution, and fix any errors. Close Visual Studio 2010.

Task 4: Turn off the virtual machine and revert the changes
1. 2. 3. 4. In Microsoft Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert. In the Revert Virtual Machine dialog box, click Revert.

Result: After completing this exercise you should have learned how to add a partial class to the model and extend the behavior of the existing class using partial classes and add validation logic in the partial class.

3-42

Developing Web Applications with Microsoft Visual Studio 2010

Lab Review

Developing MVC Models

3-43

Module Review and Takeaways

Review Questions
1. 2. 3. 4. Name some other object-relational mapping tools besides LINQ to SQL and the Entity Framework. What is the name of the pattern that is used to map the database tables to the classes? How is the Data Mapper pattern different from the Active Record pattern? How is the Repository pattern different from the Data Mapper pattern?

Real-world Issues and Scenarios


1. It is always a good idea to keep the Views in a separate project. (The Controllers and Models can reside in a single common project.) This makes the View project easily replaceable, and provide ease of unit testing for the Controllers and Models. When performing validation, always make sure not to give extra information to the user in the validation message. The message should only indicate the error associated with the action of the user.

2.

Best Practices
The model should not be concerned with saving itself to the persistent medium. The data access responsibility should be kept separate from the model. When creating data repositories, make sure to expose them as an interface rather than concrete class. This provides an easy way to perform unit testing and to mock up the repository. When creating data repositories, make sure that the repository first accesses the memory to retrieve the object, and, if not found, then accesses the physical storage.

3-44

Developing Web Applications with Microsoft Visual Studio 2010

Developing MVC Controllers

4-1

Module 4
Developing MVC Controllers
Contents:
Lesson 1: Implementing MVC Controllers Lesson 2: Creating Action Methods Lab 4: Developing MVC Controllers 4-3 4-13 4-29

4-2

Developing Web Applications with Microsoft Visual Studio 2010

Module Overview

The Model-View-Controller (MVC) architectural pattern separates an application into three main components: the model, the view, and the controller. The UI logic belongs in the view. Input logic belongs in the controller. Business logic belongs in the model.

In a Microsoft ASP.NET MVC application, the controller is the boss. Every time a request comes into an ASP.NET MVC application, it is routed to a controller. The controller can issue any set of commands to the model, and render any view back to the browser. Each controller contains one or more action methods. An action method is a special type of method that can pass data to a view. In this module, you will learn how to implement an MVC controller, and how to create various types of action methods.

Developing MVC Controllers

4-3

Lesson 1

Implementing MVC Controllers

MVC controllers process incoming requests, handle user input and interactions, and execute appropriate application logic. Action filters are used to perform logic either before a controller is called, or after a controller runs. In this lesson, you will learn about MVC controllers and the various types of action filters that can be applied to them. You will also learn how to create an MVC controller.

Lesson Objectives:
After completing this lesson, you will be able to: Describe an MVC controller. Create an MVC controller. Describe an action filter. Use an action filter.

4-4

Developing Web Applications with Microsoft Visual Studio 2010

What is an MVC Controller?

MVC controllers are responsible for handling requests made against an ASP.NET MVC web application. The requests are routed to the appropriate action method of the controller via the UrlRoutingModule object, which is an HTTP module. This module parses the request and performs route selection. For example, if you wanted to call the Details action method of the BlogController class, you would enter the following URL into the browser:
http://localhost/blog/details/3

Note: All controller classes must end with the Controller suffix; for example, the Blog controller must be named BlogController. Following is an example of a simple controller named BlogController, which contains an Index action method.
[Visual C#] using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace AdventureWorksMvc.Controllers { public class BlogController : Controller { // // GET: /Blog/ public ActionResult Index() {

Developing MVC Controllers

4-5

return View();

[Visual Basic] Public Class BlogController Inherits System.Web.Mvc.Controller ' ' GET: /Blog Function Index() As ActionResult Return View() End Function End Class

The base class for all controllers is the ControllerBase class, which provides general MVC handling. The Controller class inherits from ControllerBase and is the default implementation of a controller. The Controller class is responsible for the following processing stages: Locating the appropriate action method to call, and validating that it can be called. Getting the values to use as the action methods arguments. Handling all errors that might occur during the execution of the action method. Rendering the appropriate view.

Additional Reading
For more information about MVC controllers, see Controller Class at http://go.microsoft.com/fwlink/?LinkID=204023&clcid=0x409. For more information about routing, see Understanding the MVC Application Execution Process http://go.microsoft.com/fwlink/?LinkID=204025&clcid=0x409. Question: What is the name of the Product controller class?

4-6

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Creating an MVC Controller

In this demonstration, you will learn how to create an MVC controller. 1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Create a new ASP.NET MVC 2 Web Application project, with an associated Unit Test project. a. b. In the Start Page Microsoft Visual Studio window, on the File menu, click New Project, or press CTRL+SHIFT+N. In the New Project dialog box, in the left pane, click Visual C# or Visual Basic, in the middle pane, click ASP.NET MVC 2 Web Application, in the Location box, type D:\Demofiles\CS or D:\Demofiles\VB, and then click OK. In the Create Unit Test Project dialog box, ensure that Yes, create a unit test project is selected, and then click OK.

c. 3.

Create a controller named BlogController in the Controllers folder. The controller should include action methods for create, update, delete, and details scenarios. a. b. In Solution Explorer, right-click Controllers, point to Add and then click Controller. In the Add Controller dialog box, in the Controller Name box, type BlogController, select the Add action methods for Create, Update, Delete, and Details scenarios check box, and then click Add.

4.

Build the solution, and fix any errors. In the MvcApplication1 Microsoft Visual Studio window, on the Build menu, click Build Solution, or press CTRL+SHIFT+B.

5.

Close Visual Studio 2010. In the MvcApplication1 Microsoft Visual Studio window, click the Close button.

Developing MVC Controllers

4-7

What is an Action Filter?

An action filter is an attribute that you can apply to a controller or an individual action method, to modify how the action is executed. If the attribute decorates a controller, the action filter applies to all action methods in that controller. Action filters are custom attributes that provide a declarative means to add pre-action and post-action behavior to controller action methods. The possible uses for action filters are as varied as the actions to which they can be applied. Some possible uses for action filters include: Logging, to track user interactions. Anti-image-leeching, to prevent images from being loaded in pages that are not on your site. Web crawler filtering, to change application behavior based on the browser user agent. Localization, to set the locale. Dynamic actions, to inject an action into a controller.

ASP.NET MVC provides four types of action filters. Each type of action filter includes a collection of classes. You can use the classes that are provided, or write your own. The four types of action filters are listed in the following table: Filter type Authorization Description This filter makes security decisions about whether to execute an action method, such as performing authentication or validating properties of the request. The AuthorizeAttribute class is an example of an authorization filter. This filter wraps the action method execution, and can perform additional processing, such as providing extra data to the action method, inspecting the return value, or canceling execution of the action method.

Action

4-8

Developing Web Applications with Microsoft Visual Studio 2010

Filter type Result

Description This filter wraps execution of the ActionResult object, and can perform additional processing of the result, such as modifying the HTTP response. The OutputCacheAttribute class is an example of a result filter. This filter executes if there is an unhandled exception thrown somewhere in action method, starting with the authorization filters and ending with the execution of the result. Exception filters can be used for tasks such as logging or displaying an error page. The HandleErrorAttribute class is an example of an exception filter.

Exception

The following code shows an example of a controller that is decorated with the HandleErrorAttribute attribute.
[Visual C#] [HandleError(Order = 2)] public class HomeController : Controller { public ActionResult Index() { ViewData["Message"] = "Welcome to ASP.NET MVC!"; } return View();

public ActionResult About() { return View(); } [HandleError] public ActionResult ThrowException() { throw new Exception(); } [HandleError(View = "CustomErrorView", ExceptionType = typeof(NotImplementedException))] public ActionResult ThrowNotImplemented() { throw new NotImplementedException(); } } [Visual Basic] <HandleError(Order:=2)> Public Class HomeController Inherits System.Web.Mvc.Controller Function Index() As ActionResult ViewData("Message") = "Welcome to ASP.NET MVC!" Return View() End Function Function About() As ActionResult Return View() End Function

Developing MVC Controllers

4-9

<HandleError()> Public Function ThrowException() As ActionResult Throw (New Exception()) End Function <HandleError(View:="CustomErrorView", ExceptionType:=GetType(NotImplementedException))> Public Function ThrowNotImplemented() As ActionResult Throw (New NotImplementedException()) End Function End Class

By using the HandleErrorAttribute attribute, you can specify how to handle an exception. Following are the properties of the HandleErrorAttribute attribute: ExceptionType. Specifies the exception type or types that the filter handles. If this property is not specified, the filter handles all exceptions. View. Specifies the name of the view to display. Master. Specifies the name of the master view to use, if any. Order. Specifies the order in which the filters are applied.

A controller class, or action method, can be decorated with one or more action filters. Each action filter has an Order property, which is used to determine the order in which filters are executed. You can set the Order property to an integer value that specifies a priority from -1 (highest priority) to any positive integer value. The greater the integer value, the lower the priority of the filter. The Order property follows these rules: 1. 2. 3. 4. Filters that are applied to a controller automatically apply to every action method in that controller. Filters that are applied to the controller run before filters that are applied to an action method, as long as the order numbers are the same. Filters with the same order number are applied in an undetermined order. If no order number is specified, the order number is -1.

Creating Custom Action Filters


An action filter is implemented as an attribute class that inherits from ActionFilterAttribute. ActionFilterAttribute is an abstract class that has four virtual methods that you can override: OnActionExecuting, OnActionExecuted, OnResultExecuting, and OnResultExecuted. To implement an action filter, you must override at least one of these methods. The ASP.NET MVC framework calls the OnActionExecuting method of your action filter before it calls any action method that is marked with your action filter attribute. Similarly, the ASP.NET MVC framework calls the OnActionExecuted method after the action method has finished. The OnResultExecuting method is called just before the ActionResult instance that is returned by your action is invoked. The OnResultExecuted method is called just after the result is executed. These methods are useful for performing actions such as logging and output caching. For more information about action filters, see Action Filtering in MVC Applications at http://go.microsoft.com/fwlink/?LinkID=204030&clcid=0x409.

4-10

Developing Web Applications with Microsoft Visual Studio 2010

For more information about the output cache, see OutputCacheAttribute Class at http://go.microsoft.com/fwlink/?LinkID=204031&clcid=0x409. For more information about the HandleErrorAttribute class, see HandleErrorAttribute Class at http://go.microsoft.com/fwlink/?LinkID=204033&clcid=0x409. For more information about creating a custom action filter, see How to: Create a Custom Action Filter at http://go.microsoft.com/fwlink/?LinkID=204035&clcid=0x409. Question: What are some uses for action filters? Question: What types of action filters does ASP.NET MVC provide?

Developing MVC Controllers

4-11

Demonstration: Using an Action Filter

In this demonstration, you will learn how to use a controller that is decorated with the HandleErrorAttribute attribute. 1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the MvcApplication1 solution from the following location. Programming Language Visual C# Visual Basic a. b. Location D:\Demofiles\CS\MvcApplication1 D:\Demofiles\VB\MvcApplication1

In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project, or press CTRL+SHIFT+O. In the Open Project dialog box, in the File name box, type D:\Demofiles\CS\MvcApplication1\MvcApplication1.sln or D:\Demofiles\VB\MvcApplication1\MvcApplication1.sln and then click Open.

3.

Open the HomeController controller. In Solution Explorer, expand Controllers, and then double-click HomeController.cs or HomeController.vb.

4.

In the About action method, throw an exception of type Exception. [Visual C#]
[HandleError(ExceptionType=typeof(Exception))] public ActionResult About()

4-12

Developing Web Applications with Microsoft Visual Studio 2010

{ }

throw new Exception();

[Visual Basic]
<HandleError(ExceptionType:=GetType(Exception))> Public Function About() As ActionResult Throw New Exception() End Function

5.

Open the Web.config file. In Solution Explorer, double-click Web.config.


<system.web> <customErrors mode="On" /> </system.web>

6.

Add a customErrors element to the Web.config file.

7.

Run the application. In the MvcApplication1 Microsoft Visual Studio window, on the Debug menu, click Start Without Debugging, or press CTRL+F5.

8.

Display the About page. In the Home Page Windows Internet Explorer window, click About.

Note: The error message, which is part of the Error.aspx page or view, located in the Views\Shared folder, is displayed. 9. Close Visual Studio 2010. In the MvcApplication1 Microsoft Visual Studio window, click the Close button.

Developing MVC Controllers

4-13

Lesson 2

Creating Action Methods

Each controller contains one or more action methods. Each time a controller receives a request, it locates the appropriate action method in the controller, gets values to use as the action methods arguments, and handles any errors that might occur when the action method runs. The controller then renders the requested view. In this lesson, you will learn about action methodshow they bind the data that is received as part of the HTTP request, and how they pass data to views.

Lesson Objectives
After completing this lesson, you will be able to: Describe an action method. Describe how to call an MVC view. Describe how to retrieve data from the request. Retrieve data from a request.

4-14

Developing Web Applications with Microsoft Visual Studio 2010

What are Action Methods?

Action methods typically have a one-to-one mapping with user interactions. Examples of user interactions include entering a URL into the browser, clicking a link, and submitting a form. Each of these user interactions causes a request to be sent to the server. In each case, the URL of the request includes information that the MVC framework uses to invoke an action method. An action method is a public method of a controller that can have any number of parameters, and typically returns an object of type ActionResult. It typically calls the view and passes data to the view via the ViewData object. Action methods: Must be public. Cannot be static. Cannot have unbounded generic type parameters. Cannot be overloaded based on parameters, unless they are disambiguated with attributes such as NonActionAttribute or AcceptVerbsAttribute.

The following table lists the types that a controller action method can return, and the scenarios for which the types are returned. Return type Void/Sub or null/Nothing ActionResult Object (excluding ActionResult) Control action return The ControllerActionInvoker object returns an EmptyResult object. The ControllerActionInvoker object calls the ExecuteResult method on the result. The result is passed to a CreateActionResult, which creates a new ContentResult object. The Content method of the ContentResult object

Developing MVC Controllers

4-15

Return type

Control action return is set to the invariant string representation of the returned object.

NonActionAttribute
ASP.NET MVC treats all public methods of a controller class as action methods. If your controller class contains a public method, and you do not want it to be an action method, you must decorate that method with the NonActionAttribute attribute. If an action method decorated with the NonActionAttribute attribute is requested, the server will return a Page Not Found (404) error. The following example shows an action method that is decorated with the NonActionAttribute attribute: [Visual C#]
[NonAction] public void DoSomething() { // Method logic }

[Visual Basic]
<NonAction()> Public Sub DoSomething() ' Method logic End Sub

AcceptVerbsAttribute
The AcceptVerbsAttribute attribute specifies one or more HTTP verbs to which an action method will respond. Generally, an HTTP Get occurs when a page is first requested, and an HTTP Post occurs when a page with an HTML form element is submitted. To create a web form that creates a new blog entry, it is a better practice to create two separate action methods with the same action name that respond to the different verbs, than to create one action method with two different functions. The following example demonstrates the use of the AcceptVerbsAttibute attribute: [Visual C#]
public ActionResult Create() { return View(); } [AcceptVerbs(HttpVerbs.Post)] public ActionResult Create(Blog blog) { if (ModelState.IsValid) { // TODO: Add insert logic here } } return RedirectToAction("Index");

return View(blog);

[Visual Basic]
Function Create() As ActionResult Return View() End Function

4-16

Developing Web Applications with Microsoft Visual Studio 2010

<AcceptVerbs(HttpVerbs.Post)> _ Function Create(ByVal blogEntry As Blog) As ActionResult If ModelState.IsValid Then ' TODO: Add insert logic here Return RedirectToAction("Index") End If Return View(blogEntry) End Function

Note: You need only decorate the action method that responds to the HTTP Post, because ASP.NET MVC looks for an action method that explicitly supports the incoming HTTP verb. MVC uses the action method that does not explicitly specify the HTTP verb only if one is not found. Instead of using the AcceptVerbsAttribute attribute to designate the HTTP verbs that are associated with the request, you can also use one or more of the following slightly shorter attributes: HttpDeleteAttribute HttpGetAttribute HttpPostAttribute HttpPutAttribute

Question: What are the restrictions on action methods? Question: How do you prevent a public method of a controller from being treated like an action method? Question: What is the shortest attribute you can use to designate that an action method should respond only to an HTTP Post?

Developing MVC Controllers

4-17

Calling an MVC View

A controller calls an MVC view by returning an ActionResult. Most action methods return an instance of a class that derives from ActionResult. The ActionResult class is the base for all action results. An action result represents a command that ASP.NET performs on behalf of an action method. However, there are different action result types, depending on the task that the action method is performing. For example, the most common action is to call the View method. The View method returns an instance of the ViewResult class, which is derived from ActionResult. You can create action methods that return an object of any type, such as a string, an integer, or a Boolean value. These return types are wrapped in an appropriate ActionResult type before they are rendered to the response stream. The following table shows the built-in action result types and the action helper methods that return them. Action result ViewResult Helper method View Description Renders a view as a web page. This class contains properties that identify the view to render, the name of the view, the name of the master view, view data, temporary data, and a collection for view engines for the application. Renders a partial view, which defines a section of a view that can be rendered inside another view. Redirects to another action method by using its URL. Redirects to another action method.

PartialViewResult RedirectResult RedirectToRouteResult

PartialView Redirect RedirectToAction RedirectToRoute Content

ContentResult

Returns a user-defined content type.

4-18

Developing Web Applications with Microsoft Visual Studio 2010

Action result JsonResult JavaScriptResult FileResult EmptyResult

Helper method Json JavaScript File (None)

Description Returns a serialized Json object. Returns a script that can be executed on the client. Returns binary output to write to the response. Represents a return value that is used if the action method must return a null/Nothing result (void/Sub).

Most action methods return a ViewResult that passes data to the view. The ViewDataDictionary class represents a container that is used to pass data between a controller and a view. The ViewDataDictionary is a loosely typed dictionary that you can use to pass any type of value you want. The ViewData property of a controller exposes an instance of the ViewDataDictionary class. To pass data to a view, you first add it to the controllers ViewData property in the action method that renders the view. The following example demonstrates how you can use the ViewData property to send data to the view. [Visual C#]
public class MyController : Controller { public ActionResult HelloWorld() { ViewData["Message"] = "Hello World!"; return View(); } }

[Visual Basic]
Public Class MyController Inherits System.Web.Mvc.Controller Function HelloWorld() As ActionResult ViewData("Message") = "Hello World!" Return View() End Function End Class

Another way to pass data to the view is to pass a strongly-typed object in the View method. The following examples demonstrate how to pass a strongly-typed object to the view. [Visual C#]
public ActionResult Index() { var blogs = blogRepository.GetAllBlogs(); } return View(blogs);

[Visual Basic]
Function Index() As ActionResult Dim blogs = blogRepository.GetAllBlogs() Return View(blogs)

Developing MVC Controllers

4-19

End Function

Action methods might have to pass data to another action; for example, if an error occurs when a form is being posted, or if the method must redirect to additional methods, as might occur when the user is directed to a login view and then back to the original action method. An action method can store data in the controllers TempDataDictionary object before it calls the controllers RedirectToAction method to invoke the next action. The TempData property value is stored in session state. Any action method that is called after the TempDataDictionary value is set can get values from the object, and then process or display them. The value of TempData persists until it is read, or until the session times out. Persisting TempData in this way enables scenarios such as redirection, because the values in TempData are available beyond a single request. The TempDataDictionary class is useful for displaying confirmation messages and providing information to a generic error page. The following examples show how you to use TempData to return a confirmation message to the view. These samples demonstrate how you can use the TempData property to send information to the view: [Visual C#]
[HttpPost] public ActionResult Edit(int id, FormCollection collection) { var blog = blogRepository.GetBlog(id); if (blog == null) return RedirectToAction("Index"); try {

UpdateModel(blog, collection.ToValueProvider()); blogRepository.UpdateBlog(blog); blogRepository.Save(); TempData["ConfirmationMessage"] = blog.Title + " has been updated.";

return RedirectToAction("Index"); } catch (Exception) { return View(blog); };

[Visual Basic]
<HttpPost()> Public Function Edit(ByVal id As Integer, ByVal collection As FormCollection) As ActionResult Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If Try UpdateModel(blogEntry, collection.ToValueProvider()) blogRepository.UpdateBlog((Blog)blogEntry) blogRepository.Save()

4-20

Developing Web Applications with Microsoft Visual Studio 2010

TempData("ConfirmationMessage") = blogEntry.Title & " has been updated" Return RedirectToAction("Index") Catch Return View(blogEntry) End Try End Function

Additional Reading
For more information about the ActionResult class, see ActionResult Class at http://go.microsoft.com/fwlink/?LinkID=204043&clcid=0x409. For more information about the ViewResult class, see ViewResult Class at http://go.microsoft.com/fwlink/?LinkID=204048&clcid=0x409. Question: Which types derive from the ActionResult class? Question: What are the three ways that the ViewResult class can pass data to the view?

Developing MVC Controllers

4-21

Retrieving Data from the Request

By default, the values for action method parameters are retrieved from the requests data collection. The data collection includes name/values pairs for form data, query string values, and cookie values. The controller class locates the action method, and determines any parameter values for the method, based on the RouteData instance, and based on the form data. If the parameter value cannot be parsed, and if the type of the parameter is a reference type or a nullable value type, null is passed as the parameter value. Otherwise, an exception is thrown. There are several ways to access URL parameter values in the action methods of controller classes. The Controller class exposes Request and Response properties that can be accessed in an action method. These properties have the same semantics as the HttpRequest and HttpResponse objects that are already a part of ASP.NET. However, the Request and Response objects of the Controller class accept objects that implement the HttpRequestBase and HttpResponseBase abstract classes, instead of being sealed classes. These base classes make it easy to create mock objects, which in turn make it easy to create unit tests for controller classes. The following examples show how to use the Request object to retrieve a query-string value named id. [Visual C#]
public void Detail() { int id = Convert.ToInt32(Request["id"]); ViewData["DetailInfo"] = id; } return View();

[Visual Basic]
Public Sub Detail() Dim id As Integer = Convert.ToInt32(Request("id"))

4-22

Developing Web Applications with Microsoft Visual Studio 2010

ViewData("DetailInfo") = id Return View() End Sub

Using Model Binders


The ASP.NET MVC framework can automatically map URL parameter values to parameter values for action methods. By default, if an action method takes a parameter, the MVC framework examines the incoming request data and determines whether the request contains an HTTP request value with the same name. If it does, the request value is automatically passed to the action method. The following example shows a variation of the previous example. In this variation, the id parameter is assumed to map to a request value that is also named id. Because of this automatic mapping, the action method does not have to include code to get a parameter value from the request, and the parameter value is therefore easier to use.
[Visual C#] public ResultAction Detail(int id) { ViewData["DetailInfo"] = id; } return View();

[Visual Basic] Public Function Detail(ByVal id As Integer) As ResultAction ViewData("DetailInfo") = id Return View() End Function

You can also embed parameter values as part of the URL instead of as query-string values. For example, instead of using the URL with a query string such as /Products/Detail?id=3, you can use a URL like /Products/Detail/3. The default route-mapping rule has the format /{controller}/{action}/{id}. If there is a URL sub-path after the controller and action names in the URL, it is treated as a parameter named id, and is automatically passed to the action method as a parameter value. The MVC framework also supports optional arguments for action methods. Optional parameters in the MVC framework are handled by using nullable-type arguments for controller action methods. For example, if a method can take a date as part of the query string but you want the default to be todays date if the query string parameter is missing, you can use code like that in the following examples:
[Visual C#] public ActionResult ShowArticles(DateTime? date) { if (!date.HasValue) { date = DateTime.Now; } } // ...

[Visual Basic]

Developing MVC Controllers

4-23

Public Function ShowArticles(ByVal date As DateTime?) As ActionResult If Not date.HasValue Then date = DateTime.Now End If ' ... End Function

If the request includes a value for the date parameter, that value is passed to the ShowArticles method. If the request does not include a value for this parameter, the argument is null, and the controller can take whatever actions are required to handle the missing parameter. A model binder provides a simple way to map posted form values to a .NET Framework type and passes the type to an action method as a parameter. Model binders also give you control over the deserialization of types that are passed to action methods. Model binders are like type converters, because they can convert HTTP requests into objects that are passed to an action method. However, they also have information about the current controller context. DefaultModelBinder maps every public property of the entity based on its name. The ModelState class encapsulates the state of the model binding, and contains both values and errors. You can check the ModelState.IsValid property to determine whether any errors were encountered during the model binding. Following are the properties of the ModelState class: Name Errors Value Description Returns a ModelErrorCollection object that contains any errors that occurred during model binding. Returns a ValueProviderResult object that encapsulates the value that was being bound during model binding.

The following example uses the DefaultModelBinder to bind the data from the form to an object. [Visual C#]
[HttpPost] public ActionResult Create(Blog blog) { if (!ModelState.IsValid) return View(blog); try {

blogRepository.AddBlog(blog); blogRepository.Save(); TempData["ConfirmationMessage"] = blog.Title + " has been added.";

return RedirectToAction("Index"); } catch (Exception) { return View(blog); };

[Visual Basic]
<HttpPost()> Function Create(ByVal blogEntry As Blog) As ActionResult

4-24

Developing Web Applications with Microsoft Visual Studio 2010

If Not ModelState.IsValid Then Return View(blogEntry) End If Try blogRepository.AddBlog(blogEntry) blogRepository.Save() TempData("ConfirmationMessage") = blogEntry.Title & " has been added" Return RedirectToAction("Index") Catch Return View(blogEntry) End Try End Function

The parameter of an action result can contain a FormCollection. A FormCollection contains all of the incoming request data in one collection and it provides the ToValueProvider method that you can use to return a dictionary that contains the value providers. Once you have the value providers you can use the UpdateModel method of the controller to update the specified model instance using values from the value provider. The advantage of using the UpdateModel method to update the model explicitly is that you can easily fake the FormCollection for testing purposes. Note: You should use one of the UpdateModel method overloads that take either a list of included properties (a white list) or a list of excluded properties (a black list). If no explicit white list or black list is passed, the UpdateModel method tries to update every public property of your model for which there is a corresponding value in the request. A malicious user could exploit this to update properties to which you do not intend to provide access. The following examples use the FormCollection to update the blog object. [Visual C#]
[HttpPost] public ActionResult Edit(int id, FormCollection collection) { var blog = blogRepository.GetBlog(id); if (blog == null) return RedirectToAction("Index"); try {

UpdateModel(blog, collection.ToValueProvider()); blogRepository.UpdateBlog(blog); blogRepository.Save(); TempData["ConfirmationMessage"] = blog.Title + " has been updated.";

return RedirectToAction("Index"); } catch (Exception) { return View(blog); };

[Visual Basic]

Developing MVC Controllers

4-25

[HttpPost] Public Function Edit(ByVal id As Integer, ByVal collection As FormCollection) As ActionResult Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If Try UpdateModel(blogEntry, collection.ToValueProvider()) blogRepository.UpdateBlog(CType(blogEntry, Blog)) blogRepository.Save() TempData("ConfirmationMessage") = blogEntry.Title & " has been updated" Return RedirectToAction("Index") Catch Return View(blogEntry) End Try End Function

For more information about model binders, see ModelBinders Class at http://go.microsoft.com/fwlink/?LinkID=204057&clcid=0x409. For more information about the ModelState class, see ModelState Class at http://go.microsoft.com/fwlink/?LinkID=204058&clcid=0x409. Question: How can you retrieve data from a form? Question: How can you access the list of errors that occurred during the model binding?

4-26

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Retrieving Data from the Request

In this demonstration, you will learn how to retrieve data from the RouteData, the QueryString, a TextBox, and the FormCollection. 1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the DemoHello solution from the following location. Programming Language Visual C# Visual Basic c. d. Location D:\Demofiles\CS D:\Demofiles\VB

In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project, or press CTRL+SHIFT+O. In the Open Project dialog box, in the File name box, type D:\Demofiles\CS\DemoHello.sln or D:\Demofiles\VB\DemoHello.sln and then click Open.

3.

Retrieve data from the RouteData. a. b. c. Run the project by pressing CTRL+F5. In the Hello Page - Windows Internet Explorer window, click Hello. Append the following text to the URL in the address bar, and then press ENTER.
/RouteDataDemo/World

Note: The value of the id key, retrieved from the RouteData.Values key/value pair collection, (World) is displayed.

Developing MVC Controllers

4-27

d. 4.

Close Windows Internet Explorer.

Retrieve data from the QueryString. a. b. c. Run the project by pressing CTRL+F5. In the Hello Page - Windows Internet Explorer window, click Hello. Append the following text to the URL in the address bar, and then press ENTER.
/QueryStringDemo?id=World

Note: The value of the id key, retrieved from the Request object key/value pair collection, (World) is displayed. d. 5. Close Internet Explorer.

Retrieve data from the text box. a. Replace the content of the Content2 Content control in the Index.aspx page file in the Views\Hello folder with the following markup.
[Visual C#] <% Html.BeginForm(); %> Enter Your Name: <%: Html.TextBox("id") %> <input id="Submit1" type="submit" value="Submit" /> <h2><%: ViewData["Message"] %></h2> <% Html.EndForm(); %> [Visual Basic] <% Html.BeginForm() %> Enter Your Name: <%: Html.TextBox("id") %> <input id="Submit1" type="submit" value="Submit" /> <h2><%: ViewData("Message") %></h2> <% Html.EndForm() %>

b. c. d. e. f.

In Solution Explorer, click DemoHello. Run the project by pressing CTRL+F5. In the Hello Page - Windows Internet Explorer window, click Hello. Append the following text to the URL in the address bar, and then press ENTER.
/TextBoxDemo

In the Enter Your Name box, type your name, and then click Submit. Note: The value entered in the text box is displayed.

g. 6.

Close Internet Explorer.

Retrieve data from a FormCollection. a. Add a new action method named FormCollectionDemo in the HelloController.
[Visual C#] public ActionResult FormCollectionDemo(FormCollection collection) { ViewData["Message"] = "Hello " + collection["id"]; } return View("Index");

4-28

Developing Web Applications with Microsoft Visual Studio 2010

[Visual Basic] Function FormCollectionDemo(ByVal collection As FormCollection) As ActionResult ViewData("Message") = "Hello " & collection("id") Return View("Index") End Function

b. c. d. e. f.

Run the project by pressing CTRL+F5. In the Hello Page- Windows Internet Explorer window, click Hello. Append the following text to the URL in the address bar, and then press ENTER.
/FormCollectionDemo

In the Enter Your Name box, type your name, and then click Submit. In the AutoComplete dialog box, click No. Note: The value entered in the text box, retrieved from the FormCollection object, is displayed.

g. h.

Close Internet Explorer. Close Visual Studio 2010.

Developing MVC Controllers

4-29

Lab 4: Developing MVC Controllers

Note: You can perform the tasks in this lab by using either Microsoft Visual C# or Microsoft Visual Basic as your programming language.

Objectives
After completing this lab, you will be able to: Create an MVC controller. List the existing blog entries. Create a new blog entry. Edit a blog entry. Delete a blog entry.

Introduction
In this lab, you will create an MVC controller and add code to it to perform create, read, update, and delete (CRUD) operations.

4-30

Developing Web Applications with Microsoft Visual Studio 2010

Lab Scenario

Based on your recommendations for redesigning the AdventureWorks website, the blog pages need to be developed by using MVC. You have already built your MVC model classes by leveraging an existing ADO.NET Entity Data Model. Next, you need to develop an MVC controller to handle the database operations.

Developing MVC Controllers

4-31

Exercise 1: Creating an MVC Controller


The main tasks for this exercise are as follows: Open the AdventureWorksMvc solution in Visual Studio 2010. Create a controller named BlogController.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. 3. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution from the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 04\Starter\Exercise 01 D:\Lab Files\VB\Lab 04\Starter\Exercise 01

Task 2: Create a controller named BlogController


1. 2. Create a controller named BlogController in the Controllers folder. The controller should not include action methods for create, update, delete, and details scenarios. Add the HandleErrorAttribute attribute to the BlogController class.
[Visual C#] [HandleError] [Visual Basic] <HandleError()>

3.

Verify that the code in the BlogController code file matches the following code.
[Visual C#] using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace AdventureWorksMvc.Controllers { [HandleError] public class BlogController : Controller { // // GET: /Blog/ public ActionResult Index() { return View(); } } } [Visual Basic] Namespace AdventureWorksMvc <HandleError()> Public Class BlogController Inherits System.Web.Mvc.Controller '

4-32

Developing Web Applications with Microsoft Visual Studio 2010

' GET: /Blog Function Index() As ActionResult Return View() End Function End Class End Namespace

4. 5.

Build the solution, and fix any errors. Close Visual Studio 2010.

Results: After this exercise, you should have created a new controller named BlogController that is decorated with the HandleErrorAttribute attribute.

Developing MVC Controllers

4-33

Exercise 2: Adding code to list the existing blog entries


The main tasks for this exercise are as follows: 1. 2. 3. 4. 5. Open the AdventureWorksMvc solution in Visual Studio 2010. Add a blogRepository object. Add code to the Index action method. Create a Blogger action method. Create a Details action method.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution from the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 04\Starter\Exercise 02 D:\Lab Files\VB\Lab 04\Starter\Exercise 02

Task 2: Add a blogRepository object


1. Import the AdventureWorksMvc.Models namespace in the BlogController code file.
[Visual C#] using AdventureWorksMvc.Models; [Visual Basic] Not applicable

2.

Declare and instantiate a private BlogRepository object at the top of the BlogController class.
[Visual C#] private BlogRepository blogRepository = new BlogRepository(); [Visual Basic] Private blogRepository As New BlogRepository()

Task 3: Add code to the Index action method


1. Replace the existing code in the Index action method with code that returns all of the blog entries to the view, by calling the GetAllBlogs method of the blogRepository object.
[Visual C#] var blogs = blogRepository.GetAllBlogs(); return View(blogs); [Visual Basic] Dim blogs = blogRepository.GetAllBlogs() Return View(blogs)

2.

Verify that the final Index action method matches the following code:
[Visual C#] public ActionResult Index() { var blogs = blogRepository.GetAllBlogs();

4-34

Developing Web Applications with Microsoft Visual Studio 2010

return View(blogs);

[Visual Basic] Function Index() As ActionResult Dim blogs = blogRepository.GetAllBlogs() Return View(blogs) End Function

Task 4: Create a Blogger action method


1. Add a Blogger action method that takes the ID of the blogger as the only parameter.
[Visual C#] public ActionResult Blogger(int id) { } [Visual Basic] Function Blogger(ByVal id As Integer) As ActionResult End Function

2.

Add code to the Blogger action method to return only the blog entries for the indicated blogger to the view.
[Visual C#] var blogs = blogRepository.GetAllBlogs(id); return View(blogs); [Visual Basic] Dim blogs = blogRepository.GetAllBlogs(id) Return View(blogs)

3.

Verify that the final Blogger action method matches the following code.
[Visual C#] public ActionResult Blogger(int id) { var blogs = blogRepository.GetAllBlogs(id); } return View(blogs);

[Visual Basic] Function Blogger(ByVal id As Integer) As ActionResult Dim blogs = blogRepository.GetAllBlogs(id) Return View(blogs) End Function

Task 5: Create a Details action method


1. Add a Details action method that takes the ID of the blog entry as its one parameter.
[Visual C#] public ActionResult Details(int id) { } [Visual Basic] Function Details(ByVal id As Integer) As ActionResult

Developing MVC Controllers

4-35

End Function

2.

Add code to the Details action method to return only the indicated blog entry, to the view. However, if the blog entry no longer exists, redirect the user to the Index view.
[Visual C#] var blogEntry = blogRepository.GetBlog(id); if (blogEntry == null) return RedirectToAction("Index"); return View(blogEntry); [Visual Basic] Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If Return View(blogEntry)

3.

Verify that the final Details action method matches the following code.
[Visual C#] public ActionResult Details(int id) { var blogEntry = blogRepository.GetBlog(id); if (blogEntry == null) return RedirectToAction("Index"); } return View(blogEntry);

[Visual Basic] Function Details(ByVal id As Integer) As ActionResult Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If Return View(blogEntry) End Function

4. 5.

Build the solution, and fix any errors. Close Visual Studio 2010.

Results: After this exercise, you should have created a BlogRepository and action methods that allow you to view all of the blog entries, to view just the blog entries for a particular blogger, and to view a particular blog entry.

4-36

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 3: Adding code to create a new blog entry


The main tasks for this exercise are as follows: 1. 2.
3.

Open the AdventureWorksMvc solution in Visual Studio 2010. Create a Create action method. Create a Create action method that accepts an HTTP Post.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution from the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 04\Starter\Exercise 03 D:\Lab Files\VB\Lab 04\Starter\Exercise 03

Task 2: Create a Create action method


1. Add a Create action method in the BlogController class. [Visual C#]
public ActionResult Create() { }

[Visual Basic]
Function Create() As ActionResult End Function

2.

Add code to the Create action method to return an empty ActionResult to the view. [Visual C#]
return View();

[Visual Basic]
Return View()

3.

Verify that the final Create action method matches the following code: [Visual C#]
public ActionResult Create() { return View(); }

[Visual Basic]
Function Create() As ActionResult Return View() End Function

Task 3: Create a Create action method for an HTTP Post request


1. Add a Create action method for an HTTP Post request that takes a Blog object as the only parameter. [Visual C#]
[HttpPost]

Developing MVC Controllers

4-37

public ActionResult Create(Blog blog) { }

[Visual Basic]
<HttpPost()> Function Create(ByVal blg As Blog) As ActionResult End Function

2.

Add code to the Create action method to save the new Blog object and redirect the user to the Index view. However, if the call to the Save method fails, return the user to the Create view. [Visual C#]
if (!ModelState.IsValid) return View(blog); try {

blog.DatePosted = DateTime.Now; blogRepository.AddBlog(blog); blogRepository.Save(); TempData["ConfirmationMessage"] = blog.Title + " has been added.";

return RedirectToAction("Index"); } catch (Exception) { return View(blog); };

[Visual Basic]
If ModelState.IsValid Then Try blg.DatePosted = DateTime.Now blogRepository.AddBlog(blg) blogRepository.Save() TempData("ConfirmationMessage") = blg.Title & " has been added" Return RedirectToAction("Index") Catch Return View(blg) End Try End If Return View(blg)

3.

Verify that the final Create action method that for the HTTP Post request matches the following code. [Visual C#]
[HttpPost] public ActionResult Create(Blog blog) { if (!ModelState.IsValid) return View(blog); try {

blog.DatePosted = DateTime.Now; blogRepository.AddBlog(blog); blogRepository.Save();

4-38

Developing Web Applications with Microsoft Visual Studio 2010

TempData["ConfirmationMessage"] = blog.Title + " has been added."; return RedirectToAction("Index"); } catch (Exception) { return View(blog); };

[Visual Basic]
<HttpPost()> Function Create(ByVal blg As Blog) As ActionResult If ModelState.IsValid Then Try blg.DatePosted = DateTime.Now blogRepository.AddBlog(blg) blogRepository.Save() TempData("ConfirmationMessage") = blg.Title & " has been added" Return RedirectToAction("Index") Catch Return View(blg) End Try End If Return View(blg) End Function

4. 5.

Build the solution, and fix any errors. Close Visual Studio 2010.

Results: After this exercise, you should have created two action methods for creating new blog entries. One of the action methods accepts HTTP Get requests and the other action method accepts HTTP Post requests.

Developing MVC Controllers

4-39

Exercise 4: Adding code to edit a blog entry


The main tasks for this exercise are as follows: 1. 2. 3. Open the AdventureWorksMvc solution in Visual Studio 2010. Create an Edit action method. Create an Edit action method for an HTTP Post request.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution from the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 04\Starter\Exercise 04 D:\Lab Files\VB\Lab 04\Starter\Exercise 04

Task 2: Create an Edit action method


1. Add an Edit action method that takes the ID of a blog entry as the only parameter. The method should be added to the BlogController class. [Visual C#]
public ActionResult Edit(int id) { }

[Visual Basic]
Function Edit(ByVal id As Integer) As ActionResult End Function

2.

Add code to the Edit action method to return the indicated Blog entry, to the view. However, if the blog entry no longer exists, redirect the user to the Index view. [Visual C#]
var blog = blogRepository.GetBlog(id); if (blog == null) return RedirectToAction("Index"); return View(blog);

[Visual Basic]
Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If Return View(blogEntry)

3.

Verify that the final Edit action method matches the following code. [Visual C#]
public ActionResult Edit(int id) { var blog = blogRepository.GetBlog(id);

4-40

Developing Web Applications with Microsoft Visual Studio 2010

if (blog == null) return RedirectToAction("Index"); } return View(blog);

[Visual Basic]
Function Edit(ByVal id As Integer) As ActionResult Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If Return View(blogEntry) End Function

Task 3: Create an Edit action method for an HTTP Post request


1. Add an Edit action method for an HTTP Post request that takes the ID of the blog entry and the FormCollection as the two parameters. [Visual C#]
[HttpPost] public ActionResult Edit(int id, FormCollection collection) { }

[Visual Basic]
<HttpPost()> Function Edit(ByVal id As Integer, ByVal collection As FormCollection) As ActionResult End Function

2.

Add code to the Edit action method to save the blog entry and redirect the user to the Index view. However, if the call to the Save method fails, return the user to the Edit view. Also, if the blog entry no longer exists, redirect the user to the Index view. [Visual C#]
var blog = blogRepository.GetBlog(id); if (blog == null) return RedirectToAction("Index"); try {

UpdateModel(blog, collection.ToValueProvider()); blogRepository.UpdateBlog(blog); blogRepository.Save(); TempData["ConfirmationMessage"] = blog.Title + " has been updated.";

return RedirectToAction("Index"); } catch (Exception) { return View(blog); };

[Visual Basic]
Dim blogEntry = blogRepository.GetBlog(id)

Developing MVC Controllers

4-41

If blogEntry Is Nothing Then Return RedirectToAction("Index") End If Try UpdateModel(blogEntry, collection.ToValueProvider()) blogRepository.UpdateBlog(CType(blogEntry, Blog)) blogRepository.Save() TempData("ConfirmationMessage") = blogEntry.Title & " has been updated" Return RedirectToAction("Index") Catch Return View(blogEntry) End Try

3.

Verify that the final Edit action method for an HTTP Post request matches the following code. [Visual C#]
[HttpPost] public ActionResult Edit(int id, FormCollection collection) { var blog = blogRepository.GetBlog(id); if (blog == null) return RedirectToAction("Index"); try {

UpdateModel(blog, collection.ToValueProvider()); blogRepository.UpdateBlog(blog); blogRepository.Save(); TempData["ConfirmationMessage"] = blog.Title + " has been updated.";

return RedirectToAction("Index"); } catch (Exception) { return View(blog); };

[Visual Basic]
<HttpPost()> Function Edit(ByVal id As Integer, ByVal collection As FormCollection) As ActionResult Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If Try UpdateModel(blogEntry, collection.ToValueProvider()) blogRepository.UpdateBlog(CType(blogEntry, Blog)) blogRepository.Save() TempData("ConfirmationMessage") = blogEntry.Title & " has been updated" Return RedirectToAction("Index") Catch Return View(blogEntry) End Try End Function

4-42

Developing Web Applications with Microsoft Visual Studio 2010

4. 5.

Build the solution, and fix any errors. Close Visual Studio 2010.

Results: After this exercise, you should have created two action methods for editing blog entries. One of the action methods accepts HTTP Get requests and the other action method accepts HTTP Post requests.

Developing MVC Controllers

4-43

Exercise 5: Adding code to delete a blog entry


The main tasks for this exercise are as follows: 1. 2. 3. Open the AdventureWorksMvc solution in Visual Studio 2010. Create a Delete action method. Create a Delete action method for an HTTP Post request

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution from the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 05\Starter\Exercise 03 D:\Lab Files\VB\Lab 05\Starter\Exercise 03

Task 2: Create a Delete action method


1. Add a Delete action method that takes the ID of a blog entry as the only parameter. The method should be added to the BlogController class. [Visual C#]
public ActionResult Delete(int id) { }

[Visual Basic]
Function Delete(ByVal id As Integer) As ActionResult End Function

2.

Add code to the Delete action method to redirect to the Index view. [Visual C#]
var blog = blogRepository.GetBlog(id); if (blog == null) return RedirectToAction("Index"); return View(blog);

[Visual Basic]
Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If Return View(blogEntry)

3.

Verify that the final Delete action method matches the following code. [Visual C#]
public ActionResult Delete(int id) { var blog = blogRepository.GetBlog(id);

4-44

Developing Web Applications with Microsoft Visual Studio 2010

if (blog == null) return RedirectToAction("Index"); } return View(blog);

[Visual Basic]
Function Delete(ByVal id As Integer) As ActionResult Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If Return View(blogEntry) End Function

Task 3: Create a Delete action method for an HTTP Post request


1. Add a Delete action method for an HTTP Post request that takes the ID of the blog entry and a confirmation string as the two parameters. [Visual C#]
[HttpPost] public ActionResult Delete(int id, string confirmation) { }

[Visual Basic]
<HttpPost()> Function Delete(ByVal id As Integer, ByVal confirmation As String) As ActionResult End Function

2.

Add code to the Delete action method to delete the blog entry and redirect the user to the Index view. [Visual C#]
var blog = blogRepository.GetBlog(id); if (blog == null) return RedirectToAction("Index"); blogRepository.DeleteBlog((Blog) blog); blogRepository.Save(); TempData["ConfirmationMessage"] = blog.Title + " has been deleted."; return RedirectToAction("Index");

[Visual Basic]
Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If blogRepository.DeleteBlog(CType(blogEntry, Blog)) blogRepository.Save() TempData("ConfirmationMessage") = blogEntry.Title & " has been deleted." Return RedirectToAction("Index")

Developing MVC Controllers

4-45

3.

Verify that the final Delete action method for an HTTP Post request matches the following code. [Visual C#]
[HttpPost] public ActionResult Delete(int id, string confirmation) { var blog = blogRepository.GetBlog(id); if (blog == null) return RedirectToAction("Index"); blogRepository.DeleteBlog((Blog) blog); blogRepository.Save(); TempData["ConfirmationMessage"] = blog.Title + " has been deleted."; } return RedirectToAction("Index");

[Visual Basic]
<HttpPost()> Function Delete(ByVal id As Integer, ByVal confirmation As String) As ActionResult Dim blogEntry = blogRepository.GetBlog(id) If blogEntry Is Nothing Then Return RedirectToAction("Index") End If blogRepository.DeleteBlog(CType(blogEntry, Blog)) blogRepository.Save() TempData("ConfirmationMessage") = blogEntry.Title & " has been deleted." Return RedirectToAction("Index") End Function

4. 5.

Build the solution, and fix any errors. Close Visual Studio 2010.

Task 4: Turn off the virtual machine and revert the changes
1. 2. 3. 4. In Microsoft Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert. In the Revert Virtual Machine dialog box, click Revert.

Results: After this exercise, you should have created two action methods for deleting blog entries. One of the action methods accepts HTTP Gets and the other action method accepts HTTP Posts.

4-46

Developing Web Applications with Microsoft Visual Studio 2010

Lab Review

Developing MVC Controllers

4-47

Module Review and Takeaways

Review Questions
1. 2. 3. 4. What are the responsibilities of the controller class? What are some possible action filters? What are some ways to pass data to a view? What are some ways to retrieve data from the request?

Real-world Issues and Scenarios


The main issue with ASP.NET MVC is that it is not a mature technology. It is still evolving.

Best Practices
Make sure that the controller does not contain too much code. The controller is only responsible for validating input, calling the Model to prepare the view, and either returning the view or redirecting to another action. If you follow this rule, your action method will not be more than 20 25 lines of code. If all of your action methods use the same action filter, put the action filter in the controller rather than in each action method. If all of your controllers use the same action filter, create a base controller, and inherit from that base controller. Use UpdateModel carefully. You should use one of the UpdateModel methods that take either a list of included properties (a white list) or a list of excluded properties (a black list). If no explicit white list or black list is passed, the UpdateModel method tries to update every public property of your model for which there is a corresponding value in the request. A malicious user could exploit this to update properties to which you do not intend to provide access.

4-48

Developing Web Applications with Microsoft Visual Studio 2010

Use the OutputCacheAttribute attribute to decorate the action methods with output that you want to cache. Make sure that any action methods that modify data only accept HTTP Posts.

Developing MVC Views

5-1

Module 5
Developing MVC Views
Contents:
Lesson 1: Implementing MVC Views Lesson 2: Implementing Strongly-Typed MVC Views Lesson 3: Implementing Partial MVC Views Lab 5: Developing MVC Views 5-3 5-14 5-28 5-35

5-2

Developing Web Applications with Microsoft Visual Studio 2010

Module Overview

The Model-View-Controller (MVC) architectural pattern separates an application into three main components: the model, the view, and the controller. The UI logic belongs in the view. Input logic belongs in the controller. Business logic belongs in the model.

In a Microsoft ASP.NET MVC application, the view manages the display of information. A view renders the appropriate user interface (UI) by using the data that is passed to it from the controller. Views are considered dumb because they do not contain any logic. In this module, you will learn how to implement an MVC view.

Developing MVC Views

5-3

Lesson 1

Implementing MVC Views

MVC views render the UI for the web application. By default, the MVC framework uses custom types, such as ViewPage, ViewMasterPage, and ViewUserControl that inherit from the existing ASP.NET page (.aspx), master page (.master), and user control (.ascx) types as views. In this lesson, you will learn about MVC views, and the way MVC views display data that is passed to them from the action method of an MVC controller. You will also learn how to create an MVC view.

Lesson Objectives:
After completing this lesson, you will be able to: Describe an MVC view. Create an MVC view. Describe HTML Helpers.

5-4

Developing Web Applications with Microsoft Visual Studio 2010

What is an MVC View?

MVC views are responsible for rendering the UI for an ASP.NET MVC website. They should not contain any application logic or database retrieval code. A view renders the appropriate UI by using the data that is passed to it from the controller. The data is passed to a view from a Controller action method by using the View method. The views associated with a particular controller are located in a subfolder of the Views folder that has the same name as the controller; for example, the views associated with the HomeController are located in the Views/Home folder. If you have a view that you want to share with more than one controller, such as an error page, it should be located in the Views/Shared folder. When ASP.NET MVC is looking for a particular view, it first looks in the subfolder with the same name as the controller; then it looks in the Shared subfolder. This is the order in which it would search for a view used by the Sample action method of the HomeController.
~/Views/Home/Sample.aspx ~/Views/Home/Sample.ascx ~/Views/Shared/Sample.aspx ~/Views/Shared/Sample.ascx

ViewPage
A view page is an instance of the ViewPage class. It inherits from the Page class and implements the IViewDataContainer interface. The ViewPage class defines a ViewData property that returns a ViewDataDictionary object. This property contains the data that the view displays. The following example shows the markup for the Index.aspx page. This page is one of the default views that are generated when you create a new MVC project in Visual Studio. [Visual C#]
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

Developing MVC Views

5-5

<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server"> Home Page </asp:Content> <asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server"> <h2><%: ViewData["Message"] %></h2> <p> To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>. </p> </asp:Content>

[Visual Basic]
<%@ Page Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> <asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server"> Home Page </asp:Content> <asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server"> <h2> <%: ViewData("Message") %></h2> <p> To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website"> http://asp.net/mvc</a>. </p> </asp:Content>

Note: By convention, the name Index is given to the default view for an ASP.NET MVC application.

Note: The script delimiters <% and %> are used to mark the beginning and end of a script. When the equal sign is used within the script delimiters (<%= and %>) it is a shortcut for Response.Write(), while the colon (<%: and %>) is a shortcut for Response.Write(Html.Encode()). The ViewPage class defines a TempData property that returns a TempDataDictionary object. This property contains temporary data that persists only from one request to the next. You can use a TempDataDictionary object to pass data in the same way that you use a ViewDataDictionary object. However, the data in a TempDataDictionary object persists only from one request to the next, unless you mark one or more keys for retention by using the Keep method. If a key is marked for retention, the key is retained for the next request. A typical use for a TempDataDictionary object is to pass data from an action method when it redirects to another action method. For example, an action method might store information about an error in the controllers TempData property (which returns a TempDataDictionary object) before it calls the RedirectToAction method. The next action method can then handle the error and render a view that displays an error message. Following is the markup for a sample view that uses the TempData property to render a confirmation message (if a confirmation message exists). [Visual C#]

5-6

Developing Web Applications with Microsoft Visual Studio 2010

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<AdventureWorksMvc.Models.Blog>>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Blogger </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>Blogger</h2> <% if (TempData["ConfirmationMessage"] != null) { %> <div class="message"> <%: TempData["ConfirmationMessage"]%> </div> <% } %> <% foreach (var item in Model) { %> <div> <%: Html.ActionLink("Edit", "Edit", new { id=item.BlogID })%> <%: Html.ActionLink("Delete", "Delete", new { id=item.BlogID })%> <%: item.DatePosted %> <%: item.Title %> </div> <% } %> <p> <%: Html.ActionLink("Create New", "Create") %> </p> </asp:Content>

[Visual Basic]
<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of IEnumerable(Of AdventureWorksMvc.Blog))" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Blogger </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2>Blogger</h2> <% If Not TempData("ConfirmationMessage") Is Nothing Then %> <div class="message"> <%: TempData("ConfirmationMessage")%> </div> <% End If %> <% For Each item In Model %> <div> <%: Html.ActionLink("Edit", "Edit", New With {.id = item.BlogID})%> <%: Html.ActionLink("Delete", "Delete", New With {.id = item.BlogID})%> <%: item.DatePosted %> <%: item.Title %> </div> <% Next %> <p> <%: Html.ActionLink("Create New", "Create") %> </p> </asp:Content>

The following example refers to a MasterPageFile in its Page directive. Similar to ASP.NET pages in Web Forms-based applications, ASP.NET page views (.aspx files) can use master pages to define a consistent

Developing MVC Views

5-7

layout and structure. In a typical site, the master page is bound to a content page in the Page directive of the content page. You can also use dynamic master pages (that is, you can assign a master page at run time) when you call the View method of the Controller class. The following example shows the Site.Master view, which is the master page that is generated when you create a new MVC project in Visual Studio. This file is located in the Shared subfolder of the Views folder. [Visual C#]
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title> <link href="../../Content/Site.css" rel="stylesheet" type="text/css" /> </head> <body> <div class="page"> <div id="header"> <div id="title"> <h1>My MVC Application</h1> </div> <div id="logindisplay"> <% Html.RenderPartial("LogOnUserControl"); %> </div> <div id="menucontainer"> <ul id="menu"> <li><%: Html.ActionLink("Home", "Index", "Home")%></li> <li><%: Html.ActionLink("About", "About", "Home")%></li> </ul> </div> </div> <div id="main"> <asp:ContentPlaceHolder ID="MainContent" runat="server" /> <div id="footer"> </div> </div> </div> </body> </html>

[Visual Basic]
<%@ Master Language="VB" Inherits="System.Web.Mvc.ViewMasterPage" %> <%-- The following line works around an ASP.NET compiler warning --%> <%: ""%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title> <asp:ContentPlaceHolder ID="TitleContent" runat="server" /> </title>

5-8

Developing Web Applications with Microsoft Visual Studio 2010

<link href="../../Content/Site.css" rel="stylesheet" type="text/css" /> </head> <body> <div class="page"> <div id="header"> <div id="title"> <h1> My MVC Application</h1> </div> <div id="logindisplay"> <% Html.RenderPartial("LogOnUserControl")%> </div> <div id="menucontainer"> <ul id="menu"> <li> <%: Html.ActionLink("Home", "Index", "Home")%></li> <li> <%: Html.ActionLink("About", "About", "Home")%></li> </ul> </div> </div> <div id="main"> <asp:ContentPlaceHolder ID="MainContent" runat="server" /> <div id="footer"> </div> </div> </div> </body> </html>

Additional Reading
For more information about the ViewPage class, see ViewPage Class at http://go.microsoft.com/fwlink/?LinkID=204060&clcid=0x409. For more information about the ViewDataDictionary class, see ViewDataDictionary Class at http://go.microsoft.com/fwlink/?LinkID=204061&clcid=0x409. For more information about the TempDataDictionary class, see TempDataDictionary Class at http://go.microsoft.com/fwlink/?LinkID=204062&clcid=0x409. Question: Where can the view associated with the Sample action method of the Home controller be located? Question: What is the difference between the ViewData property and the TempData property? Question: What is the attribute of the Page directive that is used to identify the master page?

Developing MVC Views

5-9

Demonstration: Creating an MVC View

In this demonstration, you will learn how to create an MVC view. 1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Create a new ASP.NET MVC 2 Web Application project, without an associated Unit Test project. a. b. In the Start Page Microsoft Visual Studio window, on the File menu, click New Project, or press CTRL+SHIFT+N. In the New Project dialog box, in the left pane, click Visual C# or Visual Basic, in the middle pane, click ASP.NET MVC 2 Web Application, in the Location box, type D:\Demofiles\CS or D:\Demofiles\VB, and then click OK. In the Create Unit Test Project dialog box, ensure No, do not create a unit test project is selected, and then click OK.

c. 3.

Delete the Home\About view. a. b. In Solution Explorer, expand Views, expand Home, right-click About.aspx, and then click Delete. In the Microsoft Visual Studio dialog box, click OK.

4.

Create an empty view named About in the Home folder. a. b. In Solution Explorer, right-click Home, point to Add and then click View. In the Add View dialog box, in the View name box, type About, clear the Create a stronglytyped view check box, and then click Add.

5.

Build the solution, and fix any errors.

5-10

Developing Web Applications with Microsoft Visual Studio 2010

6.

In the MvcApplication1 Microsoft Visual Studio window, on the Build menu, click Build Solution, or press CTRL+SHIFT+B.

Run the application. a. b. c. In Solution Explorer, click MvcApplication1. In the MvcApplication1 Microsoft Visual Studio window, on the Debug menu, click Start Without Debugging, or press CTRL+F5. In the Home Page Windows Internet Explorer window, click About.

7.

Close Windows Internet Explorer. In the About Windows Internet Explorer window, click the Close button.

8.

Close Visual Studio 2010. In the MvcApplication1 Microsoft Visual Studio window, click the Close button.

Developing MVC Views

5-11

What are HTML Helpers?

ASP.NET MVC uses HTML helpers to render HTML markup programmatically in a view. An HTML helper returns an HTML encoded string of the type MvcHtmlString that can be used to render something as simple as a CheckBox or as complicated as a complete table of data. Note: An MvcHtmlString represents an HTML-encoded string that should not be encoded again. The following code shows the markup to render a TextBox control using an HTML helper.
<%: Html.TextBox("FirstName") %>

The following code is the HTML that is rendered by the preceding HTML helper.
<input id="FirstName" name="FirstName" type="text" value="" />

HTML helpers are extension methods of the HtmlHelper class. Extension methods for the HtmlHelper class are grouped in the System.Web.Mvc.Html namespace. These extensions add helper methods for performing actions such as creating forms, rendering HTML controls, rendering partial views, and performing input validation.

Classes of HtmlHelper Methods


Following is a partial list of the HTML helpers, organized by class. MvcForm Extensions These methods render forms. Html.BeginForm Html.BeginRouteForm Html.EndForm Input Extensions These methods render the HTML input elements.

5-12

Developing Web Applications with Microsoft Visual Studio 2010

Html.CheckBox Html.Hidden Html.Password Html.RadioButton Html.TextBox Label Extensions This method renders the HTML label element. Html.Label Link Extensions These methods render HTML links. Html.ActionLink Html.RouteLink Select Extensions These methods render lists. Html.DropDownList Html.ListBox TextArea Extensions This method renders an HTML textarea element. Html.TextArea Validation Extensions These methods support validating the data on an input form. Html.Validate Html.ValidationMessage Html.ValidationSummary

Example of How to Use HtmlHelper


The following example shows how to use the HtmlHelper class with some of the methods of the InputExtensions class. The view displays a text box, a password box, some radio buttons, and some check boxes. [Visual C#]
<h2><%= Html.Encode(ViewData["Message"]) %></h2> <br /><br /> <% using(Html.BeginForm("Input", "Home")) %> <% { %> Enter your name: <%= Html.TextBox("name") %> <br /><br /> Enter a password: <%= Html.Password("pass") %> (Not actually used.) <br /><br /> Select your favorite color:<br /> <%= Html.RadioButton("favColor", "Blue", true) %> Blue <br /> <%= Html.RadioButton("favColor", "Purple", false)%> Purple <br /> <%= Html.RadioButton("favColor", "Red", false)%> Red <br /> <%= Html.RadioButton("favColor", "Orange", false)%> Orange <br /> <%= Html.RadioButton("favColor", "Yellow", false)%> Yellow <br /> <%= Html.RadioButton("favColor", "Brown", false)%> Brown <br /> <%= Html.RadioButton("favColor", "Green", false)%> Green <br /><br /> <%= Html.CheckBox("technical") %> I like to read technical books.<br /> <%= Html.CheckBox("novels") %> I like to read novels.<br /> <%= Html.CheckBox("comic") %> I like to read comic books.<br /> <br /><br />

Developing MVC Views

5-13

<input type="submit" value="Submit" /> <% } %>

[Visual Basic]
<h2><%= Html.Encode(ViewData("Message"))%></h2> <br /> <br /> <% Using Html.BeginForm("Input", "Home")%> Enter your name: <%= Html.TextBox("name") %> <br /><br /> Enter a password: <%= Html.Password("pass") %> (Not actually used.) <br /><br /> Select your favorite color:<br /> <%= Html.RadioButton("favColor", "Blue", true) %> Blue <br /> <%= Html.RadioButton("favColor", "Purple", false)%> Purple <br /> <%= Html.RadioButton("favColor", "Red", false)%> Red <br /> <%= Html.RadioButton("favColor", "Orange", false)%> Orange <br /> <%= Html.RadioButton("favColor", "Yellow", false)%> Yellow <br /> <%= Html.RadioButton("favColor", "Brown", false)%> Brown <br /> <%= Html.RadioButton("favColor", "Green", false)%> Green <br /><br /> <%= Html.CheckBox("technical") %> I like to read technical books.<br /> <%= Html.CheckBox("novels") %> I like to read novels.<br /> <%= Html.CheckBox("comic") %> I like to read comic books.<br /> <br /><br /> <input type="submit" value="Submit" /> <% End Using%>

Additional Reading
For more information about the HtmlHelper class, see HtmlHelper Class at http://go.microsoft.com/fwlink/?LinkID=204063&clcid=0x409. For more information about rendering a view using HTML helpers, see Rendering a Form in ASP.NET MVC Using HTML Helpers at http://go.microsoft.com/fwlink/?LinkID=204064&clcid=0x40. Question: What does an HTML helper return? Question: Into which categories are the HTML helpers organized?

5-14

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 2

Implementing Strongly-Typed MVC Views

In the previous lesson, you used the ViewData property of the controller to pass data to the ViewData property of the ViewPage class. The ViewData property uses a weakly-typed dictionary to hold its values. A strongly-typed view uses a data model to hold its values.

Lesson Objectives:
After completing this lesson, you will be able to: Describe a strongly-typed MVC view. Create a strongly-typed MVC view. Describe CRUD MVC views.

Developing MVC Views

5-15

What is a Strongly-typed View?

When you pass data between a view and a controller by using the ViewData property of the ViewPage class, the data is not strongly-typed. If you want to pass strongly-typed data, change the Page declaration of the view so that the view inherits from ViewPage<(Of <(TModel>)>) instead of from ViewPage, as shown in the following example: [Visual C#]
<%@ Page Inherits="System.Web.Mvc.ViewPage<AdventureWorksMVC.Models.Blog>" %>

[Visual Basic]
<%@ Page Inherits="System.Web.Mvc.ViewPage(Of AdventureWorksMVC.Blog)" %>

ViewPage<(Of <(TModel>)>) is the strongly-typed version of ViewPage. The ViewData property of ViewPage<(Of <(TModel>)>) returns a ViewDataDictionary<(Of <(TModel>)>) object, which contains strongly-typed data for the view based on a model. The model is a class that contains properties for each data item that you want to pass. Assume that your application includes the following model. [Visual C#]
using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace SampleMVC.Models { public class Person { [Required] [DisplayName("First Name")] public string FirstName { get; set; } [Required] [DisplayName("Last Name")]

5-16

Developing Web Applications with Microsoft Visual Studio 2010

public string LastName { get; set; } [Required] public int Age { get; set; }

[Visual Basic]
Imports System.ComponentModel Imports System.ComponentModel.DataAnnotations Namespace Models Public Class Person <Required()> <DisplayName("First Name")> Public Property FirstName As String <Required()> <DisplayName("Last Name")> Public Property LastName As String <Required()> Public Property Age As Integer End Class End Namespace

The easiest way to create a strongly-typed view is to use the Add View dialog box. (Right-click the folder to which you want to add the view, point to Add, and then click View.) Select SampleMVC.Models.Person as the data class and Create as the View content, and then click the Add button. Following is the markup generated. [Visual C#]
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<SampleMVC.Models.Person>" %> <!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>Create</title> </head> <body> <% using (Html.BeginForm()) {%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(model => model.FirstName) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.FirstName) %> <%: Html.ValidationMessageFor(model => model.FirstName) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.LastName) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.LastName) %> <%: Html.ValidationMessageFor(model => model.LastName) %> </div>

Developing MVC Views

5-17

<div class="editor-label"> <%: Html.LabelFor(model => model.Age) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Age) %> <%: Html.ValidationMessageFor(model => model.Age) %> </div> <input type="submit" value="Create" /> </p> </fieldset> <% } %> <div> <%: Html.ActionLink("Back to List", "Index") %> </div> </body> </html> <p>

[Visual Basic]
<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage(Of SampleMVC.Person)" %> <!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>Create</title> </head> <body> <% Using (Html.BeginForm())%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(Function(m) m.FirstName)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(m) m.FirstName)%> <%: Html.ValidationMessageFor(Function(m) m.FirstName)%> </div> <div class="editor-label"> <%: Html.LabelFor(Function(m) m.LastName)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(m) m.LastName)%> <%: Html.ValidationMessageFor(Function(m) m.LastName)%> </div> <div class="editor-label"> <%: Html.LabelFor(Function(m) m.Age)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(m) m.Age)%> <%: Html.ValidationMessageFor(Function(m) m.Age)%> </div> <p>

5-18

Developing Web Applications with Microsoft Visual Studio 2010

<input type="submit" value="Create" /> </p> </fieldset> <% End Using%> <div> <%: Html.ActionLink("Back to List", "Index") %> </div> </asp:Content> </body> </html>

The markup that is generated uses strongly-typed HTML helpers that use the Html.HelperNameFor naming convention. The strongly-typed HTML helpers use a lambda expression to specify the name of the element, as well as the value of the element. For example, this is the markup to render a TextBox using a strongly-typed HTML helper. [Visual C#]
<%: Html.TextBoxFor(model => model.FirstName) %>

[Visual Basic]
<%: Html.TextBoxFor(Function(m) m.FirstName) %>

Following is the HTML that is rendered by the preceding markup.


<input id="FirstName" name="FirstName" type="text" value="" />

Strongly-typed HTML Helpers


Following is a partial list of the strongly-typed HTML helpers, organized by class. Input Extensions These methods render the HTML input elements. Html.CheckboxFor Html.HiddenFor Html.PasswordFor Html.RadioButtonFor Html.TextBoxFor

Label Extensions This method renders the HTML label element. Html.LabelFor

Select Extensions These methods render lists. Html.DropDownListFor Html.ListBoxFor

TextArea Extensions This method renders an HTML textarea. Html.TextAreaFor

Validation Extensions These methods support validating the data on an input form. Html.ValidateFor Html.ValidationMessageFor

The advantage of using strongly-typed views is that the view knows exactly what type of data it is expecting. This way, errors can be found at compile-time rather than runtime. Another advantage is that Visual Studio IntelliSense is available when you implement your strongly-typed views.

Developing MVC Views

5-19

Additional Reading
For more information about the HtmlHelper(TModel) class, see HtmlHelper(TModel) Class at http://go.microsoft.com/fwlink/?LinkID=204065&clcid=0x409. Question: From which class does a strongly-typed view inherit? Question: What is the easiest way to create a strongly-typed view? Question: What are the advantages of using strongly-typed views?

5-20

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Creating a Strongly-typed View

In this demonstration, you will see how to create a strongly-typed MVC view. 1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Create a new ASP.NET MVC 2 Web Application project, without an associated Unit Test project. a. b. In the Start Page Microsoft Visual Studio window, on the File menu, click New Project, or press CTRL+SHIFT+N. In the New Project dialog box, in the left pane, click Visual C# or Visual Basic, in the middle pane, click ASP.NET MVC 2 Web Application, in the Name box, type StronglyTypedView, in the Location box, type D:\Demofiles\CS or D:\Demofiles\VB, and then click OK. In the Create Unit Test Project dialog box, ensure No, do not create a unit test project is selected, and then click OK.

c. 3.

Add a model class named Person to the Models folder. [Visual C#]
using System.ComponentModel; using System.ComponentModel.DataAnnotations; public class Person { [Required] [DisplayName("First Name")] public string FirstName { get; set; } [Required] [DisplayName("Last Name")] public string LastName { get; set; } [Required] public int Age { get; set; }

Developing MVC Views

5-21

[Required] public string Gender { get; set; }

[Visual Basic]
Imports System.ComponentModel Imports System.ComponentModel.DataAnnotations Public Class Person <Required()> <DisplayName("First Name")> Public Property FirstName As String <Required()> <DisplayName("Last Name")> Public Property LastName As String <Required()> Public Property Age As Integer <Required()> Public Property Gender As String End Class

a. b. c.

In Solution Explorer, right-click Models, point to Add, and then click Class. In the Add New Item dialog box, in the Name box, type Person.cs or Person.vb, and then click Add. In the Person.cs or Person.vb window, replace the content with the following code. [Visual C#]
using System.ComponentModel; using System.ComponentModel.DataAnnotations; public class Person { [Required] [DisplayName("First Name")] public string FirstName { get; set; } [Required] [DisplayName("Last Name")] public string LastName { get; set; } [Required] public int Age { get; set; } [Required] public string Gender { get; set; } }

[Visual Basic]
Imports System.ComponentModel Imports System.ComponentModel.DataAnnotations Public Class Person <Required()> <DisplayName("First Name")> Public Property FirstName As String <Required()> <DisplayName("Last Name")> Public Property LastName As String <Required()> Public Property Age As Integer <Required()> Public Property Gender As String End Class

5-22

Developing Web Applications with Microsoft Visual Studio 2010

4.

Build the solution, and fix any errors. In the StronglyTypedView Microsoft Visual Studio window, on the Build menu, click Build Solution, or press CTRL+SHIFT+B.

5.

Create a strongly-typed view named Person in the Views\Home folder. The view should include default content for the Create operation. a. b. In Solution Explorer, expand Views, right-click Home, point to Add and then click View. [Visual C#] In the Add View dialog box, in the View name box, type Person, select the Create a strongly-typed view check box, in the View data class list, click Person, in the View content list, click Create, and then click Add. [Visual Basic] In the Add View dialog box, in the View name box, type Person, select the Create a strongly-typed view check box, in the View data class list, click StronglyTypedView.Person, in the View content list, click Create, and then click Add.

c.

6.

Change the TextBox for displaying the Gender property for the model to a DropDownList. a. Replace the following markup and code. [Visual C#]
<%: Html.TextBoxFor(model => model.Gender) %>

[Visual Basic]
<%: Html.TextBoxFor(Function(model) model.Gender) %>

b.

With the following markup and code. [Visual C#]


<%: Html.DropDownListFor(model => model.Gender, (SelectList)ViewData["Gender"]) %>

[Visual Basic]
<%: Html.DropDownListFor(Function(model) model.Gender, CType(ViewData("Gender"), SelectList)) %>

7.

Add an action method named Person to the HomeController controller in the Controllers folder. [Visual C#]
public ActionResult Person() { ViewData["Gender"] = new SelectList(new[] { "", "Female", "Male" }); } return View();

[Visual Basic]
Public Function Person() As ActionResult ViewData("Gender") = New SelectList({"", "Female", "Male"}) Return View() End Function

a. b.

In Solution Explorer, expand Controllers, and then double-click HomeController. In the HomeController.cs or HomeController.vb window, in the HomeController class, type the following code.

[Visual C#]

Developing MVC Views

5-23

public ActionResult Person() { ViewData["Gender"] = new SelectList(new[] { "", "Female", "Male" }); } return View();

[Visual Basic]
Public Function Person() As ActionResult ViewData("Gender") = New SelectList({"", "Female", "Male"}) Return View() End Function

8.

Run the application. a. b. In Solution Explorer, click StronglyTypedView. In the StronglyTypedView Microsoft Visual Studio window, on the Debug menu, click Start Without Debugging, or press CTRL+F5.

9.

Navigate directly to the Person view, by using the following route.


Home/Person

In the Home Page Windows Internet Explorer window, in the address bar, append the following URL, and then press ENTER.
Home/Person

10. Close Internet Explorer. In the Person Windows Internet Explorer window, click the Close button.

11. Close Visual Studio 2010. In the StronglyTypedView Microsoft Visual Studio window, click the Close button.

5-24

Developing Web Applications with Microsoft Visual Studio 2010

CRUD MVC Views

Most applications need to create, read, update, and delete (CRUD) data. It is easy to create each of the strongly-typed CRUD MVC views by using the Add View dialog box. The CRUD MVC views include the following views: List Details Create Update Delete Empty

This is the List view that is generated by the Add View dialog box using the Person data class. [Visual C#]
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<IEnumerable<Person>>" %> <!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>List</title> </head> <body> <table> <tr> <th> </th> <th> FirstName

Developing MVC Views

5-25

%> */ })%> */ })%>

</th> <th> LastName </th> <th> Age </th> <th> Gender </th> </tr> <% foreach (var item in Model) { %> <tr> <td> <%: Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) | <%: Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey | <%: Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey

</td> <td> <%: item.FirstName %> </td> <td> <%: item.LastName %> </td> <td> <%: item.Age %> </td> <td> <%: item.Gender %> </td> </tr> <% } %> </table> <p> <%: Html.ActionLink("Create New", "Create") %> </p> </body> </html>

[Visual Basic]
<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage(Of IEnumerable (Of StronglyTypedView.Person))" %> <!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>List</title> </head> <body> <p> <%: Html.ActionLink("Create New", "Create")%> </p> <table> <tr> <th> </th> <th>

5-26

Developing Web Applications with Microsoft Visual Studio 2010

FirstName </th> <th> LastName </th> <th> Age </th> <th> Gender </th> </tr> <% For Each item In Model%> <tr> <td> <%--<%: Html.ActionLink("Edit", "Edit", New With {.id = item.PrimaryKey})%> | <%: Html.ActionLink("Details", "Details", New With {.id = item.PrimaryKey})%> | <%: Html.ActionLink("Delete", "Delete", New With {.id = item.PrimaryKey})%>--%> </td> <td> <%: item.FirstName %> </td> <td> <%: item.LastName %> </td> <td> <%: item.Age %> </td> <td> <%: item.Gender %> </td> </tr> <% Next%> </table> </body> </html>

This is the Details view that is generated by the Add View dialog box using the Person data class. [Visual C#]
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Person>" %> <!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>Details</title> </head> <body> <fieldset> <legend>Fields</legend> <div class="display-label"> FirstName</div> <div class="display-field"> <%: Model.FirstName %></div> <div class="display-label"> LastName</div> <div class="display-field"> <%: Model.LastName %></div> <div class="display-label"> Age</div>

Developing MVC Views

5-27

<div class="display-field"> <%: Model.Age %></div> <div class="display-label"> Gender</div> <div class="display-field"> <%: Model.Gender %></div> </fieldset> <p> <%: Html.ActionLink("Edit", "Edit", new { /* id=Model.PrimaryKey */ }) %> | <%: Html.ActionLink("Back to List", "Index") %> </p> </body> </html>

[Visual Basic]
<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage(Of StronglyTypedView.Person)" %> <!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>Details</title> </head> <body> <fieldset> <legend>Fields</legend> <div class="display-label"> FirstName</div> <div class="display-field"> <%: Model.FirstName %></div> <div class="display-label"> LastName</div> <div class="display-field"> <%: Model.LastName %></div> <div class="display-label"> Age</div> <div class="display-field"> <%: Model.Age %></div> <div class="display-label"> Gender</div> <div class="display-field"> <%: Model.Gender %></div> </fieldset> <p> <%--<%: Html.ActionLink("Edit", "Edit", New With {.id = Model.PrimaryKey})%> |--%> <%: Html.ActionLink("Back to List", "Index") %> </p> </body> </html>

For more information about Creating CRUD MVC views, see Walkthrough: Using MVC View Templates with Data Scaffolding at http://go.microsoft.com/fwlink/?LinkID=204066&clcid=0x409. Question: Which default views can be created by using the Add View dialog box?

5-28

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 3

Implementing Partial MVC Views

Partial views are views that are reusable in one or more views. Whenever you find yourself using the same markup in two different views, it is time to consider using a partial view.

Lesson Objectives:
After completing this lesson, you will be able to: Describe a partial MVC view. Create a partial MVC view.

Developing MVC Views

5-29

What is a Partial View?

A partial view page is an instance of the ViewUserControl class. The ViewUserControl class inherits from the UserControl class and implements the IViewDataContainer interface. The ViewUserControl class defines a ViewData property that returns a ViewDataDictionary object. This property contains the data that the partial view displays. When a partial view is instantiated, it gets its own copy of the ViewDataDictionary object that is available to the parent view. Therefore, the partial view has access to the data of the parent view. However, if the partial view updates the data, those updates affect only the partial views ViewData object. The parent views data is not changed. A partial view stores its markup in an ASP.NET user control (.ascx file). The following markup and code shows a sample partial Create view.
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Person>" %> <!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>Create</title> </head> <body> <% using (Html.BeginForm()) {%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(model => model.FirstName) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.FirstName) %>

[Visual C#]

5-30

Developing Web Applications with Microsoft Visual Studio 2010

<%: Html.ValidationMessageFor(model => model.FirstName) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.LastName) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.LastName) %> <%: Html.ValidationMessageFor(model => model.LastName) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.Age) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Age) %> <%: Html.ValidationMessageFor(model => model.Age) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.Gender) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Gender) %> <%: Html.ValidationMessageFor(model => model.Gender) %> </div> <p> <input type="submit" value="Create" /> </p> </fieldset> <% } %> <div> <%: Html.ActionLink("Back to List", "Index") %> </div> </body> </html>

[Visual Basic]
<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage(Of StronglyTypedView.Person)" %> <!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>Create</title> </head> <body> <%-- The following line works around an ASP.NET compiler warning --%> <%: ""%> <% Using Html.BeginForm()%> <%: Html.ValidationSummary(True) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(Function(model) model.FirstName) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(model) model.FirstName) %> <%: Html.ValidationMessageFor(Function(model) model.FirstName) %> </div> <div class="editor-label"> <%: Html.LabelFor(Function(model) model.LastName) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(model) model.LastName) %> <%: Html.ValidationMessageFor(Function(model) model.LastName) %>

Developing MVC Views

5-31

</div> <div class="editor-label"> <%: Html.LabelFor(Function(model) model.Age) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(model) model.Age) %> <%: Html.ValidationMessageFor(Function(model) model.Age) %> </div> <div class="editor-label"> <%: Html.LabelFor(Function(model) model.Gender) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(model) model.Gender) %> <%: Html.ValidationMessageFor(Function(model) model.Gender) %> </div> <p> <input type="submit" value="Create" /> </p> </fieldset> <% End Using%> <div> <%: Html.ActionLink("Back to List", "Index") %> </div> </body> </html>

The RenderPartial method renders an ASP.NET user control (.ascx file) as a partial view. This is the markup and code to render the preceding partial view.

[Visual C#]
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<SampleMVC.Models.Person>" %> <!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>Create</title> </head> <body> <% Html.RenderPartial("Person"); %> </body> </html>

[Visual C#]

<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<SampleMVC.Models.Person>" %> <!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>Create</title> </head> <body> <% Html.RenderPartial("Person"); %> </body> </html>

For more information about the ViewUserControl class, see ViewUserControl Class at http://go.microsoft.com/fwlink/?LinkID=204067&clcid=0x409.

5-32

Developing Web Applications with Microsoft Visual Studio 2010

For more information about the RenderPartialExtensions class, see RenderPartialExtensions Class at http://go.microsoft.com/fwlink/?LinkID=204069&clcid=0x409. Question: What is the HTML helper that is used to render a partial view? Question: In which type of file does a partial view store its markup?

Developing MVC Views

5-33

Demonstration: Creating a Partial MVC View

In this demonstration, you will see how to create a partial MVC view. 1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the StronglyTypedView solution used in the previous demonstration. a. b. In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project, or press CTRL+SHIFT+O. In the Open Project dialog box, in the File name box, type D:\Demofiles\CS\StronglyTypedView\StronglyTypedView.sln or D:\Demofiles\VB\StronglyTypedView\StronglyTypedView.sln and then click Open.

3.

Add a strongly-typed partial view named Partial to the Views\Home folder, by using the Add View dialog box. The view must contain default content for a Create view, and the view should be based on the Person class. a. b. In Solution Explorer, expand Views, right-click Home, point to Add, and then click View. [Visual C#] In the Add View dialog box, in the View name box, type Partial, select the Create a partial view (.ascx) and Create a strongly-typed view check boxes, in the View data class list, click Person, in the View content list, click Create, and then click Add.

or[Visual Basic] In the Add View dialog box, in the View name box, type Partial, select the Create a partial view (.ascx) and Create a strongly-typed view check boxes, in the View data class list, click StronglyTypedView.Person, in the View content list, click Create, and then click Add. 4. Add an empty view named Create to the Views\Home folder, by using the Add View dialog box.

5-34

Developing Web Applications with Microsoft Visual Studio 2010

a. b. 5.

In Solution Explorer, expand Views, right-click Home, point to Add, and then click View. In the Add View dialog box, in the View name box, type Create, clear the Create a partial view (.ascx) and Create a strongly-typed view check boxes, and then click Add.

Incorporate the Partial view in the Create view as part of the Content2 Content control, by using the Html.RenderPartial method. [Visual C#]
<% Html.RenderPartial("Partial"); %>

[Visual Basic]
<% Html.RenderPartial("Partial") %>

Add the following code to the Create view, in the Content2 Content control, immediately after the h2 element. [Visual C#]
<% Html.RenderPartial("Partial"); %>

[Visual Basic]
<% Html.RenderPartial("Partial") %>

6.

Run the application. a. b. In Solution Explorer, click StronglyTypedView. In the StronglyTypedView Microsoft Visual Studio window, on the Debug menu, click Start Without Debugging, or press CTRL+F5.

7.

Navigate directly to the Person view, by using the following route.


Home/Person

In the Home Page Windows Internet Explorer window, in the address bar, append the following URL, and then press ENTER.
Home/Person

8.

Close Internet Explorer. In the Person Windows Internet Explorer window, click the Close button.

9.

Close Visual Studio 2010. In the StronglyTypedView Microsoft Visual Studio window, click the Close button.

Developing MVC Views

5-35

Lab 5: Developing MVC Views

Note: You can perform the tasks in this lab by using either Microsoft Visual C# or Microsoft Visual Basic as your programming language.

Objectives
After completing this lab, you will be able to: Create a List MVC view. Create a Details MVC view. Create a Create MVC view. Create an Edit MVC view. Create a Delete MVC view.

Introduction
In this lab, you create MVC views for listing, adding, editing, and deleting blog entries. You use stronglytyped views, ViewData and TempData to retrieve the data from the controller. Also, you use partial views to reuse markup that is used on multiple pages.

5-36

Developing Web Applications with Microsoft Visual Studio 2010

Lab Scenario

Based on your recommendations for redesigning the AdventureWorks website, the blog pages need to be developed by using MVC. You have already created an ADO.NET Entity Data Model to build your MVC model classes. You have also developed an MVC controller to handle database operations. With the database access and application logic in place, you now need to create a set of MVC views to render the UI based on controller actions.

Developing MVC Views

5-37

Exercise 1: Develop a List MVC View


The main tasks for this exercise are as follows: 1. 2. 3. Add a Blog menu item to the Site.Master page. Add a view to display the complete list of blogs. Test the new view.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. 3. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution from the following location. Location D:\Lab Files\CS\Lab 05\Starter\Exercise 01 D:\Lab Files\VB\Lab 05\Starter\Exercise 01

Programming Language Visual C# Visual Basic

Task 2: Add a Blog menu item to the Site.Master page


1. 2. Open the Site.Master page. Add a menu item to the menu on the Site.Master master page, by using an Html.ActionLink method wrapped in a li HTML element, within the ul element, with an id attribute value of menu. Add the new menu item between the Home and About menu items. [Visual C#]
<li><%= Html.ActionLink("Blog", "", "Blog")%></li>

[Visual Basic]
<li><%: Html.ActionLink("Blog", "", "Blog")%></li>

3.

Verify that the ul element matches the following markup. [Visual C#]
<ul id="menu"> <li><%= Html.ActionLink("Home", "Index", "Home")%></li> <li><%= Html.ActionLink("Blog", "", "Blog")%></li> <li><%= Html.ActionLink("About", "About", "Home")%></li> /ul>

[Visual Basic]
<ul id="menu"> <li><%: Html.ActionLink("Home", "Index", "Home")%></li> <li><%: Html.ActionLink("Blog", "", "Blog")%></li> <li><%: Html.ActionLink("About", "About", "Home")%></li> </ul>

Task 3: Add a view to display the complete list of blogs


1. 2. 3. Add a Blog subfolder to the Views folder. Add an empty view named Index.aspx, based on the Site.Master page, to the Blog folder. Update the new view to a strongly-typed view of type System.Web.Mvc.ViewPage<IEnumerable<AdventureWorksMvc.Models.Blog>> or System.Web.Mvc.ViewPage(Of IEnumerable (Of AdventureWorksMvc.Blog)).

5-38

Developing Web Applications with Microsoft Visual Studio 2010

4.

Add the following markup and code to the Index view in the Content2 Content control, immediately after the h2 element. [Visual C#]
<% foreach (var item in Model) { %> <div> <%: Html.ActionLink("Details", "Details", new { id=item.BlogID })%> <%: item.DatePosted %> <%: item.Title %> </div> <% } %>

[Visual Basic]
<% For Each item As AdventureWorksMvc.Blog In Model%> <div> <%: Html.ActionLink("Details", "Details", New With {.id = item.BlogID})%> <%: item.DatePosted %> <%: item.Title %> </div> <% Next%>

5.

Verify that the markup and code in the Index view matches the following. [Visual C#]
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<AdventureWorksMvc.Models.Blog>>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Index </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Index</h2> <% foreach (var item in Model) { %> <div> <%: Html.ActionLink("Details", "Details", new { id=item.BlogID })%> <%: item.DatePosted %> <%: item.Title %> </div> <% } %> </asp:Content>

[Visual Basic]
<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of IEnumerable (Of AdventureWorksMvc.Blog))" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Index </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Index</h2> <% For Each item As AdventureWorksMvc.Blog In Model%> <div> <%: Html.ActionLink("Details", "Details", New With {.id = item.BlogID})%> <%: item.DatePosted %>

Developing MVC Views

5-39

<%: item.Title %> </div> <% Next%> </asp:Content>

6.

Build the solution, and fix any errors.

Task 4: Test the new view


1. 2. 3. 4. Run the application. Display the Blog view. Close Internet Explorer. Close Visual Studio 2010. Results: After this exercise, you should have created a Blog menu item that opens a list MVC view named Index, which lists all of the blog entries.

5-40

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 2: Develop a Details MVC view


The main tasks for this exercise are as follows:

1. 2.

Add a strongly-typed details view named Details.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution from the following location. Location D:\Lab Files\CS\Lab 05\Starter\Exercise 02 D:\Lab Files\VB\Lab 05\Starter\Exercise 02

Programming Language Visual C# Visual Basic

Task 2: Add a strongly-typed details view named Details


1. 2. Add an empty, strongly-typed view of type Blog, named Details based on the Site.Master master page, to the Blog folder. Add the following markup and code to the Details view in the Content2 Content control, immediately after the h2 element.
Blogger: <%: Model.Blogger.Name %> DatePosted: <%: Model.DatePosted %> <h3> <%: Model.Title %></h3> <%: Model.BlogEntry %> <p> <%: Html.ActionLink("Back to List", "Index") %> </p>

3.

Verify that the markup and code in the Details view matches the following. [Visual C#]
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AdventureWorksMvc.Models.Blog>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Details </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Details</h2> Blogger: <%: Model.Blogger.Name %> DatePosted: <%: Model.DatePosted %> <h3> <%: Model.Title %></h3> <%: Model.BlogEntry %> <p> <%: Html.ActionLink("Back to List", "Index") %> </p> </asp:Content>

[Visual Basic]
<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of AdventureWorksMvc.Blog)" %>

Developing MVC Views

5-41

<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Details </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Details</h2> Blogger: <%: Model.Blogger.Name %> DatePosted: <%: Model.DatePosted %> <h3> <%: Model.Title %></h3> <%: Model.BlogEntry %> <p> <%: Html.ActionLink("Back to List", "Index") %> </p> </asp:Content>

4. 5. 6.

Test the Details view. Close Internet Explorer. Close Visual Studio 2010. Results: After this exercise, you should have created a new MVC view that shows the details about an individual blog entry.

5-42

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 3: Develop a Create MVC view


The main tasks for this exercise are as follows: 1. 2.
3.

Add a strongly-typed view named Blogger to list all of the blogs for a particular blogger. Add a strongly-typed view named Create. Use TempData to add a confirmation message to the Index view.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution from the following location. Location D:\Lab Files\CS\Lab 05\Starter\Exercise 03 D:\Lab Files\VB\Lab 05\Starter\Exercise 03

Programming Language Visual C# Visual Basic

Task 2: Add a strongly-typed view named Blogger to list all of the blogs for a particular
blogger
1. 2. Add an empty, strongly-typed view named Blogger based on the Site.Master master page, to the Blog folder. Update the Blogger view to a strongly-typed view of type IEnumerable of type Blog. [Visual C#]
System.Web.Mvc.ViewPage<IEnumerable<AdventureWorksMvc.Models.Blog>>

[Visual Basic]
System.Web.Mvc.ViewPage(Of IEnumerable (Of AdventureWorksMvc.Blog))

3.

Add the following markup and code to the Blogger view in the Content2 Content control, immediately after the h2 element. [Visual C#]
<% foreach (var item in Model) { %> <div> <%: Html.ActionLink("Edit", "Edit", new { id=item.BlogID })%> <%: Html.ActionLink("Delete", "Delete", new { id=item.BlogID })%> <%: item.DatePosted %> <%: item.Title %> </div> <% } %> <p> <%: Html.ActionLink("Create New", "Create") %> </p>

[Visual Basic]
<% For <div> <%: <%: <%: <%: Each item As AdventureWorksMvc.Blog In Model%> Html.ActionLink("Edit", "Edit", New With {.id = item.BlogID})%> Html.ActionLink("Delete", "Delete", New With {.id = item.BlogID})%> item.DatePosted %> item.Title %>

Developing MVC Views

5-43

</div> <% Next%> <p> <%: Html.ActionLink("Create New", "Create") %> </p>

Verify that the markup and code in the Blogger view matches the following. [Visual C#]
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<AdventureWorksMvc.Models.Blog>>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Blogger </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Blogger</h2> <% foreach (var item in Model) { %> <div> <%: Html.ActionLink("Edit", "Edit", new { id=item.BlogID })%> <%: Html.ActionLink("Delete", "Delete", new { id=item.BlogID })%> <%: item.DatePosted %> <%: item.Title %> </div> <% } %> <p> <%: Html.ActionLink("Create New", "Create") %> </p> </asp:Content>

[Visual Basic]
<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of IEnumerable (Of AdventureWorksMvc.Blog))" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Blogger </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Blogger</h2> <% For Each item As AdventureWorksMvc.Blog In Model%> <div> <%: Html.ActionLink("Edit", "Edit", New With {.id = item.BlogID})%> <%: Html.ActionLink("Delete", "Delete", New With {.id = item.BlogID})%> <%: item.DatePosted %> <%: item.Title %> </div> <% Next%> <p> <%: Html.ActionLink("Create New", "Create") %> </p> </asp:Content>

Task 3: Add a strongly-typed view named Create


1. Add an empty, strongly-typed view named Create based on the Site.Master master page, to the Blog folder.

5-44

Developing Web Applications with Microsoft Visual Studio 2010

2.

Add the following markup and code to the Create view in the Content2 Content control, immediately after the h2 element. [Visual C#]
<% using (Html.BeginForm()) {%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(model => model.Title) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Title) %> <%: Html.ValidationMessageFor(model => model.Title) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.BlogEntry) %> </div> <div class="editor-field"> <%: Html.TextAreaFor(model => model.BlogEntry, new { cols = "85" })%> <%: Html.ValidationMessageFor(model => model.BlogEntry) %> </div> </fieldset> <input type="submit" value="Submit" /> <% } %> <div> <%: Html.ActionLink("Back to List", "Blogger") %> </div>

[Visual Basic]
<% Using (Html.BeginForm())%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(Function(m) m.Title)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(m) m.Title)%> <%: Html.ValidationMessageFor(Function(m) m.Title)%> </div> <div class="editor-label"> <%: Html.LabelFor(Function(m) m.BlogEntry)%> </div> <div class="editor-field"> <%: Html.TextAreaFor(Function(m) m.BlogEntry, New With {.cols = "85"})%> <%: Html.ValidationMessageFor(Function(m) m.BlogEntry)%> </div> </fieldset> <input type="submit" value="Submit" /> <% End Using%> <div> <%: Html.ActionLink("Back to List", "Blogger") %> </div>

3.

Verify that the markup and code in the Create view matches the following. [Visual C#]
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AdventureWorksMvc.Models.Blog>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">

Developing MVC Views

5-45

Create </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Create</h2> <% using (Html.BeginForm()) {%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(model => model.Title) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Title) %> <%: Html.ValidationMessageFor(model => model.Title) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.BlogEntry) %> </div> <div class="editor-field"> <%: Html.TextAreaFor(model => model.BlogEntry, new { cols = "85" })%> <%: Html.ValidationMessageFor(model => model.BlogEntry) %> </div> </fieldset> <input type="submit" value="Submit" /> <% } %> <div> <%: Html.ActionLink("Back to List", "Blogger") %> </div> </asp:Content>

[Visual Basic]
<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of AdventureWorksMvc.Blog)" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Create </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Create</h2> <% Using (Html.BeginForm())%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(Function(m) m.Title)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(m) m.Title)%> <%: Html.ValidationMessageFor(Function(m) m.Title)%> </div> <div class="editor-label"> <%: Html.LabelFor(Function(m) m.BlogEntry)%> </div> <div class="editor-field"> <%: Html.TextAreaFor(Function(m) m.BlogEntry, New With {.cols = "85"})%> <%: Html.ValidationMessageFor(Function(m) m.BlogEntry)%> </div> </fieldset> <input type="submit" value="Submit" /> <% End Using%> <div>

5-46

Developing Web Applications with Microsoft Visual Studio 2010

<%: Html.ActionLink("Back to List", "Blogger") %> </div> </asp:Content>

4. 5. 6. 7.

Run the application. Navigate directly to the Blogger view by using the following route.
blog/blogger/1

Add a blog entry. Close Internet Explorer.

Task 4: Use TempData to add a confirmation message to the Index view


1. 2. Open the Index view. Add the following markup and code to the Index view, right below the h2 element. [Visual C#]
<% if (TempData["ConfirmationMessage"] != null) { %> <div class="message"> <%: TempData["ConfirmationMessage"]%> </div> <% } %>

[Visual Basic]
<% If Not TempData("ConfirmationMessage") Is Nothing Then%> <div class="message"> <%: TempData("ConfirmationMessage")%> </div> <% End If%>

3.

Verify that the markup and code in the Index view matches the following. [Visual C#]
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<AdventureWorksMvc.Models.Blog>>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Index </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Index</h2> <% if (TempData["ConfirmationMessage"] != null) { %> <div class="message"> <%: TempData["ConfirmationMessage"]%> </div> <% } %> <% foreach (var item in Model) { %> <div> <%: Html.ActionLink("Details", "Details", new { id=item.BlogID })%> <%: item.DatePosted %> <%: item.Title %> </div> <% } %> </asp:Content>

Developing MVC Views

5-47

<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of IEnumerable (Of AdventureWorksMvc.Blog))" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Index </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Index</h2> <% If Not TempData("ConfirmationMessage") Is Nothing Then%> <div class="message"> <%: TempData("ConfirmationMessage")%> </div> <% End If%> <% For Each item As AdventureWorksMvc.Blog In Model%> <div> <%: Html.ActionLink("Details", "Details", New With {.id = item.BlogID})%> <%: item.DatePosted %> <%: item.Title %> </div> <% Next%> </asp:Content>

4. 5. 6. 7. 8.

Run the application. Navigate directly to the Blogger view by using the following route.
/blog/blogger/1

Add another blog entry. Close Internet Explorer. Close Visual Studio 2010. Results: After this exercise, you should have created two new MVC views. The first new view lists all of the blog entries for a particular blogger and the second new view allows you to create new blog entries.

5-48

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 4: Develop an Edit MVC view


The main tasks for this exercise are as follows:
1. 2. 3. 4.

Create a partial view named Blog. Create an edit view named Edit, which uses the Blog partial view. Edit a blog entry. Update the Create view to use the Blog partial view.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution from the following location. Location D:\Lab Files\CS\Lab 05\Starter\Exercise 04 D:\Lab Files\VB\Lab 05\Starter\Exercise 04

Programming Language Visual C# Visual Basic

Task 2: Create a partial view named Blog


1. 2. Add an empty, strongly-typed partial view of type Blog, named Blog, to the Blog folder. Copy all of the markup and code from the Content2 Content element in the Create view to the partial Blog view. [Visual C#]
<% using (Html.BeginForm()) {%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(model => model.Title) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Title) %> <%: Html.ValidationMessageFor(model => model.Title) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.BlogEntry) %> </div> <div class="editor-field"> <%: Html.TextAreaFor(model => model.BlogEntry, new { cols = "85" })%> <%: Html.ValidationMessageFor(model => model.BlogEntry) %> </div> </fieldset> <input type="submit" value="Submit" /> <% } %> <div> <%: Html.ActionLink("Back to List", "Blogger") %> <div>

[Visual Basic]
<% Using (Html.BeginForm())%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label">

Developing MVC Views

5-49

<%: Html.LabelFor(Function(m) m.Title)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(m) m.Title)%> <%: Html.ValidationMessageFor(Function(m) m.Title)%> </div> <div class="editor-label"> <%: Html.LabelFor(Function(m) m.BlogEntry)%> </div> <div class="editor-field"> <%: Html.TextAreaFor(Function(m) m.BlogEntry, New With {.cols = "85"})%> <%: Html.ValidationMessageFor(Function(m) m.BlogEntry)%> </div> </fieldset> <input type="submit" value="Submit" /> <% End Using%> <div> <%: Html.ActionLink("Back to List", "Blogger") %> </div>

3.

Verify that the markup and code in the partial Blog view matches the following. [Visual C#]
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<AdventureWorksMvc.Models.Blog>" %> <% using (Html.BeginForm()) {%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(model => model.Title) %> </div> <div class="editor-field"> <%: Html.TextBoxFor(model => model.Title) %> <%: Html.ValidationMessageFor(model => model.Title) %> </div> <div class="editor-label"> <%: Html.LabelFor(model => model.BlogEntry) %> </div> <div class="editor-field"> <%: Html.TextAreaFor(model => model.BlogEntry, new { cols = "85" })%> <%: Html.ValidationMessageFor(model => model.BlogEntry) %> </div> </fieldset> <input type="submit" value="Submit" /> <% } %> <div> <%: Html.ActionLink("Back to List", "Blogger") %> </div>

[Visual Basic]
<%@ Control Language="VB" Inherits="System.Web.Mvc.ViewUserControl(Of AdventureWorksMvc.Blog)" %> <% Using (Html.BeginForm())%> <%: Html.ValidationSummary(true) %> <fieldset> <legend>Fields</legend> <div class="editor-label"> <%: Html.LabelFor(Function(m) m.Title)%> </div> <div class="editor-field"> <%: Html.TextBoxFor(Function(m) m.Title)%> <%: Html.ValidationMessageFor(Function(m) m.Title)%>

5-50

Developing Web Applications with Microsoft Visual Studio 2010

</div> <div class="editor-label"> <%: Html.LabelFor(Function(m) m.BlogEntry)%> </div> <div class="editor-field"> <%: Html.TextAreaFor(Function(m) m.BlogEntry, New With {.cols = "85"})%> <%: Html.ValidationMessageFor(Function(m) m.BlogEntry)%> </div> </fieldset> <input type="submit" value="Submit" /> <% End Using%> <div> <%: Html.ActionLink("Back to List", "Blogger") %> </div>

Task 3: Create an edit view, named Edit, that uses the Blog partial view
1. 2. Add an empty, strongly-typed view of type Blog, named Edit, based on the Site.Master master page, to the Blog folder. Add the following markup and code to the Edit view in the Content2 Content control, immediately after the h2 element. [Visual C#]
<% Html.RenderPartial("Blog"); %>

[Visual Basic]
<% Html.RenderPartial("Blog") %>

3.

Verify that the markup and code in the Edit view matches the following. [Visual C#]
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AdventureWorksMvc.Models.Blog>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Edit </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Edit</h2> <% Html.RenderPartial("Blog"); %> </asp:Content>

[Visual Basic]
<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of AdventureWorksMvc.Blog)" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Edit </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Edit</h2> <% Html.RenderPartial("Blog")%> </asp:Content>

Task 4: Edit a blog entry


1. 2. Run the application. Navigate directly to the Blogger view by using the following route.

Developing MVC Views

5-51

blog/blogger/1

3. 4.

Edit a blog entry. Close Internet Explorer.

Task 5: Update the Create view to use the Blog partial view.
1. Replace the markup and code after the h2 element in the Content2 Content element in the Create view with the following. [Visual C#]
<% Html.RenderPartial("Blog"); %>

[Visual Basic]
<% Html.RenderPartial("Blog") %>

2.

Verify that the markup and code in the Create view matches the following. [Visual C#]
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AdventureWorksMvc.Models.Blog>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Create </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Create</h2> <% Html.RenderPartial("Blog"); %> </asp:Content>

[Visual Basic]
<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of AdventureWorksMvc.Blog)" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Create </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Create</h2> <% Html.RenderPartial("Blog")%> </asp:Content>

3. 4. 5. 6. 7.

Run the application. Navigate directly to the Blogger view by using the following route.
blog/blogger/1

Add another blog entry. Close Internet Explorer. Close Visual Studio 2010. Results: After this exercise, you should have created a partial view that is used by both the Edit view and the Create view.

5-52

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 5: Develop a Delete MVC view


The main tasks for this exercise are as follows:
1. 2.

Add a strongly-typed view named Delete that uses the default markup provided by the Add View dialog box. Delete a blog entry.

Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorksMvc solution from the following location. Location D:\Lab Files\CS\Lab 05\Starter\Exercise 05 D:\Lab Files\VB\Lab 05\Starter\Exercise 05

Programming Language Visual C# Visual Basic

Task 2: Add a strongly-typed view named Delete that uses the default markup provided
by the Add View dialog box
1. 2. 3. 4. Build the solution. Add a delete, strongly-typed view of type Blog, named Delete, based on the Site.Master master page, to the Blog folder. The view should use the default content supplied for a Delete operation. Update the markup and code that renders the Back to List link to match the following.
<%: Html.ActionLink("Back to List", "Blogger") %>

Verify that the markup and code in the Delete view matches the following. [Visual C#]
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<AdventureWorksMvc.Models.Blog>" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Delete </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Delete</h2> <h3> Are you sure you want to delete this?</h3> <fieldset> <legend>Fields</legend> <div class="display-label"> BlogID</div> <div class="display-field"> <%: Model.BlogID %></div> <div class="display-label"> BloggerID</div> <div class="display-field"> <%: Model.BloggerID %></div> <div class="display-label"> DatePosted</div> <div class="display-field"> <%: String.Format("{0:g}", Model.DatePosted) %></div> <div class="display-label"> Title</div> <div class="display-field">

Developing MVC Views

5-53

<%: Model.Title %></div> <div class="display-label"> BlogEntry</div> <div class="display-field"> <%: Model.BlogEntry %></div> </fieldset> <% using (Html.BeginForm()) { %> <p> <input type="submit" value="Delete" /> | <%: Html.ActionLink("Back to List", "Blogger") %> </p> <% } %> </asp:Content>

[Visual Basic]
<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage(Of AdventureWorksMvc.Blog)" %> <asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server"> Delete </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> <h2> Delete</h2> <h3> Are you sure you want to delete this?</h3> <fieldset> <legend>Fields</legend> <div class="display-label"> BlogID</div> <div class="display-field"> <%: Model.BlogID %></div> <div class="display-label"> BloggerID</div> <div class="display-field"> <%: Model.BloggerID %></div> <div class="display-label"> DatePosted</div> <div class="display-field"> <%: String.Format("{0:g}", Model.DatePosted) %></div> <div class="display-label"> Title</div> <div class="display-field"> <%: Model.Title %></div> <div class="display-label"> BlogEntry</div> <div class="display-field"> <%: Model.BlogEntry %></div> </fieldset> <% Using Html.BeginForm()%> <p> <input type="submit" value="Delete" /> | <%: Html.ActionLink("Back to List", "Blogger") %> </p> <% End Using%> </asp:Content>

Task 3: Delete a blog entry


1. Run the application.

5-54

Developing Web Applications with Microsoft Visual Studio 2010

2. 3. 4. 5.

Navigate directly to the Blogger view by using the following route.


blog/blogger/1

Select a blog entry. Close Internet Explorer. Close Visual Studio 2010.

Task 4: Turn off the virtual machine and revert the changes
1. 2. 3. 4. In Microsoft Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert. In the Revert Virtual Machine dialog box, click Revert. Results: After this exercise, you should have created an MVC view to delete blog entries.

Developing MVC Views

5-55

Module Review and Takeaways

Review Questions
Question: What are the advantages of using the ASP.NET MVC framework? Question: Where can the view associated with the Sample action method of the Home controller be located? Question: In which type of file does a partial view store its markup? Question: Which views are created by the Add View dialog box? Question: What are the advantages of using strongly-typed views?

Real-world Issues and Scenarios


One issue with ASP.NET MVC is that it is still an evolving technology.

Best Practices Related to a Particular Technology Area in This Module


Make sure that your view does not include any logic. The view is supposed to be dumb. By default, ASP.NET MVC uses the Web Forms view engine. However, many developers opt to use a different view engine, such as Spark or NVelocity. Use strongly-typed views. Whenever you receive data from the user, always use Html.Encode to encode the data before you display it in a view.

5-56

Developing Web Applications with Microsoft Visual Studio 2010

Designing for Discoverability

6-1

Module 6
Designing for Discoverability
Contents:
Lesson 1: Search Engine Optimization Lesson 2: Discoverability Files Lesson 3: Using ASP.NET Routing Lab 6: Designing for Discoverability 6-3 6-12 6-22 6-43

6-2

Developing Web Applications with Microsoft Visual Studio 2010

Module Overview

Search engines play a critical role in directing traffic to websites. It is extremely important that a website is not only indexed by popular search engines, but also highly ranked in relevant query results. Higher query result rankings will lead directly to more traffic, which will deliver the websites services and content to a wider audience. This module will introduce you to techniques and strategies that are available to increase the discoverability of a website. Topics include what search engine optimization is, how the ASP.NET 4.0 Framework makes it easier to perform search engine optimization, and what should and should not be done to increase the discoverability of a website.

Designing for Discoverability

6-3

Lesson 1

Search Engine Optimization

Search engine optimization (SEO) is the process of improving the volume or quality of traffic to a website from search engines through algorithmic search results. SEO should not be confused with search engine marketing (SEM) which is the process of improving the volume or quality of traffic to a website from search engines through paid search results. Optimizing a website includes modifying its HTML, URLs, and files to increase their relevance to specific keywords and to remove barriers to the indexing activities of search engines.

Lesson Objectives:
After completing this lesson, you will be able to: Explain what Search Engine Optimization is. Describe the features of the IIS SEO Toolkit. Analyze a website by using the IIS SEO Toolkit.

6-4

Developing Web Applications with Microsoft Visual Studio 2010

Overview of Search Engine Optimization

Typically, the earlier a website appears in the search results list, the more visitors it will receive from the search engine. SEO may target different kinds of search. Simple but important changes to the content of your website, such as its HTML and URLs, can dramatically increase the page ranking. Also, there are certain strategies and activities that should be avoided to ensure that your page ranking is not degraded. Microsoft ASP.NET, Visual Studio 2010, and IIS 7.0 make it easier than ever to implement SEO strategies.

HTML
Search engine results are predicated on indexed HTML. Erroneous HTML can be misinterpreted or even skipped. If a page features too much erroneous HTML, the search engine may deem the entire website invalid. Visual Studio 2010 includes HTML IntelliSense code snippets to make it easier to author HTML tags and server-side controls. Visual Studio 2010 also includes HTML validation to warn developers of erroneous HTML that maybe present. Search engines are limited to text-based content. Artifacts such as images, music, or video cannot be directly interpreted by a search engine. It is critical to provide the search engines with descriptive markup for these artifacts. The alt attribute is one of the most common ways to provide the search engines information about an image. There is an order of prescience to each logical piece of content in an HTML page. Content inside an h1 element or page title are deemed more important by a search engine than the content inside a label or paragraph. It is important to ensure that consideration is given to every element of an HTML document, not just the elements that are rendered by a browser. Following is a list of best practices that will ensure that search engines properly interoperate and index your page.

Uniform Resource Locators


Uniform Resource Locators (URLs) specify where content of your website is available. Through routing, URLs can provide search engines with descriptions of the content they specify. Following are hypothetical examples of two URLs that direct to the same content.

Designing for Discoverability

6-5

http://www.microsoft.com?product=visualstudio&edition=2010 http://www.microsoft.com/visualstudio2010

The first URL is cryptic and hard to read. The search engines will place the same value to the query string field product as for the query string parameter visualstudio. The second URL is much easier to read and only contains words relevant to the content it displays. A search query result on Visual Studio 2010 would return the second URL before the first URL, based purely on structure. Canonical URLs often give search engines problems.
www.example.com www.example.com/default.aspx example.com example.com/default.asp

The preceding URLs provided are literally different URLs in the sense of the letters and symbols they use. They are logically the same URL in terms of the content to which they point. Search engines will recognize this discrepancy and assign an unfavorable search engine ranking. To eliminate this problem, one URL must be deemed the preferred or canonical URL, and the others must be deemed subordinate or standard URLs. This distinction can be made by redirecting traffic to the canonical URL through the Application_BeginRequest method in the Global.asax file, or a custom HTTP module. Ultimately, redirecting standard URLs to the canonical URL will consolidate and improve search engine rankings.

Anti-patterns
Search engines want to provide their users with relevant and timely results. If the results they return are irrelevant, users will no longer use their service. To ensure their results are accurate, search engines penalize pages for inaccurately representing your content. Keyword stuffing is the practice of excessively including the same keywords in your Meta, Comment, and Alt tags. Hidden Texts or Links is the practice of inserting hidden text or links that are not rendered by the browser but indexed by the search engines. Cloaking is the practice of using a software program to direct search spiders to a group of pages specifically created to trick the spider yet redirect the user to a different set of pages. Both Hidden Texts and Links do not diminish the experience of the user. These practices will negatively impact your search engine ranking and prevent new traffic from reaching your content. Question: When estimating the effort to complete a site, do you typically include SEO (search engine optimization) items? Question: In which activities have you participated to increase a websites search ranking? Question: How did traffic patterns change after you completed SEO activities?

6-6

Developing Web Applications with Microsoft Visual Studio 2010

Components of the IIS SEO Toolkit

Key Points
The IIS Search Engine Optimization (SEO) Toolkit helps web developers, hosting providers, and web server administrators to improve their websites relevance in search results by recommending how to make the site content more search engine-friendly. The IIS SEO Toolkit includes the Site Analysis module, the Robots Exclusion module, and the Sitemaps and Site Indexes module, which allows you to perform detailed analysis and offers recommendations and editing tools for managing your robots and sitemaps files.

Site Analysis
The Site Analysis module is used for analyzing local and external websites to help optimize the structure, content, and the URLs of a website to make the website friendlier to search engine crawlers. The Site Analysis module can also be used for finding common issues with the site content; issues that can affect the user experience. The module comes with many pre-built reports, used for analyzing compliance with SEO recommendations and to find issues, including broken links and performance issues.

Robots Exclusion
The Robots Exclusion module can be used from IIS Manager to manage the robots.txt file. It is possible to view sites using both a physical and a logical hierarchal view. True to the purpose of the robots.txt file, it is possible to exclude files or folders from being searched and indexed.

Sitemap and Site Index


The Sitemaps and Site Indexes module is used to manage the sitemap files and sitemap indexes, to ensure that search engines ar kept up to date. This can be done at the site, application, or folder level. From the Sitemaps and Site Indexes module you can list the important URLs to and rank them in the sitemap.xml file, and ensure that no broken links are listed.

Designing for Discoverability

6-7

Installation
The Microsoft Web Platform Installer 2.0 (Web PI) is a free tool that makes getting the latest components of the Microsoft Web Platform, including IIS Search Engine Optimization Toolkit. Web PI can be downloaded directly from the www.microsoft.com/ website. Once the Microsoft Web Platform Installer 2.0 (Web PI) is installed, simply navigate to the IIS SEO Toolkit download page and use the green Install Now button. Question: Have you encountered a website that did not have an accurate robots.txt file? What mistakes were made? Did traffic improve once the robots.txt file was fixed? Question: Have you encountered a website that did not have an accurate sitemap.xml file? If so, how did it impact your use and perception of the website?

6-8

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Analyzing a Website by Using the IIS SEO Toolkit

In this demonstration, you will see how to analyze a website by using the Site Analysis tool in the IIS SEO Toolkit, and interpret the report that is generated.

Crawling a Website
1. Open IIS SEO Toolkit. a. b. 2. 3. On the Start menu, point to All Programs, expand IIS 7.0 Extensions, right-click Search Engine Optimization (SEO) Toolkit 1.0, and then click Run as Administrator. In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then click Yes.

In Internet Information Services (IIS) Manager, in the right pane, in the Site Analysis section, click Create a new analysis. In the New Analysis dialog box, in the Name box, type Default Web Site analysis, in the Start URL box, type http://localhost, and then click OK.

Note: It is possible to crawl any website that is publicly accessible on the Internet.

The New Analysis Dialog Box


Advanced Settings Maximum Number of Links: Controls the number of unique links to be processed and downloaded from a website during a crawl. A link is any URL that is used within a pages markup, including hyperlinks, references to image files, CSS files, and java script files. Increasing this number increases the size of the reports file, and makes the crawling process run longer.

Designing for Discoverability

6-9

Maximum Download Size per Link: Controls the number of kilobytes of content to be downloaded per link. Increasing this number increases the size of the cached content stored by Site Analysis on the local file system. Ignore 'nofollow' attribute: The nofollow attribute and the nofollow meta tag are used to tell search engine crawlers not to follow certain or all hyperlinks in the page. This is a means of protection against spam in blog comments. If pages on your site use this attribute, the hyperlinks on those pages will not be processed or analyzed during site analysis. However, links to resources such as images, CSS, and java script files will still be processed. If it is necessary to analyze the hyperlinks that use this attribute, use this setting to ignore the nofollow attributes and meta tags. Ignore 'noindex' meta tag: - Used to tell search engine crawlers not to index the content of the page. If pages on your site use this meta tag, the content of those pages will not be searched for any violations. If it is necessary to analyze even the pages that use this attribute, use this setting to ignore the noindex meta tag. External Links: Use this drop-down list when your website has sub-domains, or when you want to run an analysis on a particular directory within a site. This setting controls whether sub-domains and/or subdirectories should be treated as external or internal links. Edit Feature Settings Maximum Number of Concurrent Requests: Controls the number of concurrent requests the web crawler will make. Reports Directory: Specifies the directory on the local file system where all crawled data and cached website content is stored. Note: Two numbers are reported during analysis. Links Processed: The total number of links that have been crawled and downloaded by the web crawler. Total Links: The total number of links found while crawling the website.

Interpreting the Site Analysis Report


In Internet Information Services (IIS) Manager, in the Site Analysis Report section, you can view a number of pages with report details. To get to the Site Analysis Report section, follow these steps. 1. Open IIS SEO Toolkit. a. b. 2. 3. On the Start menu, point to All Programs, expand IIS 7.0 Extensions, right-click Search Engine Optimization (SEO) Toolkit, and then click Run as Administrator. In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then click Yes.

In Internet Information Services (IIS) Manager, in the right pane, in the Site Analysis section, click View existing reports. In the Site Analysis pane, you can double-click any of the reports listed.

Note: In the Site Analysis Report section, you can use the vertically placed tabs on the left of the Dashboard to get to the following information.

6-10

Developing Web Applications with Microsoft Visual Studio 2010

Summary Page
The site analysis summary page provides an overview of all SEO-related violations and problems found on the analyzed website. In addition, it contains a large set of pre-built reports about your site content and structure. You can drill down into each individual item in the report by double-clicking it, or by using the View Group Details command in the context menu. To open a particular report in a separate query page, use the Open Query context menu command.

Query Page
Opening any of the pre-built reports from the summary page will result in a new query page. The query page is used to issue queries against the site analysis data that was collected during the crawl of the website. In the preceding screenshot, the query is used to get all the pages that reference images without specifying an alt attribute within the img HTML element. You can perform a set of actions, accessible from the context menu, for each item within the query results pane. The following actions are as follows: View Details: This option opens a dialog box, which can be used to obtain detailed information about the item. Specifically, you can see the violation details and suggested corrective actions. In addition, the actual response data is available if you need to investigate the causes of the reported violation further. For example, if you want to find out where in the response HTML this violation occurred, choose the Content tab. This opens the response content with the offending section of the markup highlighted. View in Browser: If you right-click a URL, you can select View in Browser from the context menu to show the URL in the browser. View Pages Linking to This Page: If you right-click a URL, you can also select View Pages Linking to This Page. This option opens a new query page that shows all the pages on the site that reference the URL for the selected item. This kind of report is useful when you want to find out which pages may be affected if you change a particular URL on your site. View Pages Linked by This Page: This option opens a new query page that shows all the URLs and resources that the HTML markup for the currently selected URL references. View Violations in This Page: This option opens a new query page that shows all the violations found on the page of the selected URL. View in Hierarchy: This option opens a hierarchy view page that consists of the following parts: URLs of all pages that lead to the selected page. The URL of the selected page. URLs of all the resources and pages referenced by the selected page.

View Routes to this Page: This option opens a new page that displays the 5 shortest unique routes from the analysis start page to the currently selected page. Each route is shown with the start page at the bottom and each subsequent page above, with the selected page on top. This report can be used to analyze how visitors can get to a particular page on your website, and whether there any unnecessary pages that can be eliminated for users to discover the selected page more easily.

Designing for Discoverability

6-11

Word Analysis: This feature can be used to get an idea of the most commonly used words in a pages content. These can be used as keywords for accurately describing the web page content for search engines. The most often used words within a page will be displayed, which can give you an idea of which keywords to choose for this page. In addition, the texts of links that reference this page are listed at the bottom of the dialog box. This helps you to check whether the anchor text used within those links accurately describes the content of the page. Question: When would be the ideal timeframe in a project to run the Site Analysis Tool? Question: What feature of the report can be used to avoid production issues proactively?

6-12

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 2

Discoverability Files

The Robot Exclusion Standard, also known as the Robots Exclusion Protocol or robots.txt protocol, is a convention to prevent cooperating web spiders and other web robots from accessing all or part of a website that is otherwise publicly viewable. The Sitemaps protocol allows a webmaster to inform search engines about URLs on a website that are available for crawling.

Lesson Objectives:
After completing this lesson, you will be able to: Create robots and sitemap files. Explain what robot files are. Explain what sitemap files are.

Designing for Discoverability

6-13

What are Robots Files?

Robots files are used to prevent cooperating web spiders or crawlers from accessing all or part of a website. A web crawler or spider is a computer program that captures data on the Internet in a structured and automated manner, which is used by search engines to display results when queried. Essentially, a robots.txt file on a website is a request to have specified robots ignore specified files or directories in their search. This allows websites to pilot or test content before a web spider indexes it.

Disadvantages
The robots.txt files are purely advisory. They are predicated on the cooperation of the web spider to adhere to the requests they are making. The robots.txt file does not guarantee privacy or explicitly block web crawlers. If not properly installed, a robots.txt file can keep search engines from indexing the most important content of a website. In severe cases, search engines may skip the site entirely. It is important to ensure that the areas you want to have indexed are not blocked by your robots.txt file.

Demonstrate how to Create a Robots File


Web spiders or web search engines, such as Bing, crawl or search the Internet to index the pages on servers. The crawled information is cataloged and made publicly available for searching. This allows users to easily and quickly access the various information published on the web. In addition to cataloging the crawled information, the web spiders prioritize the documents or pages, which means giving a search result a score or ranking. This helps arrange the search results in an order of most likely matches for a search. Web spider is also known as a robot, and when accessing a site, the robot is identified as User-agent.

Syntax Examples
The following are examples of what you can put in your robots.txt file to ensure the right content, and only the right content is searched and cataloged or indexed Allow ALL robots to visit ALL files:

6-14

Developing Web Applications with Microsoft Visual Studio 2010

User-agent: * Allow: /

Disallow ALL robots to visit ALL files:


User-agent: *

Disallow ALL robots to visit SPECIFIED directories:


User-agent: * Disallow: /privateDirectoryOne/ Disallow: /privateDirectoryTwo/ Disallow: /privateDirectoryThree/

Disallow ALL robots to visit SPECIFIED directories:


User-agent: * Disallow: /private/

Disallow SPECIFIED robots to visit SPECIFIED directories:


User-agent: RobotOne Disallow: /private/

Question: Have you ever piloted or tested content in a production environment that you did not want a search engine to index? Question: What are some disadvantages of allowing web crawlers to index content that is not ready for production?

Designing for Discoverability

6-15

Demonstration: Creating a Robots File

In this demonstration, you will see how to create a robots.txt file. 1. Open Internet Information Services (IIS) Manager as an administrator. a. b. c. 2. 3. On the Start menu, click Control Panel. In Control Panel, click System and Security, and then click Administrative Tools. Right-click Internet Information Services (IIS) Manager, and then click Run as administrator.

In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then press ENTER. Select the Default Website. In the Connections pane, expand 10264A-GEN-DEV (10264A-GEN-DEV\Admin), expand Sites, and then click Default Web Site.

4.

Open the Search Engine Optimization feature. In Internet Information Services (IIS) Manager, in the middle pane, in the Management section, double-click Search Engine Optimization.

5.

View existing rules. In the Search Engine Optimization pane, in the Robots Exclusion section, click View existing rules.

Note: Currently there are no rules, and there is no robots.txt file. 6. Add a sitemap file. a. In the Actions pane, in the Sitemap Locations section, click Add Sitemaps.

6-16

Developing Web Applications with Microsoft Visual Studio 2010

b.

In the Add Sitemaps dialog box, in the URL Paths list, select the Default Web Site, and then click OK.

Note: Currently there are is no sitemap file, but this action will create the robots.txt file. 7. Open the robots.txt file. In the Actions pane, in the Robots section, click Open Robots.txt File.

Note: The robots.txt file is opened in Notepad. Currently, it holds only a reference to the sitemap at the default location for the default website. Following are examples of what you can add to a robots.txt file. This example disallows all web spiders for the entire site:
# Make changes for all web spiders User-agent: * Disallow: /

The following example disallows a robot named WebSpider from the virtual paths /marketing and /sales:
# Tell "WebSpider" where it can't go User-agent: WebSpider Disallow: /marketing Disallow: /sales # Allow all other robots to browse everywhere User-agent: * Disallow:

This example allows only a web spider named SpiderOne into a site, while denying all other spiders:
# Allow "SpiderOne" in the site User-agent: SpiderOne Disallow: # Deny all other spiders User-agent: * Disallow: /

This last example disallows FrontPage-related paths in the root of your website:
# Ignore FrontPage files User-agent: * Disallow: /_borders Disallow: /_derived Disallow: /_fpclass Disallow: /_overlay Disallow: /_private Disallow: /_themes Disallow: /_vti_bin Disallow: /_vti_cnf Disallow: /_vti_log Disallow: /_vti_map Disallow: /_vti_pvt Disallow: /_vti_txt

8.

Close Notepad. In the robots.txt - Notepad window, click the Close button.

Designing for Discoverability

6-17

9.

Close Internet Information Services (IIS) Manager. In the Internet Information Services (IIS) Manager window, click the Close button.

10. Close Administrative Tools. In the Control Panel\System and Security\Administrative Tools window, click the Close button.

11. Close System and Security. In the Control Panel\System and Security window, click the Close button.

6-18

Developing Web Applications with Microsoft Visual Studio 2010

What is the Sitemap File?

A sitemap file informs search engines about URLs on a website that are available for crawling. A sitemap file also contains information about when a URL last updated, how often it changes, and what role it plays within the hierarchy of the website. The sitemap files most basic function is to allow web crawlers to index the site more efficiently.

Sitemap Elements
<urlset>

Required document-level element for the Sitemap, the rest of the document after the <?xml version> element must be contained in this.
<url>

Required parent element for each entry; the remaining elements are children of element.
<loc>

Required element of the full URL of the page, including the protocol (e.g. http, https) and a trailing slash, if required by the site's hosting server, this value must be less than 2,048 characters.
<lastmod>

Optional element date that the file was last modified, in ISO 8601 format. This can display the full date and time or, if desired, may simply be the date in the format YYYY-MM-DD.
<changefreq>

Optional element that displays how frequently the page may be modified. The values always, hourly, daily, weekly, monthly, yearly and never may be used with this element.

Designing for Discoverability

6-19

<priority>

Optional element that displays the priority of the URL relative to other URLs on the site:

Syntax Example
<?xml version='1.0' encoding='UTF-8'?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"> <url> <loc>http://example.com/</loc> <lastmod>2010-01-01</lastmod> <changefreq>daily</changefreq> <priority>0.5</priority> </url> </urlset>

Disadvantages
Sitemap files are not compatible with all web frameworks. Web 2.0 frameworks, such as Silverlight or Adobe Flash, are examples of incompatible frameworks. These technologies are not consumed by search engines in the same manner. Sitemap files also do not stop web crawlers from discovering URLs that are not contained in the file. Think of a sitemap as a table of contents that may or may not be complete. Incomplete or inaccurate sitemaps can cause content to be misinterpreted or skipped entirely. Question: When do you usually install a sitemap file?

6-20

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Creating a Sitemap File

In this demonstration, you will see how to create a sitemap file by using the IIS SEO Toolkit extensions.

Creating a Sitemap File


1. Open Internet Information Services (IIS) Manager as an administrator. 2. 3. 4. 5. On the Start menu, click Control Panel.

In Control Panel, click System and Security, and then click Administrative Tools. Right-click Internet Information Services (IIS) Manager, and then click Run as administrator. In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then press ENTER. Open the Search Engine Optimization feature. In the right pane, in the Management Group section, double-click Search Engine Optimization.

6.

Create a new sitemap for the default website, in a file named Sitemap.xml. Set the change frequency to daily, do not record the last modified date and time, and set the priority to 1. a. b. c. d. In the Search Engine Optimization pane, in the Sitemaps and Sitemap Indexes section, click Create a new sitemap. In the Choose Site dialog box, in the Site list, click Default Web Site, and then click OK. In the Add Sitemap dialog box, in the File Name box, type Sitemap.xml, and then click OK. In the Add URLs dialog box, in the URL Paths list, click Default Web Site, and then click OK.

7.

Close Internet Information Services (IIS) Manager. In the Internet Information Services (IIS) Manager window, click the Close button.

8.

Close Administrative Tools.

Designing for Discoverability

6-21

9.

In the Control Panel\System and Security\Administrative Tools window, click the Close button.

Close System and Security. In the Control Panel\System and Security window, click the Close button.

6-22

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 3

Using ASP.NET Routing

ASP.NET routing enables you to use URLs that do not have to map to specific files in a website. Because the URL does not have to map to a file, you can use URLs in a web application that are descriptive of the user's action and therefore more easily understood by users.

Lesson Objective(s):
After completing this lesson, you will be able to: Use ASP.NET routing with Web Forms pages. Use ASP.NET routing with MVC pages. Explain how ASP.NET routing works. Create custom routes. Create route constraints.

Designing for Discoverability

6-23

How ASP.NET Routing Works

A route or URL pattern is mapped to a handler, which can be a physical file or a class. ASP.NET Web Forms have long been using the concept of making a physical file, such as an .aspx file, directly available for requests. In MVC applications, the handler is a class used to process the request. The class is commonly known as the controller. With the advent of ASP.NET 4.0, Web Forms applications can also use the routing known from MVC. The concept of routing means to configure an application to accept a request that do not map directly to a physical file. When you define URL patterns or routes, these are generally meaningful to users, and they can help with search-engine optimization (SEO). The following example code shows an example of a route for the ASP.NET Web Forms page Customers.aspx. This page displays users grouped by state.
http://localhost/customers.aspx?state=WA

If you have routing set up and configured, your application can accept the following request to respond with the very same information:
http://localhost/customers/WA

When you define a route in your application, you need to create an instance of the Route class. The class accepts a URL pattern, a handler, and the name of the route. The name is optional. Question: What are the advantages of using routed URLs over standard URLs?

6-24

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Using ASP.NET Routing with Web Forms Pages

1.

Open Microsoft Visual Studio 2010. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

2.

Open the WebFormsRouting solution at the following location. Programming Language Visual C# Visual Basic a. b. Location D:\Demofiles\CS D:\Demofiles\VB

In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project, or press CTRL+SHIFT+O. In the Open Project dialog box, in the File name box, type D:\Demofiles\CS\WebFormsRouting.sln or D:\Demofiles\VB\WebFormsRouting.sln and then click Open.

3.

Add reference to the System.Web.Routing assembly. a. b. c. In Solution Explorer, right-click WebFormsRouting, and then click Add Reference. In the Add Reference dialog box, click .NET. In the list, click System.Web.Routing, and then click OK.

4.

Open the Global.asax file. In Solution Explorer, double-click Global.asax.

5.

Import the System.Web.Routing namespace in the Global.asax code file. At the top of the Global.asax.cs or Global.asax.vb code file, add the following code.

Designing for Discoverability

6-25

[Visual C#]
using System.Web.Routing;

[Visual Basic] Imports System.Web.Routing

6.

Add a RegisterRoutes method as shown to the Global class. [Visual C#]


void RegisterRoutes(RouteCollection routes) { routes.MapPageRoute( "SearchRoute", // Route name "search/{searchterm}", // URL with parameters "~/Search.aspx" // Web forms page to handle it ); }

[Visual Basic]
Sub RegisterRoutes(ByVal routes As RouteCollection) ' Route name ' URL with parameters ' Web forms page to handle it routes.MapPageRoute("SearchRoute", "search/{searchterm}", "~/Search.aspx") End Sub

In the Global.asax.cs or Global.asax.vb window, in the Global class, add the following code. [Visual C#]
void RegisterRoutes(RouteCollection routes) { routes.MapPageRoute( "SearchRoute", // Route name "search/{searchterm}", // URL with parameters "~/Search.aspx" // Web forms page to handle it ); }

[Visual Basic]
Private Sub RegisterRoutes(ByVal routes As RouteCollection) ' Route name ' URL with parameters ' Web forms page to handle it routes.MapPageRoute("SearchRoute", "search/{searchterm}", "~/Search.aspx") End Sub

7.

Modify the Application_Start method as shown. [Visual C#]


void Application_Start() { RegisterRoutes(RouteTable.Routes); }

[Visual Basic]
Private Sub Application_Start() RegisterRoutes(RouteTable.Routes) End Sub

6-26

Developing Web Applications with Microsoft Visual Studio 2010

8.

Open the Search.aspx.cs or Search.aspx.vb code file. In Solution Explorer, right-click Search.aspx, and then click View Code.

9.

Modify the Page_Load method in the Search class as shown. [Visual C#]
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { string searchTerm = "No Search Term specified."; if (RouteData.Values["searchterm"] != null) { searchTerm = "You searched for '" + RouteData.Values["searchterm"].ToString() + "'"; } SearchTermLabel.Text = searchTerm; } }

[Visual Basic]
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load If Not Page.IsPostBack Then Dim searchTerm As String = "No Search Term specified." If Not RouteData.Values("searchterm") Is Nothing Then searchTerm = "You searched for '" & RouteData.Values("searchterm").ToString() & "'" End If SearchTermLabel.Text = searchTerm End If End Sub

10. Run the application. a. b. In Solution Explorer, click WebFormsRouting. In the AdventureWorks Microsoft Visual Studio window, on the Debug menu, click Start Without Debugging, or press CTRL+F5.

11. Navigate directly to the Search page by using the following route.
search/My Search Term

In the Home Page Windows Internet Explorer window, in the address bar, append the following text.
search/My Search Term

12. Close Windows Internet Explorer. In the http://localhost:xxxx/search/My%20Search%20Term Windows Internet Explorer window, click the Close button.

13. Close Visual Studio 2010. In the RouteConstraints Microsoft Visual Studio window, click the Close button.

Designing for Discoverability

6-27

Question: How can using ASP.NET Routing improve long-term maintenance of a web application? Question: What is your perception of a website when you get an HTTP 404 error?

6-28

Developing Web Applications with Microsoft Visual Studio 2010

Using ASP.NET Routing with MVC Pages

Routing is at the heart of an ASP.NET MVC application, so when you create a new ASP.NET MVC application by using the ASP.NET MVC 2 Application project template, the application is pre-configured to use ASP.NET Routing. ASP.NET Routing must be set up in two different files; the web configuration file, and the the Global Application class file.

Web Configuration File


In the web configuration file, Web.config, you find the following sections, all relevant to ASP.NET routing; system.web.httpModules, system.web.httpHandlers, system.webServer.modules, and system.webServer.handlers. The first two sections, you normally find in the root web.config file, typically found in the C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config folder, as shown in the following example markup.
... <system.web> ... <httpHandlers> <add path="eurl.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True" /> <add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="True" /> ... </httpHandlers> <httpModules> <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" /> <add name="Session" type="System.Web.SessionState.SessionStateModule" /> <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" /> <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" /> ... </httpModules>

Designing for Discoverability

6-29

... </system.web>

The latter two sections can typically be found in the application configuration file, Web.config. By default, the system.webServer.modules section is specified in the Web.config file for an application created by using the by using the ASP.NET MVC 2 Application project template, as shown in the following example markup.
<system.webServer> ... <modules runAllManagedModulesForAllRequests="true"/> </system.webServer>

You can manually add the handlers section to the system.webServer section, if needed.

Global Application Class File


A route table is created in the applications Global.asax file, also known as the Global Application class. The Global Application class is derived from the HttpApplication class, and it represents the application, and contains optional event handlers for the ASP.NET application life cycle events, that typically run at the start or end of the application lifetime. The route table is created at the start of the application lifetime, in the Application_Start event handler. In the following example code, you can see the default code for the Global.asax file for an ASP.NET MVC 2 web application. [Visual C#]
using using using using using using System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc; System.Web.Routing;

namespace MvcApplication1 { // Note: For instructions on enabling IIS6 or IIS7 classic mode, // visit http://go.microsoft.com/?LinkId=9394801 public class MvcApplication : System.Web.HttpApplication { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults ); } protected void Application_Start() { AreaRegistration.RegisterAllAreas();

6-30

Developing Web Applications with Microsoft Visual Studio 2010

RegisterRoutes(RouteTable.Routes); } } }

[Visual Basic]
' Note: For instructions on enabling IIS6 or IIS7 classic mode, ' visit http://go.microsoft.com/?LinkId=9394802 Public Class MvcApplication Inherits System.Web.HttpApplication Shared Sub RegisterRoutes(ByVal routes As RouteCollection) routes.IgnoreRoute("{resource}.axd/{*pathInfo}") ' MapRoute takes the following parameters, in order: ' (1) Route name ' (2) URL with parameters ' (3) Parameter defaults routes.MapRoute( _ "Default", _ "{controller}/{action}/{id}", _ New With {.controller = "Home", .action = "Index", .id = UrlParameter.Optional} _ ) End Sub Sub Application_Start() AreaRegistration.RegisterAllAreas() RegisterRoutes(RouteTable.Routes) End Sub End Class

When the first request for an MVC application is received, the Application_Start method is called. As you can see from the example code, the static/shared RegisterRoutes method is called from the Application_Start method, ensuring the route table is created. This is the default set up, but you can customize this as you see fit. In the RegisterRoutes method, you can see the call to the IgnoreRoute method of the RouteCollection class. This method call ensures that all requests for .axd files are ignored. This is a security measure, because an .axd file is a handler file used to manage website administration requests, such as the Trace.axd file. In the RegisterRoutes method, you also find a single route defined. This route is named Default, and it is created to request to a default route. As you can see from the following example code extract, the route name is passed, a controller named Home will be used to handle the request by default, and an action method named Index in the controller will by default handle the actual request. Finally, the optional parameter id, can be passed to the action method. [Visual C#]
routes.MapRoute( "Default", // Route name "{controller}/{action}/{id}", // URL with parameters new {

Designing for Discoverability

6-31

controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults );

[Visual Basic]
' MapRoute takes the following parameters, in order: ' (1) Route name ' (2) URL with parameters ' (3) Parameter defaults routes.MapRoute( _ "Default", _ "{controller}/{action}/{id}", _ New With {.controller = "Home", .action = "Index", .id = UrlParameter.Optional} _ )

Notice that the default values point to the Home controller, and the Index action method, but the route mapping also means you can request a different controller and/or a different action method, thanks to the URL with parameters part. If you append the following to the URL in your browsers address bar, it will call the Index action method of the Home controller, as expected, passing 567 to the Index action method.
/Home/Index/567

However, you can also append the following to the URL in your browsers address bar, which will call the Details action method of the Customer controller, passing 34 to the Details action method. The request will fail if the Customer controller or the Details action method does not exist.
/Customer/Details/34

Because of the default parameter values for the Default route, you do not have to specify the parameters. Basically, the following full URLs will all call the Index method on the Home controller.
http://localhost/Home/Index http://localhost/Home http://localhost

The id parameter is by default set to an empty string, "". Controllers and action methods are covered in detail in Module 4, "Developing MVC Controllers", but the following example code shows the default Index action method and the HomeController class. [Visual C#]
using using using using using System; System.Collections.Generic; System.Linq; System.Web; System.Web.Mvc;

namespace MvcApplication1.Controllers { [HandleError] public class HomeController : Controller { public ActionResult Index() {

6-32

Developing Web Applications with Microsoft Visual Studio 2010

ViewData["Message"] = "Welcome to ASP.NET MVC!"; return View(); } ... } }

[Visual Basic]
<HandleError()> _ Public Class HomeController Inherits System.Web.Mvc.Controller Function Index() As ActionResult ViewData("Message") = "Welcome to ASP.NET MVC!" Return View() End Function ... End Class

Question: How does MVC built-in routing improve search engine query results? Question: How does MVC built-in routing improve the maintainability of a website?

Designing for Discoverability

6-33

Creating Custom Routes

The default route table works for most smaller ASP.NET MVC applications, but you will find that as your applications grow in size or complexity, that you have need to implement custom routes. A customer management application may need to handle incoming requests for addresses, and support requests such as /Address/457. This means that the user requests addresses for which the house number is 457. While this can be handled by the default route, by adding an overloaded Index action method, it is much better from a maintenance perspective to create a custom route. The following example code defines a custom route in a Global.asax file. [Visual C#]
routes.MapRoute( "Address", "Address/{houseNumber}", new {controller="Address", action="List"} );

[Visual Basic]
routes.MapRoute( "Address", "Address/{houseNumber}", New With {.controller = "Address", .action = "List"} _ )

6-34

Developing Web Applications with Microsoft Visual Studio 2010

Note: In line with most other things in the world of programming, it is important how you add your custom route definitions to the Global.asax file. When the routes are searched for a match to an incoming request, it starts with the route definition mapped first. So, when you have a default route, as is the default set up, ensure that the default route is the last to be mapped; it will then serve as fallthrough route, in case none of the other defined routes are a match. If you add the default route first, it is very likely that your custom route definition will never be reached, because the default route definition will be a match. The code shown contains a route named Address, which can be used to map browser requests to the AddressController shown next. [Visual C#]
public class AddressController : Controller { public ActionResult List(int houseNumber) { return View(); } }

[Visual Basic]
Public Class AddressController Inherits System.Web.Mvc.Controller Public Function List(ByVal houseNumber As Integer) As ActionResult Return View() End Function End Class

Notice that the List action method exposed by the Address controller accepts a single parameter named houseNumber of type int/Integer. This means that the defined route defined will match any of the following URLs.
/Address/23 /Address/7 /Address/78687988

So, the route will allow the correct parameter to pass through, however it will not allow the following URLs, because the parameter value, does not match the defined route.
/Address/jensen /Address/fruity /Address/12y78u /Address/gh67gh

The listed requests will throw an exception, because of a data type mismatch. This is not best practice, and if unhandled, it will produce an error message that the user will see. See the "Creating Route Constraints" topic later in this lesson for more information on how to address this issue.

Designing for Discoverability

6-35

Demonstration: Creating Custom Routes

1.

Open Microsoft Visual Studio 2010. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

2.

Create a new ASP.NET MVC 2 web application named Routes in the D:\Demofiles\CS\Module06 or D:\Demofiles\VB\Module06 folder, by using the ASP.NET MVC 2 Web Application template. a. b. c. d. e. f. On the File menu, click New Project. In the Installed Templates section, expand Visual Basic or Visual C#, and then click Web. In the list of project types, click ASP.NET MVC 2 Web Application. In the Name box, type Routes. In the Location box, type D:\Demofiles\CS\Module06 or D:\Demofiles\VB\Module06, and then click OK. In the Create Unit Test Project dialog box, select the No, do not create a unit test project option, and then click OK.

3.

Open the Global.asax file. In the Solution Explorer window, double-click Global.asax.

4.

Add the following route to the RegisterRoutes method as shown. [Visual C#]
routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( "Address", "Address/{houseNumber}", new {controller="Address", action="List"} );

6-36

Developing Web Applications with Microsoft Visual Studio 2010

[Visual Basic]
routes.IgnoreRoute("{resource}.axd/{*pathInfo}") routes.MapRoute( "Address", "Address/{houseNumber}", New With {.controller = "Address", .action = "List"} _ )

In the Global.asax.cs or Global.asax.vb window, in the MvcApplication class, in the RegisterRoutes method, add the following code. [Visual C#]
routes.MapRoute( "Address", "Address/{houseNumber}", new {controller="Address", action="List"} );

[Visual Basic]
routes.MapRoute( "Address", "Address/{houseNumber}", New With {.controller = "Address", .action = "List"} _ )

After this code: [Visual C#]


routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

[Visual Basic]
routes.IgnoreRoute("{resource}.axd/{*pathInfo}")

5.

Create the AddressController controller. a. b. In the Solution Explorer window, right-click Controllers, point to Add, and then click Controller. In the Add Controller dialog box, in the Controller Name box, type AddressController, and then click Add.

6.

Add the List action method to the AddressController class as shown. [Visual C#]
public ActionResult List(int houseNumber) { ViewData["HouseNumber"] = houseNumber.ToString(); return View(); }

[Visual Basic]
Function List(ByVal houseNumber As Integer) As ActionResult ViewData("HouseNumber") = houseNumber.ToString() Return View() End Function

7.

Create the List view in the Views/Address folder.

Designing for Discoverability

6-37

a. b. c. d. 8.

In the Solution Explorer window, right-click Views, point to Add, and then click New Folder. In the text box, type Address, and then press ENTER. In the Solution Explorer window, right-click Address, point to Add, and then click View. In the Add View dialog box, in the View name box, type List, and then click Add.

Replace the default content of the Content2 Content control in the List view with the following markup and code, to display the house number requested. [Visual C#]
<h2> List</h2> <h3> List of houses with number <%: ViewData["houseNumber"]%></h3>

[Visual Basic]
<h2> List</h2> <h3> List of houses with number <%: ViewData("houseNumber")%></h3>

9.

Run the application. a. b. In Solution Explorer, click Routes. In the Routes Microsoft Visual Studio window, on the Debug menu, click Start Without Debugging, or press CTRL+F5.

10. Navigate directly to the Address/List view by using the following route.
Address/123

In the Home Page Windows Internet Explorer window, in the address bar, append the following text, and then press Enter.
Address/123

Note: A message stating List of houses with number 123 is now shown. 11. Navigate directly to the Address/List view by using the following route.
Address/twentyseven

In the List Windows Internet Explorer window, in the address bar, replace Address/123 with the following text.
Address/twentyseven

6-38

Developing Web Applications with Microsoft Visual Studio 2010

Note: An error message is now shown. [Visual Basic] The parameters dictionary contains a null entry for parameter 'houseNumber' of nonnullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult List(Int32)' in 'Routes.Routes.AddressController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter. [Visual C#] The parameters dictionary contains a null entry for parameter 'houseNumber' of nonnullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult List(Int32)' in 'Routes.Controllers.AddressController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter. 12. Close Internet Explorer. In the window The parameters dictionary contains a null entry for parameter 'houseNumber' of non-nullable type Windows Internet Explorer, click the Close button.

Keep the solution open for the next demonstration.

Designing for Discoverability

6-39

Creating Route Constraints

Browser requests can fail for various reasons, including if the wrong parameter is supplied. However, allowing the wrong parameters to pass through to an action method is not a best practice. You need to control what can be accepted. For this purpose, you can use route constraints, to control, or restrict the browser requests. This way they match a particular route you have defined. You can define such a constraint by using a regular expression. The Address route definition defined in the previous topics is shown here. [Visual C#]
routes.MapRoute( "Address", "Address/{houseNumber}", new {controller="Address", action="List"} );

[Visual Basic]
routes.MapRoute( "Address", "Address/{houseNumber}", New With {.controller = "Address", .action = "List"} _ )

As previously pointed out, the following requests will throw an exception, because of a data type mismatch.
/Address/jensen /Address/fruity /Address/12y78u /Address/gh67gh

6-40

Developing Web Applications with Microsoft Visual Studio 2010

You need to specify that the route matches only URLs that contain a proper houseNumber parameter of type int/Integer. You can use a constraint when defining a route to restrict the URLs that match the route. The modified Address route shown next, contains a regular expression constraint that only matches integer values. [Visual C#]
routes.MapRoute( "Address", "Address/{houseNumber}", new {controller="Address", action="List"}, new {houseNumber = @"\d+"} );

[Visual Basic]
routes.MapRoute( "Address", "Address/{houseNumber}", New With {.controller = "Address", .action = "List"}, _ New With {.productId = "\d+"} _ )

The regular expression \d+ matches one or more integer characters, so to some extent it is no different than what you had previously, because the second group of the previously listed browser requests that does not match the route. However, it will be handled by another matching route or, if there is no matching route, the following error is returned, which is better than an exception.

They key here is to ensure you have either a route defined for all possible requests and/or have the proper exception handling in place.

Designing for Discoverability

6-41

Demonstration: Creating Route Constraints

Use the solution from the previous demonstration. 1. Modify the Address route in Global.asax as shown to add an integer constraint to the houseNumber parameter. [Visual C#]
routes.MapRoute( "Address", "Address/{houseNumber}", new {controller="Address", action="List"}, new {houseNumber = @"\d+"} );

[Visual Basic]
routes.MapRoute( "Address", "Address/{houseNumber}", New With {.controller = "Address", .action = "List"}, _ New With {.houseNumber = "\d+"} _ )

a. b.

In the Routes Microsoft Visual Studio window, click Global.asax.cs or Global.asax.vb. Insert the following code [Visual C#]
, new {houseNumber = @"\d+" }

[Visual Basic]
, _ New With {.houseNumber = "\d+"} _

At this location

6-42

Developing Web Applications with Microsoft Visual Studio 2010

[Visual C#]
routes.MapRoute( "Address", "Address/{houseNumber}", new {controller="Address", action="List"} <Insert Code Here> );

[Visual Basic]
routes.MapRoute( "Address", "Address/{houseNumber}", New With {.controller = "Address", .action = "List"} <Insert Code Here> )

2.

Run the application. a. b. In the Solution Explorer window, click Routes. In the Routes Microsoft Visual Studio window, on the Debug menu, click Start Without Debugging, or press CTRL+F5.

3.

Navigate directly to the Address/List view by using the following route.


Address/twentyseven

In the Home Page Windows Internet Explorer window, in the address bar, append the following text , and then press Enter.
Address/twentyseven

Note: An error message is now shown. The resource cannot be found. 4. Close Internet Explorer. 5. In the window The resource cannot be found. Windows Internet Explorer, click the Close button.

Close Visual Studio 2010. In the Routes Microsoft Visual Studio window, click the Close button.

Designing for Discoverability

6-43

Lab 6: Designing for Discoverability

Objectives
After completing this lab, you will be able to: Map URLs of Web Forms pages. Create a sitemap file. Build an application infrastructure.

Introduction
In this lab, you map URLs of Web Forms pages to use ASP.NET URL mapping for listing products by category, and details for a specific product ID. You also create a sitemap, as well as a robots.txt file with an inclusion to the newly created sitemap file for the Default Web Site in IIS, and add navigation controls to the application.

6-44

Developing Web Applications with Microsoft Visual Studio 2010

Lab Scenario

You are developing an application that will be used for external customers, and you want to ensure that Search engines can find your site easily. As well, you want to use URLs that are easy for your salespeople to send in emails. Using the routing features of ASP.NET 4.0, you will map the URLs of a Web Forms page. You will create a sitemap page, and complete building the application infrastructure.

Designing for Discoverability

6-45

Exercise 1: Mapping URLs of Web Forms Pages


The main tasks for this exercise are as follows:
1. 2. 3. 4.

Add and verify reference to System.Web.Routing. Edit the Global.asax file to use ASP.NET URL mapping for the page listing products by category. Test the pages. Add a second route to map a URL to the following product ID: http://localhost/product/1. Test the pages.

5.

Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. 2. 3. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution at the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 06\Starter\Exercise 01 D:\Lab Files\VB\Lab 06\Starter\Exercise 01

Task 2: Add and verify a reference to the System.Web.Routing assembly


1. 2. Add a reference to the System.Web.Routing assembly. Verify a reference to the System.Web.Routing assembly.

Task 3: Map the page listing products by category


1. 2. 3. Open the Global.asax file. Import the System.Web.Routing namespace in the Global.asax code file. Add a RegisterRoutes method as shown. [Visual C#]
void RegisterRoutes(RouteCollection routes) { routes.MapPageRoute( "products-browse", // Route name "products/{category}", // URL with parameters "~/Products.aspx" // Web forms page to handle it ); }

[Visual Basic]
Private Sub RegisterRoutes(ByVal routes As RouteCollection) ' Route name ' URL with parameters ' Web forms page to handle it routes.MapPageRoute("products-browse", "products/{category}", "~/Products.aspx") End Sub

6-46

Developing Web Applications with Microsoft Visual Studio 2010

4.

Modify the Application_Start method as shown. [Visual C#]


void Application_Start() { RegisterRoutes(RouteTable.Routes); }

[Visual Basic]
Private Sub Application_Start() RegisterRoutes(RouteTable.Routes) End Sub

5. 6.

Open the Products.aspx.cs or Products.aspx.vb code file. Modify the Page_Load method in the Products class as shown. [Visual C#]
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { string categoryName = null; string categoryId; // Retrieve category param from "/Products/{Category}" URL categoryId = Page.RouteData.Values["category"].ToString(); categoryName = DataAccessLayer.Products.GetCategoryName(int.Parse(categoryId)); lblCategory.Text = categoryName; var data = DataAccessLayer.Products.GetProductsByCategory(int.Parse(categoryId)); gvProducts.DataSource = data; gvProducts.DataBind(); } }

[Visual Basic]
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load If Not Page.IsPostBack Then Dim categoryName As String = Nothing Dim categoryId As String ' Retrieve category param from "/Products/{Category}" URL categoryId = Page.RouteData.Values("category").ToString() categoryName = AdventureWorks.DataAccessLayer.Products.GetCategoryName(Integer.Parse(categoryId)) lblCategory.Text = categoryName Dim data = AdventureWorks.DataAccessLayer.Products.GetProductsByCategory(Integer.Parse(categoryId )) gvProducts.DataSource = data gvProducts.DataBind() End If End Sub

Designing for Discoverability

6-47

Task 4: Test the pages


1. 2. Run the application. Navigate directly to the Products page by using the following route.
products/1

Note: A grid should render with a single row containing products for the product category with an ID value of 1. 3. Close Internet Explorer.

Task 5: Add a second route to map a URL to a product ID


1. 2. Open the Global.asax file. Modify the RegisterRoutes method as shown. [Visual C#]
void RegisterRoutes(RouteCollection routes) { routes.MapPageRoute( "products-browse", // Route name "products/{category}", // URL with parameters "~/Products.aspx" // Web forms page to handle it ); routes.MapPageRoute( "product-browse", // Route name "product/{id}", // URL with parameters "~/ProductDetail.aspx" // Web forms page to handle it ); }

[Visual Basic]
Private Sub RegisterRoutes(ByVal routes As RouteCollection) ' Route name ' URL with parameters ' Web forms page to handle it routes.MapPageRoute("products-browse", "products/{category}", "~/Products.aspx") ' Route name ' URL with parameters ' Web forms page to handle it routes.MapPageRoute("product-browse", "product/{id}", "~/ProductDetail.aspx") End Sub

3. 4.

Open the ProductDetail.aspx.cs or ProductDetail.aspx.vb code file. Modify the Page_Load method in the ProductDetail class as shown. [Visual C#]
protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { string productId; // Retrieve id param from /Products/{Id} URL

6-48

Developing Web Applications with Microsoft Visual Studio 2010

productId = Page.RouteData.Values["id"].ToString(); var data = DataAccessLayer.Products.GetProduct(int.Parse(productId)); lblName.Text = data.Name; lblId.Text = data.ProductID.ToString(); lblColor.Text = data.Color; lblSize.Text = data.Size; lblWeight.Text = data.Weight.ToString(); lblListPrice.Text = data.ListPrice.ToString(); hdnProductId.Value = data.ProductID.ToString(); hdnProductName.Value = data.Name; hdnListPrice.Value = data.ListPrice.ToString(); } }

[Visual Basic]
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load If Not Page.IsPostBack Then Dim productID As String = Nothing ' Retrieve id param from /Products/{Id} URL productID = Page.RouteData.Values("id").ToString() Dim data = AdventureWorks.DataAccessLayer.Products.GetProduct(Integer.Parse(productID)) lblName.Text = data.Name lblId.Text = data.ProductID.ToString() lblColor.Text = data.Color lblSize.Text = data.Size lblWeight.Text = data.Weight.ToString() lblListPrice.Text = data.ListPrice.ToString() hdnProductId.Value = data.ProductID.ToString() hdnProductName.Value = data.Name hdnListPrice.Value = data.ListPrice.ToString() End If End Sub

Task 6: Test the pages


1. 2. Run the application. Navigate directly to the ProductDetail page by using the following route.
product/680

Note: A grid should render with a single row containing details of the product with an ID value of 680. 3. 4. Close Internet Explorer. Close Visual Studio 2010.

Results: After completing this exercise, you should have added a reference to the System.Web.Routing assembly, and modified the Global.asax file to use ASP.NET URL mapping to list products by category and details for a specific product ID.

Designing for Discoverability

6-49

Exercise 2: Creating a Sitemap File


The main tasks for this exercise are as follows:
1. 2.

Create a sitemap file to list products. Modify the robots.txt file to include the sitemap.

Task 1: Create a sitemap file to list products


1. 2. 3. 4. 5. 6. Open Internet Information Services (IIS) Manager as an administrator. In Control Panel, click System and Security, and then click Administrative Tools. Right-click Internet Information Services (IIS) Manager, and then click Run as administrator. In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then press ENTER. Open the Search Engine Optimization feature. Create a new sitemap for the default website, in a file named Sitemap.xml. Set the change frequency to daily, do not record the last modified date and time, and set the priority to 1.

Task 2: Modify the robots.txt file to include the sitemap


1. 2. 3. 4. 5. 6. Select the Default Web site. Open the Search Engine Optimization feature. Add a new allow rule for the default website and Sitemap.xml file. Close Internet Information Services (IIS) Manager. Close Administrative Tools. Close System and Security.

Results: After completing this exercise, you should have created a sitemap as well as a robots.txt file with an inclusion to the newly created sitemap file for the default website in IIS.

6-50

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 3: Building the Application Infrastructure


The main tasks for this exercise are as follows: 1. 2. Add Navigation Controls to the web application. Use the FindControl function to locate a control.

Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution at the following location. Location D:\Lab Files\CS\Lab 06\Starter\Exercise 03 D:\Lab Files\VB\Lab 06\Starter\Exercise 03

Programming Language Visual C# Visual Basic

Task 2: Add Navigation Controls to the web application


1. 2. Create a Web.sitemap file in the root directory of the website. Replace the existing content of the Web.sitemap file with the following markup.
<?xml version="1.0" encoding="utf-8" ?> <siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" > <siteMapNode roles="*"> <siteMapNode url="~/Default.aspx" title="Home" description="Home"></siteMapNode> <siteMapNode url="~/ShoppingCart.aspx" title="Shopping" description="Shopping"></siteMapNode> <siteMapNode url="~/About.aspx" title="About" description="About"></siteMapNode> </siteMapNode> </siteMap>

3. 4. 5.

Save and close the Web.sitemap file. Open the Site.Master master page. Locate the div element with a class attribute value of clear hideSkiplink.
<div class="clear hideSkiplink"> <asp:Menu ID="NavigationMenu" runat="server" CssClass="menu" EnableViewState="false" IncludeStyleBlock="false" Orientation="Horizontal"> <Items> <asp:MenuItem NavigateUrl="~/Default.aspx" Text="Home" /> <asp:MenuItem NavigateUrl="~/ShoppingCart.aspx" Text="Cart" /> <asp:MenuItem NavigateUrl="~/About.aspx" Text="About" /> </Items> </asp:Menu> </div>

6.

Replace the content of the div element with a class attribute value of clear hideSkiplink, with the following markup.
<div class="clear hideSkiplink"> <asp:SiteMapDataSource runat="server" ID="siteMapDataSource" ShowStartingNode="false" /> <asp:Menu runat="server" ID="NavigationMenu" Orientation="Horizontal" DataSourceID="siteMapDataSource" /> </div>

7. 8.

Save and close the Site.Master file. Run the application.

Designing for Discoverability

6-51

9.

Close Internet Explorer.

Task 3: Use the FindControl function to locate a control


1. 2. Open the Site.Master code-behind file. In the Page_Load method, add the following code. [Visual C#]
Menu NavigationMenu = (Menu)this.FindControl("NavigationMenu");

[Visual Basic]
Dim NavigationMenu as Menu = Me.FindControl("NavigationMenu")

3. 4. 5. 6.

Place Breakpoint on the new line of code. Debug the application. Single-step over the selected line of code. Hover the mouse over the NavigationMenu variable.

Note: IntelliSense will show you details about the Menu control. You can expand the different levels by clicking the +-sign. 7. 8. Stop debugging. Close Visual Studio 2010.

Task 4: Turn off the virtual machine and revert the changes
1. 2. 3. 4. In Microsoft Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert. In the Revert Virtual Machine dialog box, click Revert.

Results: After this exercise, you should have added navigation controls to the web application.

6-52

Developing Web Applications with Microsoft Visual Studio 2010

Lab Review

Designing for Discoverability

6-53

Module Review and Takeaways

Review Questions
1. 2. 3. 4. 5. What can every developer do to ensure future content is properly indexed by search engines? What can developers do to gauge the level of optimization for legacy websites? What can developers do to ensure that new content is indexed by search engines? What can developers do to prevent unwanted content from being indexed by search engines? What are the benefits of URL routing for search engines and end users?

Common Issues ASP.NET 4.0 and IIS 7.0


Following is a list of common issues developers face when participating in Search Engine Optimization. These issues include tips that will lead to resolution. Issue Low Page Ranks Unindexed Content Unwanted Content Indexed Unoptimized Website Troubleshooting tip Valid HTML, Descriptive HTML, Descriptive URLs, Descriptive Meta Data Sitemap File Robots File IIS SEO Toolkit

Real-world Issues and Scenarios


1. 2. Website does not appear in results of relevant search engine queries. New content does not appear in results of relevant search engine queries.

6-54

Developing Web Applications with Microsoft Visual Studio 2010

3. 4.

Unintended content appears in results of relevant search engine queries. Status Search Engine Optimization is unknown for legacy applications.

Best Practices ASP.NET 4.0 and IIS 7.0


Supplement or modify the following best practices for your own work situations: Include a DOCTYPE element in every page you publish. Include at least one h1 tag in every page you publish. Include an accurate and descriptive title within the head tag of every page you publish.

Eliminate HTML validation warnings presented by Visual Studio 2010: Include a meta tag in the head tag for all relevant keywords in every page you publish. Include a meta tag in the head tag for a relevant description in every page you publish.

Tools
Tool Visual Studio 2010 IIS SEO Toolkit Use for HTML Intellisense Site Analysis Where to find it http://go.microsoft.com/fwlink/?LinkID=203985&clcid=0x409 http://go.microsoft.com/fwlink/?LinkID=203986&clcid=0x409

Writing Server-Side Code for Web Forms

7-1

Module 7
Writing Server-Side Code for Web Forms
Contents:
Lesson 1: Overview of the Structure of a Web Application Lesson 2: Controlling View State Lesson 3: Localizing a Web Application Lesson 4: Persisting Data on a Web Forms Page Lesson 5: Validating User Input Lab 7: Writing Server-Side Code for Web Forms 7-3 7-10 7-16 7-27 7-33 7-42

7-2

Developing Web Applications with Microsoft Visual Studio 2010

Module Overview

Server-side code is used in many, if not most websites today, and with ASP.NET 4.0, you get a lot of functionality from the framework. The goal of this module is to learn about the advanced features of server-side coding and technologies. You will learn how to allow the website to move into a global and web farm environment through localization, how to make web applications scalable by using shared sessions, and how to create custom user controls. You will also learn how to use validation controls, including CustomValidator, and RegularExpressionValidator.

Writing Server-Side Code for Web Forms

7-3

Lesson 1

Overview of the Structure of a Web Application

When you create a new web application or a new website, Visual Studio 2010 will create some folders automatically. In a web application, some predefined file types exists that have special meanings. In this lesson, we will explore these folders and file types.

Lesson Objectives:
After completing this lesson, you will be able to: Describe the folder structure of a web application. Describe the file types contained in a web application. Distinguish between automatic and dynamic compilation.

7-4

Developing Web Applications with Microsoft Visual Studio 2010

Structure of a Web Application

When you create a new web application project, you can organize your folder in any way you want. Visual Studio creates some folders that have special purposes. All of them can be added to the web application by right-clicking the project in Solution Explorer, pointing to Add, pointing to Add ASP.NET Folder, and then clicking the desired ASP.NET folder type. Folder App_Browsers Description Contains browser definitions (.browser files) that ASP.NET uses to identify individual browsers and determine their capabilities.

App_Code

Contains source code for utility classes and business objects (for example, .cs and .vb files) that you want to compile as part of your application. In a dynamically compiled application, ASP.NET compiles the code in the App_Code folder on the initial request to your application. Items in this folder are then recompiled when any changes are detected. Contains application data files including MDF files, XML files, as well as other data store files. The App_Data folder is used by ASP.NET to store an application's local database, which can be used for maintaining membership and role information. Contains resources (.resx and .resources files) that are compiled into assemblies with global scope. Resources in the App_GlobalResources folder are strongly typed, and can be accessed programmatically. Contains resources (.resx and .resources files) that are associated with a specific page, user control, or master page in an application.

App_Data

App_GlobalResources

App_LocalResources

Writing Server-Side Code for Web Forms

7-5

Folder App_Themes

Description Contains a collection of files (.skin and .css files, as well as image files and generic resources) that define the appearance of ASP.NET web pages and controls. Contains reference contract files (.wsdl files), schemas (.xsd files), and discovery document files (.disco and .discomap files) defining a web reference for use in an application. Contains compiled assemblies (.dll files) for controls, components, or other code that you want to reference in your application. Any classes represented by code in the Bin folder are automatically referenced in your application.

App_WebReferences

Bin

For more information about the ASP.NET Web Project folder structure, see http://go.microsoft.com/fwlink/?LinkID=203989&clcid=0x409.

7-6

Developing Web Applications with Microsoft Visual Studio 2010

Web Application File Types

Typically, a web application can have different types of files serving different purposes. Some of the files are supported by ASP.NET, while others are supported by IIS. Most of them can be added to the web application by right-clicking the project in Solution Explorer, pointing to Add, and then clicking New Item. File Type .aspx .ascx .ashx .config .master .svc .asmx .axd .resx .cs or .vb Global.asax Description An ASP.NET Web Forms file (page) that can contain web controls and presentation and business logic. A web user control file that defines a custom, reusable control. A generic handler file. A configuration file (typically Web.config) that contains XML elements that represent settings for ASP.NET features. A master page that defines the layout for other web pages in the application. A WCF service file. An XML web services file that contains classes and methods that are available to other web applications by way of SOAP. A handler file used to manage website administration requests, typically Trace.axd. A resource file that contains resource strings that refer to images, localizable text, or other data. Class source-code file that is compiled at run time. A file that contains code that derives from the HttpApplication class. This file represents the application, and contains optional methods that run at the start or

Writing Server-Side Code for Web Forms

7-7

File Type

Description end of the application lifetime.

For more information about ASP.NET Web Project file types, see http://go.microsoft.com/fwlink/?LinkID=203990&clcid=0x409.

7-8

Developing Web Applications with Microsoft Visual Studio 2010

Web Application Compilation Methods

One of the biggest advantages ASP.NET has over other technologies is the use of compiled code. Compiled code offers following advantages: Performance: Compiled code is parsed only once, at compile time. Security: Compiled code is more difficult to reverse engineer. Stability: Compiled code is checked at compile time for syntax errors. Interoperability: Because Microsoft intermediate language (MSIL) code supports any .NET language, you can use assemblies that were originally written in other languages in your code.

ASP.NET automatically compiles your application code and any dependent resources the first time a user requests a resource from the website. In general, ASP.NET creates an assembly for each application folder (such as App_Code) and one for the main folder. (If files in a folder are in different programming languages, separate assemblies will be created for each language.) You can specify which folders are compiled into single assemblies in the compilation section of the Web.config file. ASP.NET dynamic compilation enables you to modify your source code without having to compile your code explicitly before you deploy your web application. If you modify a source file, ASP.NET automatically recompiles the file and updates all linked resources. When your code is compiled, the resulting assemblies are cached in a folder on the server. This folder requires appropriate permissions so that your code compiles and runs correctly. You can configure both the compilation folder location and the permissions under which your code compiles and operates. The typical location is %SystemRoot%\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files. For more information about dynamic compilation, see http://go.microsoft.com/fwlink/?LinkID=203991&clcid=0x409.

Writing Server-Side Code for Web Forms

7-9

For more information about automatic compilation, see http://go.microsoft.com/fwlink/?LinkID=203992&clcid=0x409.

7-10

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 2

Controlling View State

HTTP is stateless; therefore, view state plays a central role in the good functioning of ASP.NET Web Forms applications. In this lesson we will describe view state, how to control it, and its impact on performance.

Lesson Objectives:
After completing this lesson, you will be able to: Describe what view state is, and its impact on performance. Disable view state. Apply view state.

Writing Server-Side Code for Web Forms

7-11

What is View State?

In order for ASP.NET Web Forms applications to run properly, they need to save the state of the page between renderings. When the page is sent to the client, the state of the controls is sent twice: once into the control directly, so that it can render appropriately, and be saved into a hidden field on the page. When the page is posted back, ASP.NET reads the content of this hidden field to recreate the original state of the page, and then reads the actual data that that the user entered. If there are changes, ASP.NET raises the change events, and the event that caused the postback. As you might suspect, by using view state, the size of the page increases. For more information about view state, see http://go.microsoft.com/fwlink/?LinkID=203994&clcid=0x409.

7-12

Developing Web Applications with Microsoft Visual Studio 2010

Controlling View State

When a page is sent to the client, parts of its controls state will be serialized into XML, and then be Base64 encoded and sent to the client into a hidden field called __VIEWSTATE. Because of that, the size of this field can become very big. Some firewalls have problems letting through fields that are too big, and they will reject the page. To solve this problem, ASP.NET offers a way to limit the size of the __VIEWSTATE field, by setting the MaxPageStateFieldLength property to a value with which firewalls dont have problems. (Changing the value of MaxPageStateFieldLength property in this way causes the __VIEWSTATE field to split into several smaller fields.) One simple way to reduce the size of the __VIEWSTATE field is to turn off view state for the controls that do not need it, such as read-only controls. To turn off view state you have to set the property ViewStateMode for the control or for the page to Disabled. The EnableViewState property can be used to turn off view state for the page and any control it contains, even if the view state has been enabled for a control by setting the ViewStateMode for the control to Enabled.

Writing Server-Side Code for Web Forms

7-13

Using ViewStateMode

One problem with EnableViewState is that if you set it to False, the value of EnableViewState for the child controls will be ignored. To overcome this problem, ASP.NET 4.0 introduced a new property called ViewStateMode. In order for ViewStateMode to work, EnableViewState has to be set to True, which is the default value, so removing it altogether, will have the same effect. ViewStateMode can have one of the following three values: Enabled: The page/control is using view state. Disabled: The page/control has its view state turned off. Inherit (Default): The control is inheriting the view state of the parent control.

For more information about ViewStateMode, see: http://go.microsoft.com/fwlink/?LinkID=203995&clcid=0x409.

7-14

Developing Web Applications with Microsoft Visual Studio 2010

Using Control State

View state can be turned off, but some controls do need to save some state to function correctly. You can overcome this problem by using control state. Control state is using the same mechanism that view state is using, but it cannot be turned off. To use the control state from a control you must override the methods SaveControlState and LoadControlState. In addition, you must call the RegisterRequiresControlState method from the OnInit event. For more information about view state versus control state, see http://go.microsoft.com/fwlink/?LinkID=203996&clcid=0x409.

Writing Server-Side Code for Web Forms

7-15

View State Best Practices

The biggest disadvantage of view state is it size. This affects both the time it takes to load the page, and the correct indexing of the page by different search engines. To solve this issue, you can do one or more of the following: Disable view state completely if the page is read-only. Disable view state only for all the controls on a page, except those that are read/write. If view state is too big, you can move it to the end of the page. In this way, you will aid a search engine to better index the content of your page. Mind you, this is not a trivial task and you will have to implement it manually. Consider using control state instead of view state only for those control properties that are absolutely necessary for the functioning of your control.

7-16

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 3

Localizing a Web Application

In order to survive in a global market, applications need to be adapted quickly to new regions, and translated into new languages. The .NET Framework offers support for these issues by introducing the notions of globalization and localization.

Lesson Objectives:
After completing this lesson, you will be able to: Describe the use of a resource file for localization. Create a resource file. Retrieve values from a resource file.

Writing Server-Side Code for Web Forms

7-17

What is Localization?

Globalization is the process of designing and developing an application that supports localized user interfaces and regional data for users in multiple cultures. In the .NET Framework, the CultureInfo class represents information about a specific culture. This information includes the writing system, calendars in use, date and time formatting conventions, numeric and currency conventions, and sorting rules. Localizability is an intermediate process for verifying that a globalized application is ready for localization. An application is ready for localization if the application's executable code has been clearly separated from the application's localizable resources. The common language runtime's satellite assembly resource model fully supports this separation of code and resources. Executable code is located in the application's main assembly, and only resources are located in the application's resource files. Localization is the process of translating an application's resources into localized versions for each culture that the application will support. An application that is ready for localization is separated into two conceptual blocks: a block that contains all user interface elements, and a block that contains executable code. The user interface block contains only localizable user-interface elements such as strings, error messages, dialog boxes, menus, embedded object resources, and so on for the neutral culture. The code block contains only the application code to be used by all supported cultures. The common language runtime supports a satellite assembly resource model that separates an application's executable code from its resources. The CultureInfo class contains culture-specific information, such as the language, country/region, calendar, and cultural conventions. This class also provides the information required for performing culture-specific operations, such as casing, formatting dates and numbers, and comparing strings. The CultureInfo class specifies a unique name for each culture. For more information about localization, see http://go.microsoft.com/fwlink/?LinkID=203997&clcid=0x409.

7-18

Developing Web Applications with Microsoft Visual Studio 2010

Working with Resource Files

An application is ready to be localized if the code and the localizable parts are clearly separated. In .NET, this separation is done by having the code in code files, and the localizable resources defined in special purpose files, called resource files. When working with web applications, there are two kinds of resource files, local resources, which reside in App_LocalResources special ASP.NET folder, and global resources, which reside in App_GlobalResources special ASP.NET folder. Local resource files are specific to an ASP.NET page or control, and every language will have its own resource file. For instance, the default resource file for Default.aspx is called Default.aspx.resx. If we want a French version for that file, we need to create a resource file called Default.aspx.fr.resx. To create the local resource files, you would create the file manually, by adding a New Item called Default.aspx.resx, or you would generate the file in Visual Studio 2010. To generate the file you must complete the following steps: 1. 2. Open the .aspx or .ascx file for which you want to generate a resource file for, in Design mode. On the Tools menu, click Generate Local Resource. This will create the default resource. For Default.aspx, this will be a resource file named Default.aspx.resx.

The original file will have now an extra attribute called meta:resourcekey for any control, including the page itself, which has properties that supports localization. The value of this attribute is used as key in the resource file to find the translations for specific properties. The generated resource file will have an entry for any localizable property found on the page or control, with their respective values found on the original file. To translate the resource file you can copy it and rename it to match the desired language, and then make the translation in place, or use a third-party product for manually translating the file. Global resources files are files that contain resources that need to be translated, and are not specific to a page or control, like error messages, pictures, and so on. To create a global resource file, you must first add the special ASP.NET folder named App_GlobalResources, and in that folder, you add a new resource file. The name of the file is important because it will be used in your code. To translate the resources in

Writing Server-Side Code for Web Forms

7-19

that file, you must create a new resource file for the new language. For instance, if you created a global resource file called WebResources.resx, then the file containing the French translations should be called WebResources.fr.resx.

7-20

Developing Web Applications with Microsoft Visual Studio 2010

Reading Data from Resource Files

When a page is requested in a certain language, if a page or control is localized, ASP.NET will read the values for the localizable properties from the resource files. First, it looks to see whether the resource is available in that specific language, and if it isnt, it will fall back to the default value in the neutral resource. To read the data from the resource files we have two methods: Implicit localization: This method works only with local resources. For any control that has a meta:resourcekey attribute set, ASP.NET uses the value of that attribute to find the right resource; for example, if we use the following markup in our Default.aspx:

<asp:Button ID="btnCategory" runat="server" Text="Submit" meta:resourcekey="btnCategoryResource1"></asp:Button>

Then ASP.NET will look in the Default.aspx.<culture>.resx file for an entry called btnCategoryResource1.Text, to find the right text. If there is no entry, it will look in the Default.aspx.resx for that entry, and if there is no entry either will use the value from the .aspx file. Note: If a resource does not exist if the default or neutral culture, it will not be looked up in the requested culture, even if the resource does exist there. Explicit Localization: This method works with both local and global resources. In this case we have to specify the name of the resource entry direct in our code, or in markup.
<asp:Literal runat="server" Text="<%$ Resources: LiteralResource3%>"/>

When working with Resources the custom expression takes the following form:
<%$ Resources:Class, ResourceID %>

Writing Server-Side Code for Web Forms

7-21

Class is the name of the global resource file without .resx. If the Class part is omitted, then ASP.NET will look for the resource with the specified ResourceID in the local resource file. For any global resource file ASP.NET will automatically generate a class under the Resources namespace that has the same name as the file, and one property for every entry in the file, so the previous expression can be written as:
[Visual C#] myLiteral.Text = Resources.Class.ResourceID; [Visual Basic] myLiteral.Text = Resources.Class.ResourceID

For more information about resource files, see http://go.microsoft.com/fwlink/?LinkID=203998&clcid=0x409.

7-22

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Localize a Web Application

In this demonstration, you will see how to localize a web application. 1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the Localization solution from the following location. Location D:\Demofiles\CS D:\Demofiles\VB

Programming Language Visual C# Visual Basic a. b. 3.

In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project, or press CTRL+SHIFT+O. In the Open Project dialog box, in the File name box, type D:\Demofiles\CS\Localization.sln or D:\Demofiles\VB\Localization.sln and then click Open.

Open Default.aspx. In Solution Explorer, double-click Default.aspx.

4.

Add a Label server control after the h2 element, with the following attributes. Value HelloLabel Hello in English Place the cursor after the h2 element.

Attribute ID Text a.

Writing Server-Side Code for Web Forms

7-23

b. 5.

Open the Toolbox, expand Standard, and then double-click Label.


<asp:Label ID="HelloLabel" runat="server" Text="Hello in English"></asp:Label>

Switch to Design view. In the Default.aspx window, click Design.

6.

Generate local resources by using the Generate Local Resource command on the Tools menu. In the Localization Microsoft Visual Studio window, on the Tools menu, click Generate Local Resource.

7.

Switch to Source view. In the Default.aspx window, click Source.

8. 9.

Notice the newly added attributes, meta:resourcekey, for both the page and the Label server control. Open the App_LocalResources\Default.aspx.resx file. In Solution Explorer, in the App_LocalResources folder, double-click Default.aspx.resx.

10. Add a new string resource named HeaderText.Text with the value Localization. In the bottom row of the Resource Editor, in the Name box, type HeaderText.Text, and in the Value box, type Localization.

11. Add a new string resource named DescriptionText with the value ASP.NET Localization. In the bottom row of the Resource Editor, in the Name box, type DescriptionText, and in the Value box, type ASP.NET Localization.

12. Save and close the resource file. a. b. On the File menu, click Save App_LocalResources\Default.aspx.resx, or press CTRL+S. In the Default.aspx.resx window, click the Close button.

13. Copy the App_LocalResources\Default.aspx.resx file to a new file named Default.aspx.de.resx, in the App_LocalResources folder. a. b. c. d. In Solution Explorer, in the App_LocalResources folder, right-click Default.aspx.resx, and then click Copy. In Solution Explorer, right-click App_LocalResources, and then click Paste. In Solution Explorer, in the App_LocalResources folder, right-click Copy of Default.aspx.resx, and then click Rename. In the text box, type Default.aspx.de.resx, and then press ENTER.

14. Open the App_LocalResources\Default.aspx.de.resx file. In Solution Explorer, in the App_LocalResources folder, double-click Default.aspx.de.resx.

15. Localize the string resource named HeaderText.Text with a new value of Lokalisierung. In the Resource Editor, in the row with a value in the Name column of HeaderText.Text, in the Value box, type Lokalisierung.

16. Localize the string resource named HelloLabelResource1.Text with a new value of Hallo in Deutsch. In the Resource Editor, in the row with a value in the Name column of HelloLabelResource1.Text, in the Value box, type Hallo in Deutsch.

7-24

Developing Web Applications with Microsoft Visual Studio 2010

17. Localize the string resource named PageResource1.Title with a new value of Startseite. In the Resource Editor, in the row with a value in the Name column of PageResource1.Title, in the Value box, type Startseite.

18. Localize the string resource named DescriptionText with a new value of ASP.NET Lokalisierung. In the Resource Editor, in the row with a value in the Name column of DescriptionText, in the Value box, type ASP.NET Lokalisierung.

19. Save and close the resource file. a. b. On the File menu, click Save App_LocalResources\Default.aspx.de.resx, or press CTRL+S. In the Default.aspx.de.resx window, click the Close button.

20. In Default.aspx, localize the hard-coded Localization text implicitly, by adding a Localize server control within the h2 element, with the following attributes. Attribute ID meta:resourcekey a. b. c. Value HeaderText HeaderText

Place the cursor within the h2 element, just before the text Localization. Open the Toolbox, expand Standard, and then double-click Localize. Modify the Localize server control to appear as follows.
<asp:Localize ID="HeaderText" runat="server" meta:resourcekey="HeaderText"></asp:Localize>

21. Delete the text Localization from the h2 element. 22. Add two HTML self-closing br elements, and a Literal server control named DescriptionLiteral, after the HelloLabel server control. a. b. c. d. Place the cursor after the HelloLabel element. Type the following text and then press ENTER.
<br/><br/>

Open the Toolbox, expand Standard, and then double-click Literal. Modify the Literal server control to appear as follows.
<asp:Literal ID="DescriptionLiteral" runat="server" Text=""></asp:Literal>

23. Make the Literal control explicitly localizable, by adding the following text to the Text property.
<%$ Resources: DescriptionText %>

24. Add a new global resource file named WebResources.resx to the App_GlobalResources folder. a. b. c. In Solution Explorer, right-click Localization, point to Add, point to Add ASP.NET Folder, and then click App_GlobalResources. In Solution Explorer, right-click App_GlobalResources, point to Add, and then click New Item. In the Add New Item dialog box, in the middle pane, click Resources File, in the Name box, type WebResources.resx, and then click Add.

Writing Server-Side Code for Web Forms

7-25

Note: The name of the file is the same as the class that will be generated in the Resources namespace. 25. Add a new string resource named FooterText with the value This is the footer.... In the bottom row of the Resource Editor, in the Name box, type FooterText, in the Value box, type This is the footer....

26. Save and close the resource file. a. b. On the File menu, click Save App_GlobalResources\WebResources.resx, or press CTRL+S. In the WebResources.resx window, click the Close button.

27. Copy the App_GlobalResources\WebResources.resx file to a new file named WebResources.de.resx, in the App_GlobalResources folder. a. b. c. d. In Solution Explorer, in the App_GlobalResources folder, right-click WebResources.resx, and then click Copy. In Solution Explorer, right-click App_GlobalResources, and then click Paste. In Solution Explorer, in the App_LocalResources folder, right-click Copy of WebResources.resx, and then click Rename. In the text box, type WebResources.de.resx, and then press ENTER.

28. Open the App_GlobalResources\WebResources.de.resx file. In Solution Explorer, in the App_GlobalResources folder, double-click WebResources.de.resx.

29. Localize the string resource named FooterText with a new value of Dies ist der Fuzeile.... In the Resource Editor, in the row with a value in the Name column of FooterText, in the Value box, type Dies ist der Fuzeile....

30. Save and close the resource file. a. b. On the File menu, click Save App_GlobalResources\WebResources.de.resx, or press CTRL+S. In the WebResources.de.resx window, click the Close button.

31. Add an h3 element, and within the h3 element, a Label server control named FooterLabel, after the DescriptionLiteral server control. a. b. c. d. e. Place the cursor after the DescriptionLiteral element. Type the following text and the press ENTER.
<h3></h3>

Place the cursor between the opening and closing h3 tags. Open the Toolbox, expand Standard, and then double-click Label. Modify the Label server control to appear as follows.
<asp:Label ID="FooterLabel" runat="server" Text=""></asp:Label>

32. Modify the Label control, by adding the following text to the Text property.
<%$ Resources:WebResources, FooterText %>

33. Run the application. a. In Solution Explorer, click Localization.

7-26

Developing Web Applications with Microsoft Visual Studio 2010

b.

In the Localization Microsoft Visual Studio window, on the Debug menu, click Start Without Debugging, or press CTRL+F5.

34. Verify that Default.aspx Web Form displays text in English. 35. Show the Localization home page in German, by changing the language preference in the Internet Options dialog box. a. b. c. d. e. In the Home Page - Windows Internet Explorer window, on the Tools menu, click Internet Options. In the Internet Options dialog box, click Languages. In the Language Preference dialog box, click Add. In the Add Language dialog box, in the Language list, click German (Germany) [de-DE], and then click OK. In the Language Preference dialog box, in the Language list, click German (Germany) [deDE], and then click Move up.

36. In the Language Preference dialog box, click OK. 37. In the Internet Options dialog box, click OK. 38. Refresh the page in Windows Internet Explorer. In the Home Page Windows Internet Explorer window, press F5.

Note: The page should now be shown in German. 39. Close Internet Explorer. In the Home Page Windows Internet Explorer window, click the Close button.

40. Close Visual Studio 2010. In the Localization Microsoft Visual Studio window, click the Close button.

Writing Server-Side Code for Web Forms

7-27

Lesson 4

Persisting Data on a Web Forms Page

ASP.NET uses HTTP as underlying protocol, and HTTP is stateless. Stateless refers to the fact that the server does not maintain information about requests after they are processed. For example, if a user requests information on a product, the server does not maintain that user once it finishes the request. Having state refers to the server maintaining information about a request. This is more common when the user adds items to cart. This kind of behavior requires special attention when designing new web applications, and ASP.NET offers multiple solutions. In this lesson we will explore some of those options.

Lesson Objectives:
After completing this lesson you will be able to: Store user information in cookies and session. Configure Microsoft SQL Server to store session information.

7-28

Developing Web Applications with Microsoft Visual Studio 2010

Introduction to State Management

To make the communication between web server and web client meaningful and coherent, the state need to be saved between requests. All web applications function by using the Request/Response communication pattern. That means that for every request that comes from the client, the server will reply back with one response. In a stateless world, the server is just serving the reply back, but doesnt remember what was said earlier in the communication.

Writing Server-Side Code for Web Forms

7-29

Options for State Management

The state can be saved either on the server, or on the client. Both have advantages and disadvantages.

Server Side
The data is saved where it is needed, but if there are too many clients simultaneously, the performance might be affected, and the resource usage will be high. Another thing that needs to be taken into consideration is scalability. If the data is saved locally on the server, then it will be difficult to make it work in a web farm scenario. Application state: A key-value dictionary of objects that you can use to store data available to all the requests. Session state: A key-value dictionary of objects that you can use to store data coming from a single client browser across multiple requests. User profile: Allows you to define and store per-user settings to be used throughout your application. Caching: Keys paired with values, where you can place items and later retrieve them.

Client Side
The data is saved where it belongs, together with the page, but this creates unnecessary data transfers between the client and the server. View state: The state of the page is serialized into XML, encoded Base64, and is then sent to the client as a hidden field. Control state: Some controls are dependent on view state , but view state can be turned off, unlike control state, which cannot be turned off. Posted data: State data is sent as hidden field, much the same as view state, but is not using XML serialization, or Base64 encoding.

7-30

Developing Web Applications with Microsoft Visual Studio 2010

Cookies: State data is sent as text as part of the HTTP header, in both the request and in the reply. Query: State data is encoded in the query string, but this has the limitation of max 255 characters.

Writing Server-Side Code for Web Forms

7-31

Options for Saving Session State

Four options for saving Session state data are available: InProc: Session values are memory-bound objects within the ASP.NET worker process memory space, w3wp.exe. This is the default option. StateServer: Session values are serialized and stored in the memory of a separate process (aspnet_state.exe). Still memory-bound, this process could be run in a location-transparent way (either locally or on another machine). SQLServer: Session values are serialized and stored in a Microsoft SQL Server table. The instance of SQL Server can run either locally or remotely. Custom: The fourth option is to create a custom state client provider.

We will discuss further only the options of making the session data persistent in SQL Server database.

7-32

Developing Web Applications with Microsoft Visual Studio 2010

Using SQL Server to Store Session State

To use SQLServer mode, you must first be sure the ASP.NET session state database is installed on SQL Server. You can install the ASP.NET session state database using the Aspnet_regsql.exe tool. This will create a database called ASPState. To configure an ASP.NET application to use SQLServer mode, in the application's Web.config file set the mode attribute of the sessionState element to SQLServer. Next, set the sqlConnectionString attribute to a connection string for your SQL Server database, without specifying the database name.
<configuration> ... <system.web> ... <sessionState mode="SQLServer" sqlConnectionString="Integrated Security=SSPI;Data Source=SampleSqlServer;" /> ... </system.web> ... </configuration>

Writing Server-Side Code for Web Forms

7-33

Lesson 5

Validating User Input

User input validation is the first line of defense for almost all secure software. Thus, the user input validation has to be integrated with the security and reliability design of a specific application. A question then arises about the best place to perform the validationwhen the data is first entered in the program, or later when the data is actually used? The answer is: in both places, since a malicious input may go around the first validation. Generally, data must be always checked before using it.

Lesson Objectives:
After completing this lesson you will be able to: Describe the various validation controls used in Web Forms pages. Describe the various ways to display error messages in a Web Forms page. Use RegEx in a custom validation control.

7-34

Developing Web Applications with Microsoft Visual Studio 2010

Why Validate?

One must be sure that data is valid, sensible, reasonable, and secure before it is processed. There are different reasons for validating input, including protecting against injection attacks, and ensuring the data is correct and conforms to your business rules. Another reason for validating on the client is to make the application appear responsive, and indicate any input errors as users type in the required information.

Writing Server-Side Code for Web Forms

7-35

Validation Controls

ASP.NET offers a series of predefined validation controls: RequiredFieldValidator: You can specify that a user must provide information in a specific control on an ASP.NET web page by adding a RequiredFieldValidator control to the page, and linking it to the required control. For example, you can specify that users must fill in a Name text box before they can submit a registration form. CompareValidator: Compares a user's entry against a constant value, against the value of another control (using a comparison operator such as less than, equal, or greater than), or for a specific data type. Supported data types are: Integer, Currency, Double, Date, and String. RangeValidator: Checks that a user's entry is between specified lower and upper boundaries. You can check ranges within pairs of numbers, alphabetic characters, and dates. RegularExpressionValidator: Checks that the entry matches a pattern defined by a regular expression. This type of validation enables you to check for predictable sequences of characters, such as those in email addresses, telephone numbers, postal codes, and so on. CustomValidator: Checks the user's entry using validation logic that you write yourself. This type of validation enables you to check for values derived at run time.

7-36

Developing Web Applications with Microsoft Visual Studio 2010

Validation Controls Properties

All validation controls inherits from BaseValidator, and have the following properties: ControlToValidate: The programmatic ID of the input control that the validation control will evaluate. If this is not a legitimate ID, an exception is thrown. ErrorMessage: The error message to display in the ValidationSummary control if validation fails. If the Text property of the validation control is not set, this text is also displayed in the validation control when validation fails. The ErrorMessage property is commonly used to provide different messages for the validation control and the ValidationSummary control. Text: When set, this message is displayed in the validation control when validation fails. If this property is not set, the text specified in the ErrorMessage property is displayed in the control. Display: The display behavior for the specified validation control. This property can be one of the following values: None Validation control is never displayed inline. Use this option when you want to show the error message only in a ValidationSummary control. Static Validation control displays an error message if validation fails. Space is allocated on the web page for the error message even if the input control passes validation. The layout of the page does not change when the validation control displays its error message. Because the page layout is static, multiple validation controls for the same input control must occupy different physical locations on the page. Dynamic Validation control displays an error message if validation fails. Space for the error message is allocated dynamically on the page when validation fails. This allows multiple validation controls to share the same physical location on the page.

ValidationGroup: Meant for organizing validation controls. A validation group is created by setting the ValidationGroup property to the same name (a string) for all the controls you want to group.

Writing Server-Side Code for Web Forms

7-37

You can assign any name to a validation group, but you must use the same name for all members of the group. EnableClientScript: Use the EnableClientScript property to specify whether client-side validation is enabled. Validation controls always perform validation on the server. They also have complete clientside implementation that allows DHTML-supported browsers (such as Microsoft Internet Explorer 4.0 and later) to perform validation on the client. Client-side validation enhances the validation process by checking user input before it is sent to the server. This allows errors to be detected on the client before the form is submitted, avoiding the round trip of information necessary for server-side validation. By default, this value is set to true, which enables client-side validation if the browser supports it. You can disable client-side validation on a control-by-control basis. This is useful if dynamic updating on the client creates problems with the layout of the page, or if you want to execute some server code before validation takes place.

7-38

Developing Web Applications with Microsoft Visual Studio 2010

Validation Groups

Validation groups allow you to organize validation controls on a page as a set. Each validation group can perform validation independently from other validation groups on the page. You create a validation group by setting the ValidationGroup property to the same name (a string) for all the controls you want to group. You can assign any name to a validation group, but you must use the same name for all members of the group. During postback, the IsValid property of the Page class is set based only on the validation controls in the current validation group. The current validation group is determined by the control that caused validation to occur.

Writing Server-Side Code for Web Forms

7-39

Displaying Validation Errors

Validation errors can be displayed to the user in four different ways. It is often best to use a combination of these. The following describes the different methods:

Inline
An inline error refers to having the error message right beside the control that contains the invalid input. For example, if the user has a badly formed email address, often the error message Invalid email address will appear to the right of the control.

Summary
The validation summary control lists all errors that have been generated by the validation controls. This is most often placed near the Submit button. When the user clicks Submit, he or she is presented with a list of all items that need to be fixed.

Inline and Summary


Using both inline and summary controls gives the user the most feedback. This displays a message beside the control, as well as near the Submit button. Often the inline control will be changed to display a * or a graphic to point the user to where the error occurred.

Custom
A custom error control allows you to write script or custom code when an error is not in the norm, such as to check for certain values. This control uses the Page.IsValid property to determine whether an error has occurred. For more information about displaying validation errors, see http://go.microsoft.com/fwlink/?LinkID=203999&clcid=0x409.

7-40

Developing Web Applications with Microsoft Visual Studio 2010

Regular Expressions Validation

The RegularExpressionValidator control is used to determine whether the value of an input control matches a pattern defined by a regular expression. This type of validation allows you to check for predictable sequences of characters, such as those found in social security numbers, email addresses, telephone numbers, postal codes, and so on. Both server-side and client-side validation are performed, unless the browser does not support client-side validation, or client-side validation is explicitly disabled (the EnableClientScript property is set to false). For more information about RegularExpressionValidator, see http://go.microsoft.com/fwlink/?LinkID=204000&clcid=0x409.

Writing Server-Side Code for Web Forms

7-41

Custom Validation

Use the CustomValidator control to provide a user-defined validation function for an input control. The CustomValidator control is a separate control from the input control it validates, which allows you to control where the validation message is displayed. Validation controls always perform validation on the server. They also have complete client-side implementation that allows script-enabled browsers (such as Microsoft Internet Explorer 4.0 and later) to perform validation on the client. Client-side validation enhances the validation process by checking user input before it is sent to the server. This allows errors to be detected on the client before the form is submitted, thus avoiding the round trip of information necessary for server-side validation. To create a server-side validation function, provide a handler for the ServerValidate event that performs the validation. The string from the input control to validate can be accessed by using the Value property of the ServerValidateEventArgs object passed into the event handler as a parameter. The result of the validation is then stored in the IsValid property of the same ServerValidateEventArgs parameter. To create a client-side validation function, first add the server-side validation function described earlier. Next, add the client-side validation script function to the ASP.NET page.
function ValidationFunctionName(source, arguments)

For information about custom validation, see http://go.microsoft.com/fwlink/?LinkID=204001&clcid=0x409http://msdn.microsoft.com/enus/library/9eee01cx.aspx.

7-42

Developing Web Applications with Microsoft Visual Studio 2010

Lab 7: Writing Server-Side Code for Web Forms

Note: You can perform the tasks in this lab by using either Visual C# or Visual Basic as your programming language.

Objectives:
After completing this lab, students will be able to: Modify a Web Forms page to display localized content. Persist user data by using a variety of methods. Utilize view state effectively. Add validation to Web Forms pages.

Introduction
In this lab, you modify a Web Forms page and the master page to display localized content, located in different resource files. You persist user data by using cookies, application state, and session state, and you learn how to utilize view state effectively. You also add validation to Web Forms pages, using validation controls.

Writing Server-Side Code for Web Forms

7-43

Lab Scenario

To improve the customer experience, existing Web Forms pages of the AdventureWorks website need to be updated to display localized information. Because purchases by international customers make up a large percentage of online sales, management has decided that the messages, units, dates, and so on, should be displayed in either English or other languages based on a customers language preference. Therefore, you need to edit the home page to detect the default browser language.

7-44

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 1: Modifying a Web Forms Page to Display Localized Content


The main tasks for this exercise are as follows: Create resource files so that Default.aspx can display the page in English and language of your choice. Localize the Site.Master master.

Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. 2. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd. Open Microsoft Visual Studio 2010. 3. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the AdventureWorks solution from the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 07\Starter\Exercise 01 D:\Lab Files\VB\Lab 07\Starter\Exercise 01

Task 2: Create resource files for Default.aspx


1. 2. Analyze the markup in Default.aspx. Generate local resources for Default.aspx, by using the Generate Local Resource functionality available in Design view. Note: This automatically creates the App_LocalResources folder in the root of your web application, if one does not already exist. The process also creates a resource file called Default.aspx.resx, in the App_LocalResources folder. 3. 4. Switch back to Source view of Default.aspx. Notice that both the lbCategories and btnCategory server controls have had an extra attribute called meta:resourcekey added to the existing markup.
<asp:Button ... meta:resourcekey="btnCategoryResource1"></asp:Button> <asp:ListBox ... meta:resourcekey="lbCategoriesResource1"></asp:ListBox>

Note: The values of these attributes are used to find the localized values for the properties of the localizable controls in the Default.aspx.resx file. 5. 6. Notice that the Page directive at the top of the page now contains the following information.
<%@ Page ... culture="auto" meta:resourcekey="PageResource1" uiculture="auto" %>

Open Default.aspx.resx. Note: In the Resource Editor, you will see a list with all the localizable properties of the localizable controls from the Default.aspx page.

7.

Switch back to Default.aspx.

Writing Server-Side Code for Web Forms

7-45

8.

Notice that the text strings Welcome to AdventureWorks! and Product Categories were not modified, and they were not added to the .resx file either. This is because they were hard-coded in the Web Forms page. Localize the hard-coded Welcome to AdventureWorks! text implicitly, by adding a Localize server control within the h2 element, with the following attributes. Attribute ID Text meta:resourcekey Value lclWelcome Welcome to AdventureWorks! LocalizeResource1

9.

10. Delete the text Welcome to AdventureWorks! from the h2 element. Note: Make sure that you do not delete the text Welcome to AdventureWorks! from the Localize server control. 11. Add a resource string named lclWelcomeResource1.Text to the Default.aspx.resx resource file. The string must have the value of Welcome to AdventureWorks!. 12. Localize the hard-coded Product Categories text explicitly, by adding a Literal server control within the p element, with the following attributes. Attribute ID Text Value ProductCategoriesLiteral <%$ Resources: ProductCategoriesLiteral.Text %>

13. Delete the text Product Categories from the p element. Note: Make sure that you do not delete the text Product Categories from the Literal server control. 14. Add a resource string named ProductCategoriesLiteral.Text to the Default.aspx.resx resource file. The string must have the value of Product Categories. 15. Run the application. 16. Verify that Default.aspx Web Form looks the same as it did before you modified it. 17. Close Windows Internet Explorer. 18. Add an existing German resource file for the Default.aspx Web Form to the App_LocalResources folder. The file is named Default.aspx.de.resx and it is located in the D:\Lab Files\CS\Lab 07\Starter\Exercise 01 or D:\Lab Files\VB\Lab 07\Starter\Exercise 01 folder.

Task 3: Localize the Site.Master master page


1. 2. Open the Site.Master master page. Localize the hard-coded Log In text, by adding a Literal server control within the a element, with the following attributes.

7-46

Developing Web Applications with Microsoft Visual Studio 2010

Attribute ID Text 3. Delete the text Log In from the a element.

Value LoginLiteral Log In

Note: Make sure that you do not delete the text Log In from the Literal server control. 4. Localize the hard-coded Welcome text, by adding a Literal server control within the LoggedInTemplate element, with the following attributes. Attribute ID Text 5. Value WelcomeLiteral Welcome

Delete the text Welcome from the LoggedInTemplate element. Note: Make sure that you do not delete the text Welcome from the Literal server control.

6. 7.

Open the Site.Master master page in Design view. Generate local resources for Site.Master, by using the Generate Local Resource functionality. Note: This generates a new file called Site.Master.resx in the App_LocalResources folder.

8.

Add an existing German resource file for the Site.Master master page to the App_LocalResources folder. The file is named Site.Master.de.resx and it is located in the D:\Lab Files\CS\Lab 07\Starter\Exercise 01 or D:\Lab Files\VB\Lab 07\Starter\Exercise 01 folder.

Task 4: Test the web application


1. 2. Run the application. Show the AdventureWorks home page in German, by changing the language preference in the Internet Options dialog box.

Writing Server-Side Code for Web Forms

7-47

Note: The page should now be shown in German. 3. 4. Close Internet Explorer. Close Visual Studio 2010. Results: After this exercise, you should have a web application that supports different languages, and shows the site in the users preferred language.

7-48

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 2: Persisting Data on Web Forms Pages


The main tasks for this exercise are as follows: 1. 2. 3. 4. Use a cookie collection to persist user information, setting scope and lifetime to save the last chosen category. Store system-wide information in the Application object, to hold the number of simultaneous visitors on the site. Use the session object to store the shopping cart. Configure session state to run in SQL Server.

Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 07\Starter\Exercise 02 D:\Lab Files\VB\Lab 07\Starter\Exercise 02

Task 2: Use a cookie collection to persist user information and set scope and lifetime to
save the last chosen category
1. 2. Open the Default.aspx Web Form in Code view. On postback, create a cookie object called Preferences that holds the current product category, saved as a value named LastCategory. Make sure that the cookie will expire after one minute. The cookie must be appended to the response. [Visual C#]
else { if (lbCategories.SelectedIndex != -1) { string category = lbCategories.SelectedValue; HttpCookie cookie = new HttpCookie("Preferences"); cookie["LastCategory"] = category; cookie.Expires = DateTime.Now.AddMinutes(1); Response.AppendCookie(cookie); } Response.Redirect("/Products.aspx?id=" + category);

[Visual Basic]
Else If lbCategories.SelectedIndex <> -1 Then Dim category = lbCategories.SelectedValue Dim cookie As New HttpCookie("Preferences") cookie("LastCategory") = category cookie.Expires = DateTime.Now.AddMinutes(1) Response.AppendCookie(cookie)

Writing Server-Side Code for Web Forms

7-49

Response.Redirect("/Products.aspx?id=" & category, True) End If End If

3.

If the page is rendered for the first time, add code to check that a cookie named Preferences exists in the request cookie collection, and if there is, read the LastCategory value from the cookie, and assign it to the SelectedValue property of the ListBox control. [Visual C#]
if (!Page.IsPostBack) { List<ProductCategory> data = DataAccessLayer.Products.GetCategories(); lbCategories.DataSource = data; lbCategories.DataBind(); HttpCookie cookie = Request.Cookies["Preferences"]; if (cookie != null) { lbCategories.SelectedValue = cookie["LastCategory"]; }

[Visual Basic]

If Not Page.IsPostBack Then Dim data As List(Of ProductCategory) = AdventureWorks.DataAccessLayer.Products.GetCategories lbCategories.DataSource = data lbCategories.DataBind() Dim cookie As HttpCookie = Request.Cookies("Preferences") If Not cookie Is Nothing Then lbCategories.SelectedValue = cookie("LastCategory") End If

4.

Build the solution, and fix any errors.

Task 3: Store system-wide information in the Application object


1. 2. Open Global.asax in Code view. In the Application_Start method, overwrite the existing code, by adding a new application variable named OnlineVisitors, to the Application object. The variable must have a starting value of 0. [Visual C#]
void Application_Start(object sender, EventArgs e) { Application["OnlineVisitors"] = 0; }

[Visual Basic]
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) Application("OnlineVisitors") = 0 End Sub

3.

In the Session_Start method increment the value of the OnlineVisitors application variable by 1. Make sure you prevent multiple threads from writing to the application variable, by locking the Application object before writing, and unlocking once you have finished writing to it. [Visual C#]

7-50

Developing Web Applications with Microsoft Visual Studio 2010

void Session_Start(object sender, EventArgs e) { Application.Lock(); int visitors = (int)Application["OnlineVisitors"]; visitors++; Application["OnlineVisitors"] = visitors; Application.UnLock(); }

[Visual Basic]
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) Application.Lock() Dim visitors As Integer = Integer.Parse(Application("OnlineVisitors")) visitors += 1 Application("OnlineVisitors") = visitors Application.UnLock() End Sub

4.

In the Session_End decrement the value of the OnlineVisitors application variable by 1, if the current value is not 0. Make sure you prevent multiple threads from writing to the application variable, by locking the Application object before writing, and unlocking once you have finished writing to it. [Visual C#]
void Session_End(object sender, EventArgs e) { Application.Lock(); int visitors = (int)Application["OnlineVisitors"]; if (visitors > 0) { visitors++; Application["OnlineVisitors"] = visitors; } } Application.UnLock();

[Visual Basic]
Sub Session_End(ByVal sender As Object, ByVal e As EventArgs) Application.Lock() Dim visitors As Integer = Integer.Parse(Application("OnlineVisitors")) If visitors > 0 Then visitors -= 1 Application("OnlineVisitors") = visitors End If Application.UnLock() End Sub

5.

Build the solution, and fix any errors.

Task 4: Use the session object to store the shopping cart


1. 2. Open the ProductDetails Web Form in Code view. Upon postback, the Order button has been pressed, so the information entered in the Web Form is persisted. In the Page_Load method, notice how the product ID, product name, and list price, which are not displayed to the user, are saved to hidden fields. In the btnOrder_Click event handler, notice that a new List object of type clsShoppingCart is created and saved to Session state. Finally, the user is redirected to the ShoppingCart Web Form.

Writing Server-Side Code for Web Forms

7-51

3. 4.

Open the ShoppingCart Web Form in Code view. Analyze the code in the Page_Load method.

Task 5: Configure session state to run in SQL Server


1. 2. Open the Web.config file. Configure your application to use the local SQL Server instance named SQLExpress, for persisting session information instead of the default InProc mode.
<system.web> ... <sessionState mode="SQLServer" sqlConnectionString="Integrated Security=SSPI;Data Source=.\SQLExpress;" /> </system.web>

3.

Configure the local SQL Server instance SQLExpress to host the state database, by running the following command from the Visual Studio Command Prompt (2010). The Visual Studio Command Prompt (2010) must be run as an administrator.
aspnet_regsql -E -S .\SQLExpress -ssadd

4.

Open the SQL Server Command Line Tool, by running the following command from the Visual Studio Command Prompt (2010).
sqlcmd E S .\SQLExpress

5.

Add permissions for the user Student to access the tempdb and ASPState database to use the new SQL Server Session state, by running commands from the SQL Server Command Line Tool within the Visual Studio Command Prompt (2010). The commands are saved in the D:\Lab Files\CS\Lab 07\Starter\Exercise 02\ASPState.txt or D:\Lab Files\VB\Lab 07\Starter\Exercise 02\ASPState.txt file, from where you can copy them and paste them into the SQL Server Command Line Tool. Close the SQL Server Command Line Tool, by running the following command from the Visual Studio Command Prompt (2010).
quit

6.

7. 8.

Close the Visual Studio Command Prompt (2010). Close Visual Studio 2010.

Results: After this exercise, you should have implemented state using different techniques, including Application and Session state.

7-52

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 3: Utilizing View State Effectively


The main tasks for this exercise are as follows: 1. 2. Configure the view state to persist page data. Disable the view state and its effects.

Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the following location. Location D:\Lab Files\CS\Lab 07\Starter\Exercise 03 D:\Lab Files\VB\Lab 07\Starter\Exercise 03

Programming Language Visual C# Visual Basic

Task 2: Configure view state to persist page data


1. 2. 3. 4. 5. 6. 7. Run the application. View the source of the Default.aspx page in Internet Explorer, by using the View Source functionality. Analyze the HTML code, and pay special attention to the __VIEWSTATE field. Close the View Source window. Close Internet Explorer. Open the Default.aspx Web Form. Disable view state for the lbCategories server control.
<asp:ListBox ID="lbCategories" runat="server" DataTextField="Name" DataValueField="ProductCategoryID" Height="270px" Width="186px" EnableViewState="False" ></asp:ListBox>

8. 9.

Run the application. View the source of the Default.aspx page in Internet Explorer, by using the View Source functionality.

10. Analyze the HTML code, and pay special attention to the __VIEWSTATE field, which is now much smaller, almost half the size. 11. Close the View Source window. 12. Notice the effects of disabling view state for the lbCategories server control, by clicking Submit. Note: The lbCategories server control is now empty because it is not being populated by the server code on a postback. 13. Close Internet Explorer.

Task 3: Disable view state and its effects


1. Disable view state for the Default Web Form by setting the EnableViewState property to False.
<%@ Page Title="Home Page" ... EnableViewState="False" %>

Writing Server-Side Code for Web Forms

7-53

2. 3.

Run the application. Click Submit. Note: The lbCategories server control is now empty because it is not being populated by the server code on a postback.

4. 5.

Close Internet Explorer. Enable view state for the lbCategories server control.
<asp:ListBox ID="lbCategories" runat="server" DataTextField="Name" DataValueField="ProductCategoryID" Height="270px" Width="186px" EnableViewState="True" ></asp:ListBox>

6. 7.

Run the application. Click Submit. Note: The lbCategories server control is now empty, even if you enabled view state for the control. This is because disabling view state for a control or page will disable the view state for all child controls.

8. 9.

Close Internet Explorer. Remove the EnableViewState attribute and value from the Page directive.

10. Remove the EnableViewState attribute and value from the lbCategories server control. 11. Disable view state for the Default Web Form by setting the ViewStateMode property to Disabled.
<%@ Page Title="Home Page" ... ViewStateMode="Disabled" %>

12. Enable view state for the lbCategories server control by setting the ViewStateMode property to Enabled.
<asp:ListBox ID="lbCategories" runat="server" DataTextField="Name" DataValueField="ProductCategoryID" Height="270px" Width="186px" ViewStateMode="Enabled"></asp:ListBox>

13. Run the application. Note: The rendered page looks okay. 14. Click Submit. Note: The lbCategories server control is still populated because view state has been enabled for the server control. 15. Close Internet Explorer. 16. Close Visual Studio 2010.

7-54

Developing Web Applications with Microsoft Visual Studio 2010

Results: After this exercise, you should have examined and implemented the view state in different ways.

Writing Server-Side Code for Web Forms

7-55

Exercise 4: Adding Validation to Web Forms Pages


The main tasks for this exercise are as follows: 1. 2. 3. Add credit card fields to the check-out page. Add and configure a RequiredFieldValidator control for the txtCreditCard control. Add and configure a RegularExpressionValidator control for the credit card field.

Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the following location. Programming Language Visual C# Visual Basic Location D:\Lab Files\CS\Lab 07\Starter\Exercise 04 D:\Lab Files\VB\Lab 07\Starter\Exercise 04

Task 2: Add credit card fields to the check-out page


1. 2. Open the ShoppingCart.aspx Web Form. Add a TextBox server control for the credit card field and name it txtCreditCard. Place the server control below the gvCart GridView server control. Add describing text, Credit card number:, in front of the server control.
<br /> Credit card number: <asp:TextBox runat="server" ID="txtCreditCard"/>

Task 3: Add and configure a RequiredFieldValidator control for the txtCreditCard control
1. Add a RequiredFieldValidator control named CreditCardRequiredFieldValidator to the ShoppingCart Web Form, and place it immediately after the txtCreditCard control.
<asp:TextBox runat="server" ID="txtCreditCard" /> <asp:RequiredFieldValidator ID="CreditCardRequiredFieldValidator" runat="server"> </asp:RequiredFieldValidator>

2.

Set the following properties as indicated.

a. ControlToValidate = txtCreditCard b. ErrorMessage = Credit card number is required. c. Text = *


<asp:RequiredFieldValidator ID="CreditCardRequiredFieldValidator" runat="server" ControlToValidate="txtCreditCard" ErrorMessage="Credit card number is required." Text="*"> </asp:RequiredFieldValidator>

Task 4: Add and configure a RegularExpressionValidator control for the credit card field
1. Add a RegularExpressionValidator control named CreditCardRegularExpressionValidator to the ShoppingCart Web Form, and place it immediately after the CreditCardRequiredFieldValidator control. Add a self-closing HTML br element after the RegularExpressionValidator control.
</asp:RequiredFieldValidator> <asp:RegularExpressionValidator ID="CreditCardRegularExpressionValidator" runat="server"> </asp:RegularExpressionValidator> <br />

7-56

Developing Web Applications with Microsoft Visual Studio 2010

2.

Set the following properties as indicated.

a. b. c. d.

ControlToValidate = txtCreditCard ErrorMessage = Please enter a valid credit card number. Text = * ValidationExpression= ^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13})$

<asp:RegularExpressionValidator ID="CreditCardRegularExpressionValidator" runat="server" ControlToValidate="txtCreditCard" Text="*" ErrorMessage="Please enter a valid credit card number." ValidationExpression="^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][09]{13})$"> </asp:RegularExpressionValidator>

3. 4.

Open the ShoppingCart Web Form in Code view. Make sure that an order can be placed only if Page.IsValid is true. Add the check to the btnPlaceOrder_Click event handler method. [Visual C#]
protected void btnPlaceOrder_Click(object sender, EventArgs e) { if (Page.IsValid) { Session["_cart"] = null; Response.Redirect("~/ThankYou.aspx", true); } }

[Visual Basic]
Protected Sub btnPlaceOrder_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnPlaceOrder.Click If Page.IsValid Then Session("_cart") = Nothing Response.Redirect("~/ThankYou.aspx", True) End If End Sub

5. 6. 7. 8. 9.

Run the application. Select Bib-Shorts on the Product Categories list, and click Submit. On the Products page, click Men's Bib-Shorts, L. On the Men's Bib-Shorts, L page, click Order. On the Shopping Cart page, click Place Order. Note: Observe that an asterisk (*) is placed next to txtCreditCard server control because you have not filled in this field.

10. On the Shopping Cart page, in the Credit card number box, type 1234123412341234, and then click Place Order. Note: Observe that an asterisk (*) is placed next to txtCreditCard server control because you have not entered a valid credit card number.

Writing Server-Side Code for Web Forms

7-57

11. On the Shopping Cart page, in the Credit card number box, type 4058340022020047, and then click Place Order. Note: Observe that you are redirected to the ThankYou Web Form because you have filled in a valid credit card number. 12. Close Internet Explorer. 13. Close Visual Studio 2010. Results: After this exercise, you should have implemented validation for the check-out page, by adding validation controls to the Web Form.

Task 5: Turn off the virtual machine and revert the changes
1. 2. 3. 4. In Microsoft Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert. In the Revert Virtual Machine dialog box, click Revert.

7-58

Developing Web Applications with Microsoft Visual Studio 2010

Lab Review

Writing Server-Side Code for Web Forms

7-59

Module Review and Takeaways

Review Questions
1. 2. 3. 4. What are the names of the two ASP.NET folders used for resources? How is control state different from view state? What is the default location for resource (.resx) files .resx, when a web application is built? Which type of state can you use to maintain state for the entire period of a user visit?

Real-world Issues and Scenarios


1. You have been tasked with creating a new web application for a client. Before you begin, you know from your peers that this particular client has a problem with defining the correct requirements. This means that requirements will be added after you have started your work. You also know from talking to some of the client's employees that it is likely that the web application will be localized at some stage. You now have a situation in which you need to decide if you should separate UI elements from executable code. After deploying a web application, you receive complaints from your customers that a particular Web Form is taking several seconds to load, and at peak times it can take as long as 10s of seconds to load. You know that this page uses view state to store rather large amounts of data, which are necessary for the page to function. How can you fix this to halve the time the page takes to load?

2.

Best Practices
Supplement or modify the following best practices for your own work situations: Disable view state for read-only server controls, or read-only pages. Use control state for properties for which you need to save state when creating controls. Keep the size of view state to a minimum, to speed up processing and rendering of a page. When creating a new web application, and there is a current or future requirement to localize it, separate the application into two conceptual blocks: one for the UI elements, and one for the executable code.

7-60

Developing Web Applications with Microsoft Visual Studio 2010

Use a global resource file for storing resources that are shared between various pages or controls in a web application. Always validate any input in a web application. Input validation must always be performed server-side, whether or it is performed client-side.

Optimizing Data Management for Web Forms

8-1

Module 8
Optimizing Data Management for Web Forms
Contents:
Lesson 1: Managing Data by Using LINQ to Entities Lesson 2: Using Data Source Controls Lesson 3: Using ASP.NET Dynamic Data Lab 8A: Optimizing Data Management for Web Forms Lab 8B: Optimizing Data Management for Web Forms 8-3 8-18 8-62 8-38 8-79

8-2

Developing Web Applications with Microsoft Visual Studio 2010

Module Overview

In this module, you will learn some of the ways you can optimize and display data management tasks for a web forms-based application using ASP.NET Dynamic Data, data binding, LINQ to Entities, server-side controls, and server-side code. This module explains what LINQ to Entities is and how you can use it with LINQ Create, Read, Update, and Delete (CRUD) queries to manage data in a database by using an Entity Framework data model in a Microsoft ASP.NET web application. All of the LINQ to Entities queries and the Entity Framework data models are created by using the tools that are built into Microsoft Visual Studio 2010.

Optimizing Data Management for Web Forms

8-3

Lesson 1

Managing Data by Using LINQ to Entities

Most business applications are currently written to access data in relational databases. At some point, these applications will have to interact with the data represented in a relational form. The .NET Framework has several ways of managing data, including pure ADO.NET, LINQ to SQL and the ADO.NET Entity Framework. The latter can be used with LINQ to Entities to query the data in the data store behind the data model. This lesson explains what LINQ to Entities is, and how it works.

Lesson Objectives
After completing this lesson, you will be able to: Create a LINQ to Entities model. Use LINQ to Entities in your code. Perform CRUD operations using LINQ to Entities.

8-4

Developing Web Applications with Microsoft Visual Studio 2010

Overview of LINQ to Entities

Key Points
Data in a data store, such as a database, is most often stored using a relational model, which is optimized for efficient storage and retrieval. However, the relational model is not optimized for the conceptual modeling that is used in object-oriented programming. Multiple normalized tables often correspond to a single class, and relationships between classes are not represented in the same way as relationships between tables. Business application developers often use two or more programming languages: A high-level programming language, such as Microsoft Visual Basic or Microsoft Visual C#, for the business and application logic, and the presentation layers. A query language, such as Transact-SQL, to interact directly with the database.

The downside to using more than a single programming language is that it requires a developer to be proficient in several programming languages. When building an application that uses a data access API, such as pure ADO.NET, to query a database, the query is often specified as a string literal by using quotes. Such a query string is opaque to the high-level language compiler and is therefore not checked for errors at compile-time, but rather at run-time. The errors include general syntax errors, as well as whether the referenced columns/fields or rows actually exist. There is also no type checking of the query parameters, and certainly no IntelliSense support. Two technologies help you get the better of these issues: the ADO.NET Entity Framework and LINQ.

ADO.NET Entity Framework


The ADO.NET Entity Framework enables developers to work with data in the form of domain-specific objects and properties, such as customers and customer addresses, without having to think about the underlying database tables and columns where the data is stored.

Optimizing Data Management for Web Forms

8-5

LINQ
LINQ allows developers to formulate set-based queries in their application code, without having to use a separate query language.

ADO.NET Entity Framework and LINQ to Entities


Through the Object Services infrastructure of the Entity Framework, ADO.NET exposes a common conceptual view of data, including relational data, as objects in the .NET environment. This makes the object layer an ideal target for LINQ support. This LINQ technology, LINQ to Entities, allows developers to create flexible, strongly typed queries against the Entity Framework object context by using LINQ expressions and the LINQ standard query operators directly from the development environment. The queries are expressed in the programming language itself and not as string literals embedded in the application code. The compiler catches syntax errors, as well as errors in member names and data types, at compile time. LINQ to Entities queries use the Object Services infrastructure, in which the ObjectContext class is the primary class for interacting with an Entity Data Model as Common Language Runtime (CLR) objects. The developer constructs a generic ObjectQuery instance through the ObjectContext. The ObjectQuery generic class represents a query that returns an instance or collection of typed entities. The returned entity objects are updatable and are located in the object context.

Additional Reading
For more information about the ADO.NET Entity Framework, see ADO.NET Entity Framework at http://go.microsoft.com/fwlink/?LinkID=203976&clcid=0x409. Question: Which infrastructure does LINQ to Entities queries use for interacting with the Entity Data Model as CLR objects? Answer: LINQ to Entities queries use the Object Services infrastructure for interacting with the Entity Data Model as CLR objects.

8-6

Developing Web Applications with Microsoft Visual Studio 2010

Overview of ADO.NET Entity Framework Object Services

Key Points
Object Services is the component of the ADO.NET Entity Framework that enables you to query, insert, update, and delete data, all expressed as strongly-typed CLR objects. These CLR objects are instances of entity types, which means that they are types that derive from the System.Data.Objects.DataClasses.EntityObject type, "plain-old" CLR object (POCO) types, POCO proxy types, and self-tracking entity types.

Entity Types
Following are the different CLR entity types that can be used by Object Services. System.Data.Objects.DataClasses.EntityObject The ADO.NET Entity Data Model tools generate, by default, EntityObject derived entity types. When you work with EntityObject derived types, the object context manages the relationships between your objects. It tracks changes as they occur, and also supports lazy loading in the most efficient manner. POCO Entities The Entity Framework enables you to use existing domain objects together with the data model, without making any modifications to the data classes. These POCO data classes support most of the same query, insert, update, and delete behaviors as the entity types. POCO Proxies Use POCO proxies if you want efficient and instant change tracking and lazy loading. When you use proxies, you have the same functionality as EntityObject derived types, but your domain classes are still separate from the Entity Framework. Self-Tracking Entities The EntityObject derived types, POCO, and POCO proxy types work well in applications where entity objects can be attached to the object context that handles change tracking. Self-tracking entities can

Optimizing Data Management for Web Forms

8-7

record changes to scalar, complex, and navigation properties, and they do not depend on the Entity Framework.

Queries
Object Services supports both Entity SQL and LINQ queries against the types defined in the conceptual model. Object Services materializes the returned data as objects, and propagates any object changes back to the data source. In addition, Object Services also provides facilities for tracking any changes, binding the objects to controls, and handling concurrency.

Entity SQL
Entity SQL is a SQL-like language that enables you to query conceptual models in the Entity Framework. Conceptual models represent data as entities and relationships, and Entity SQL allows you to query those entities and relationships in a format that is familiar to those who have used SQL.

Object Context
The ObjectContext class is the primary class for interacting with data when working with objects that are instances of entity types, defined in a conceptual model. An instance of the ObjectContext class encapsulates a connection to the database (EntityConnection object), metadata describing the model (MetadataWorkspace object), and an ObjectStateManager object for tracking objects during CRUD operations.

Additional Reading
For more information about POCO entities and POCO proxies, see Working with POCO Entities (Entity Framework) at http://go.microsoft.com/fwlink/?LinkID=203954&clcid=0x409. For more information about the self-tracking entities, see Working with Self-Tracking Entities (Entity Framework) at http://go.microsoft.com/fwlink/?LinkID=203955&clcid=0x409. For more information about Entity SQL, see Entity SQL Overview at http://go.microsoft.com/fwlink/?LinkID=203956&clcid=0x409. Question: What are POCO entities? Answer: POCO entities are "plain-old" CLR object types.

8-8

Developing Web Applications with Microsoft Visual Studio 2010

The Entity Data Model

Key Points
Using LINQ to Entities, you can create flexible, strongly-typed queries against the Entity Data Model (EDM) Object Context. For this to happen, mapping between the conceptual data model and the underlying data source is handled automatically, which means that you can create a LINQ to Entities application without any knowledge of the underlying data source or any specific ways of querying the data source. This has another advantage in that it allows you to change the data source without making any changes to the client application, simply because most database-specific features are handled by Object Services. The Entity Data Model (EDM) is an entity relationship model. The EDM defines data in a neutral format that is not constrained by the structure of programming languages or relational databases. EDM schemas are used to specify the details of entities and relationships, and to implement them as data structures. The EDM is a specification for defining the data used by applications built on the ADO.NET Entity Framework. To use the EDM you need to define the entities and the relationships, if any. This must be done in a design schema, which is used to build the programmable classes that are used by your code. The storage structures that persist the data in the model are represented in another schema, which is called the storage schema. The design schema and the storage schema are connected through a mapping specification. Effectively this means that the mapping specification connects the programmable classes to the storage structures, giving you an objectified way of accessing the data source. Entities defined by the EDM can be read in serialized form by using a data reader, or materialized as objects. The materialized objects are programmable in CLR languages such as Visual Basic and Visual C#, and are updated and saved without embedded SQL strings or other database syntax. The EDM supplies the basic entity and relationship types used in EDM schemas and the mapping specification. However, these types can be extended as necessary. A data model can be an analysis in the unified modeling language (UML) or diagrams on a whiteboard. By whatever method, data types, their attributes, the relationships between data types, the constraints on

Optimizing Data Management for Web Forms

8-9

data, and so on, must be organized conceptually before they can be implemented in application code. The EDM extends the models that application designers use to describe data during the development process, and provides XML syntax to detail the results in schematic form.

Additional Reading
For more information about the Entity Data Model specification, see EDM Specifications at http://go.microsoft.com/fwlink/?LinkID=203957&clcid=0x409. Question: What is the first step in creating an Entity Data Model? Answer: You must first define the entities and the relationships, if any, in a design schema.

8-10

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Creating an Entity Data Model

Key Points
This demonstration shows you how to create an Entity Data Model. 1. Open Microsoft Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the EDM solution from the D:\Demofiles\VB or D:\Demofiles\CS folder. a. b. In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project. In the Open Project dialog box, in the File name box, type D:\Demofiles\VB\EDM.sln or D:\Demofiles\CS\EDM.sln, and then click Open.

3.

Add an ADO.NET Entity Data Model project item named AdventureWorks.edmx. a. b. c. d. e. f. g. In Solution Explorer, right-click EDM, point to Add, and then click New Item. In the Add New Item - EDM dialog box, in the left pane, click Data, and then in the middle pane, click ADO.NET Entity data Model. In the Name box, type AdventureWorks.edmx, and then click Add. In the Entity Data Model Wizard, on the Choose Model Contents page, click Generate from database, and then click Next. On the Choose Your Data Connection page, click New Connection. If the Choose Data Source dialog box opens, in the Data source list, click Microsoft SQL Server, and then click Continue. In the Connection Properties dialog box, in the Server name box, type 10264A-GENDEV\SQLEXPRESS, in the Select or enter a database name box, type AdventureWorksLT2008R2, and then click OK.

Optimizing Data Management for Web Forms

8-11

h. i.

In the Entity Data Model Wizard, on the Choose Your Data Connection page, view the updated settings, derived from the selected database, and then click Next. On the Choose Your Database Objects page, in the Which database objects do you want to include in your model? list, expand Tables, select the Tables check box, clear the BuildVersion (dbo)check box, and then click Finish.

Note: If the Pluralize or singularize generated object names check box is selected, the wizard uses English-language rules for singulars and plurals and does the following: makes all EntityType names singular and all EntitySet names plural; and for NavigationProperty, for each that returns at most one entity, makes the name singular, and for each that returns more than one entity, makes the name plural. If the Include foreign key columns in the model check box is selected, the wizard generates properties on entity types that correspond to foreign key columns in the database. j. k. Review the entity properties. In the AdventureWorks.edmx window, click the Customer entity, and then show the Properties window. Notice how Entity Set Name property is plural (Customers), and the Name property is singular (Customer). l. Review the mapping. a. b. In the AdventureWorks.edmx window, click and possibly expand the Mapping Details Customer window. Under Column Mappings, in particular, observe how the NameStyle SQL Server bit column is mapped to a .NET Framework Boolean/bool data type.

4. Close the ADO.NET Entity Data Model item. In the AdventureWorks.edmx window, click the Close button.

5. Close Visual Studio 2010. a. b. In the EDM Microsoft Visual Studio window, click the Close button. In the Microsoft Visual Studio dialog box, click Yes.

Question: What does it mean to pluralize or singularize generated object names? Answer: It means that English-language rules are used to make all EntityType names singular, and all EntitySet names plural, and then for NavigationProperty, for each that returns at most one entity, make the name singular; for each that returns more than one entity, make the name plural.

8-12

Developing Web Applications with Microsoft Visual Studio 2010

Object Oriented Programming Using LINQ to Entities

Key Points
To work with LINQ to Entities and the EDM from your code, you must create an instance of the ObjectContext type, which is automatically generated for you when you save the EDM. This is how you can create an instance of the ObjectContext derived class created in the previous demonstration. [Visual Basic]
' Create new object context instance Dim adventureWorksObjectContext As New AdventureWorksLT2008_DataEntities()

[Visual C#]
// Create new object context instance AdventureWorksLT2008_DataEntities adventureWorksObjectContext = new AdventureWorksLT2008_DataEntities();

Once you have an instance of the ObjectContext derived class, you can query the objects in the data source. If you want to retrieve all of the customers, this is how it can be done. [Visual Basic]
' Retrieve all customers Dim customersQuery = From customers In adventureWorksObjectContext.Customers Select customers

[Visual C#]
// Retrieve all customers var customersQuery = from customers in adventureWorksObjectContext.Customers select customers;

The code shown is using anonymous types, but it could be written using the explicit ObjectQuery type. [Visual Basic]

Optimizing Data Management for Web Forms

8-13

Dim customersQuery As New ObjectQuery(Of Customer)("Customers", adventureWorksObjectContext)

[Visual C#]
var customersQuery = new ObjectQuery<Customer>("Customers", adventureWorksObjectContext);

The ObjectQuery type is part of the System.Data.Objects namespace, and it is the same type of object that is returned when you use the implementation with the anonymous type. In line with other LINQ implementations, you can obviously query the objects as well, such as retrieving all female customers. [Visual Basic]
' Retrieve all female customers Dim customersQuery = From customers In adventureWorksObjectContext.Customers Where customers.Title = "Ms." Select customers

[Visual C#]
// Retrieve all female customers var customersQuery = from customers in adventureWorksObjectContext.Customers where customers.Title == "Ms." select customers;

As with all non-managed objects in the .NET Framework, you need to dispose of the ObjectContext derived object, like this: [Visual Basic]
' Dispose of ObjectContext object adventureWorksObjectContext.Dispose()

[Visual C#]
// Dispose of ObjectContext object adventureWorksObjectContext.Dispose();

The simplest way of working with the ObjectContext derived object, is to wrap it in a Using/using statement. [Visual Basic]
Using adventureWorksObjectContext As New AdventureWorksLT2008_DataEntities() ' Retrieve all male customers, ordered by last name Dim customersQuery = From customers In adventureWorksObjectContext.Customers Order By customers.LastName Where customers.Title = "Mr." Select customers ' Loop through returned objects For Each cust As Customer In customersQuery ' Display first and last name of returned objects Response.Write(cust.FirstName & " " & cust.LastName & "<br/>") Next End Using

[Visual C#]

using (AdventureWorksLT2008_DataEntities adventureWorksObjectContext = new AdventureWorksLT2008_DataEntities())

8-14

Developing Web Applications with Microsoft Visual Studio 2010

// Retrieve all male customers, ordered by last name var customersQuery = from customers in adventureWorksObjectContext.Customers where customers.Title == "Mr." orderby customers.LastName select customers; // Loop through returned objects foreach (Customer cust in customersQuery) { // Display first and last name of returned objects Response.Write(cust.FirstName + " " + cust.LastName + "<br/>"); }

Notice how the customers are ordered by last name and how you can loop through the returned objects. Question: What is the first step when you want to use an Entity Data Model from your code? Answer: You need to create an instance of the ObjectContext derived type.

Optimizing Data Management for Web Forms

8-15

CRUD Operations Using LINQ to Entities

Key Points
When you want to use LINQ to Entities to manage the data in the database in which your EDM is modeled, you need to perform the updates locally, and subsequently update the database. So, if you have an ObjectContext derived type, this is how you can manage the data locally. [Visual Basic]
Using adventureWorksObjectContext As New AdventureWorksLT2008_DataEntities() ' Add new category to the ProductCategories collection adventureWorksObjectContext.ProductCategories.AddObject(New ProductCategory With { .Name = "Fab Bikes", .ModifiedDate = DateTime.Now }) ' Find product Dim productQuery = From products In adventureWorksObjectContext.Products Where products.ProductID = 680 Select products ' Delete found product adventureWorksObjectContext.Products.DeleteObject( productQuery.First) ' Find customer Dim customersQuery = From customers In adventureWorksObjectContext.Customers Where customers.CustomerID = 28 Select customers ' Update found customer Dim customer = customersQuery.First() customer.FirstName = "Kim" customer.MiddleName = ""

8-16

Developing Web Applications with Microsoft Visual Studio 2010

customer.LastName = "Abercrombie" ' Submit changes adventureWorksObjectContext.SaveChanges() Catch ex As Exception Response.Write(ex.Message & "<br/>" & ex.InnerException.Message) End Try End Using Try

[Visual C#]
using (AdventureWorksLT2008_DataEntities adventureWorksObjectContext = new AdventureWorksLT2008_DataEntities()) { // Add new category to the ProductCategories collection adventureWorksObjectContext.ProductCategories.AddObject(new ProductCategory { Name = "Fab Bikes", ModifiedDate = DateTime.Now }); // Find product var productQuery = from products in adventureWorksObjectContext.Products where products.ProductID == 680 select products; // Delete found product adventureWorksObjectContext.Products.DeleteObject( productQuery.First()); // Find customer var customersQuery = from customers in adventureWorksObjectContext.Customers where customers.CustomerID == 28 select customers; // Update found customer var customer = customersQuery.First(); customer.FirstName = "Kim"; customer.MiddleName = ""; customer.LastName = "Abercrombie"; try {

} catch (Exception ex) { Response.Write(ex.Message + "<br/>" + ex.InnerException.Message); }

// Submit changes adventureWorksObjectContext.SaveChanges();

Notice how the SaveChanges method is called to submit the changes to the database. In addition, the AddObject and DeleteObject methods are used to add a new object and delete an existing object. Always wrap the SaveChanges method in a Try...Catch/try...catch construct, to catch any exceptions thrown by the database or the provider. In many cases, the actual exception thrown is wrapped in another exception, which is why it is good to view or log the messages from both exceptions. When you want to delete an object, you can also do it with a somewhat shorter syntax. [Visual Basic]

Optimizing Data Management for Web Forms

8-17

' Delete product adventureWorksObjectContext.Products.DeleteObject(adventureWorksObjectContext.Product s.Single(Function(p) p.ProductID = 680))

[Visual C#]
// Delete product adventureWorksObjectContext.Products.DeleteObject(adventureWorksObjectContext.Product s.Single(p => p.ProductID == 680));

It is definitely shorter and simpler, although the use of Lambdas can make your code harder to read. Keep in mind that even if the syntax is shorter, you still need to submit your changes to the database. Question: Which method is used to submit local changes to the database? Answer: The SaveChanges method is used to submit local changes to the database.

8-18

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 2

Using Data Source Controls

The ASP.NET framework comes with a number of web server controls, where many of them are databound and others are data source controls. The former are used to display data in a data source, such as an XML file or a database, whereas the latter are used to connect to and retrieve data from a data source and make it available for other controls to bind to, without requiring code. They can also support modifying data. This lesson explains how to use both types of controls, and describes some of the controls in detail.

Lesson Objectives
After completing this lesson, you will be able to: Describe data bound and data source controls. Describe the capabilities of data source controls. Use the LinqDataSource and EntityDataSource controls. Use the GridView, ListView, DetailsView, and Microsoft Chart controls.

Optimizing Data Management for Web Forms

8-19

Types of Data Source Controls

Key Points
Data source controls have a long history within the ASP.NET frameworksince version 2.0, to be exact and they have been increasingly popular with many developers. The different data source controls in the ASP.NET framework are: AccessDataSource, EntityDataSource, LinqDataSource, ObjectDataSource, SiteMapDataSource, SqlDataSource, and XmlDataSource. The following table describes these data source controls in detail. Data Source control AccessDataSource Description Enables you to work with a Microsoft Access database. Supports sorting, filtering, and paging when data is returned as a DataSet object. This control should only be used with an Access database. Enables you to bind to data that is based on the Entity Data Model (EDM). Supports automatic generation of update, insert, delete, and select commands. The control also supports sorting, filtering and paging. Enables you to use Language-Integrated Query (LINQ) in an ASP.NET web page through declarative markup to retrieve and modify data from a data object. Supports automatic generation of select, update, insert, and delete commands. The control also supports sorting, filtering, and paging. The LinqDataSource control can be used with a database or an in-memory data collection such as an array. Enables you to work with a business object or other class and create web applications that rely on middle-tier objects to manage data. Basically, the ObjectDataSource control supports three-tier architecture by providing a way for you to bind data controls on the page to a middle-tier business object. Supports advanced sorting and paging scenarios unavailable with the other data source controls.

EntityDataSource

LinqDataSource

ObjectDataSource

8-20

Developing Web Applications with Microsoft Visual Studio 2010

Data Source control SiteMapDataSource SqlDataSource

Description Used with ASP.NET site navigation for databinding controls. Enables you to work with Microsoft SQL Server, OLE DB, ODBC, or Oracle databases. When used with SQL Server, supports advanced caching capabilities. The control also supports sorting, filtering, and paging when data is returned as a DataSet object. Enables you to work with an XML file, especially for hierarchical ASP.NET server controls such as the TreeView or Menu control. Supports filtering capabilities using XPath expressions and enables you to apply an XSLT transformation to the data. The XmlDataSource allows you to update data by saving the entire XML document with changes.

XmlDataSource

The programming surface and design-time experience of the EntityDataSource, LinqDataSource, ObjectDataSource, SqlDataSource and XmlDataSource controls are very similar. Common to all of the data source controls, is that they can be configured declaratively, either manually (directly in the markup), or by specifying the properties in the Properties window. Alternatively, you can use the designers, which are available from Design view of the Web Form on which the data source control is placed.

EntityDataSource Control
The EntityDataSource control supports data binding scenarios in web applications that use the ADO.NET Entity Framework, and thus the EDM. The EntityDataSource control manages create, read, update, and delete operations against a data source on behalf of data-bound controls on the same web page. The EntityDataSource control works with editable grids, forms with user-controlled sorting and filtering, twoway bound drop-down list controls, and master-detail pages. You can supply parameter values to queries from page controls, cookies, query parameters appended to the page URI, and other ASP.NET parameter objects. The EntityDataSource designer makes it easier to configure an EntityDataSource control at design time.

LinqDataSource Control
The LinqDataSource control exposes LINQ to web developers through the ASP.NET data source control architecture. By using declarative markup, you can create a LinqDataSource control that connects to data from either a database or an in-memory data collection such as an array. In the declarative text, you can write all the conditions that are required to retrieve, filter, order, and group the data. When you retrieve data from a SQL database table, you can also configure a LinqDataSource control to handle updating, inserting, and deleting data. The control does this without requiring you to write the SQL commands to perform these tasks. The LinqDataSource class also provides an event model that enables you to handle customized scenarios.

Additional Reading
For more information about the AccessDataSource control, see AccessDataSource Web Server Control Overview at http://go.microsoft.com/fwlink/?LinkID=203958&clcid=0x409. For more information about the ObjectDataSource control, see ObjectDataSource Web Server Control Overview at http://go.microsoft.com/fwlink/?LinkID=203959&clcid=0x409.

Optimizing Data Management for Web Forms

8-21

For more information about the SiteMapDataSource control, see SiteMapDataSource Web Server Control Overview at http://go.microsoft.com/fwlink/?LinkID=203960&clcid=0x409. For more information about the SqlDataSource control, see SqlDataSource Web Server Control Overview at http://go.microsoft.com/fwlink/?LinkID=203961&clcid=0x409. For more information about the XmlDataSource control, see XmlDataSource Web Server Control Overview at http://go.microsoft.com/fwlink/?LinkID=203962&clcid=0x409. Question: Which data source control should you use for managing site navigation? Answer: You should you use the SiteMapDataSource control for managing site navigation.

8-22

Developing Web Applications with Microsoft Visual Studio 2010

Capabilities of Data Source Controls

Key Points
Data source controls have different capabilities, including binding, sorting, filtering, and modifying data.

Binding
The binding capability of the data source controls is what make them special; they expand the capabilities of databound controls such as the GridView, FormView, and DetailsView controls. Without this capability, there would be no need for data source controls. In fact, by working together, the data source controls and the databound controls let you retrieve, modify, page, sort, and filter data from different data sources with little or no code at all. You can work with data in a databound control by binding the databound control to a data source control such as the EntityDataSource or LinqDataSource control. The data source control is responsible for connecting to a data source, such as a database or an entity class, and then retrieving or updating the data. The databound control can then use this data. To perform the binding, you set the databound control's DataSourceID property to point to a data source control, by specifying the ID of the data source control. The databound control can automatically take advantage of the data services provided by the data source control, once databound. Here is an example of the LinqDataSource declared in markup bound to the NorthwindObjectContext, and a GridView control bound to the LinqDataSource control.
<asp:LinqDataSource ContextTypeName="NorthwindObjectContext" TableName="Products" ID="NorthWindLinqDataSource" runat="server" /> ... <asp:GridView ID="ProductsGridView" DataSourceID="NorthWindLinqDataSource" runat="server">

For the more complex databound controls, such as the GridView and FormView controls, there can be more to setting up the control, such as specifying where the individual columns from the data source are displayed. Here is an example of a FormView control, bound to the previously shown LinqDataSource control.

Optimizing Data Management for Web Forms

8-23

<asp:FormView ID="ProductsFormView" DataSourceID="NorthWindLinqDataSource" AllowPaging="true" runat="server"> <HeaderStyle forecolor="white" backcolor="Blue" /> <ItemTemplate> <table> <tr> <td align="right"><b>Product ID:</b></td> <td><asp:Label id="ProductIDLabel" runat="server" Text='<%# Eval("ProductID") %>' /></td> </tr> <tr> <td align="right"><b>Product Name:</b></td> <td><asp:Label id="ProductNameLabel" runat="server" Text='<%# Eval("ProductName") %>' /></td> </tr> ... </table> </ItemTemplate> <PagerTemplate> <table> <tr> <td> <asp:LinkButton ID="FirstButton" CommandName="Page" CommandArgument="First" Text="<<" runat="server"/> </td> ... </tr> </table> </PagerTemplate> </asp:FormView>

The important thing to notice is the Eval statements in the inline code blocks that reference the columns returned by the LinqDataSource and made available by the FormView control, to which all of the Label controls belong.

Sorting
The sorting capability of the data source controls is a handy feature that you can use to sort the data at runtime without requiring any code at all. Keep in mind, though, that sorting can be customized with code. To enable sorting of data at runtime, you can use the AccessDataSource, LinqDataSource, ObjectDataSource, or SqlDataSource control as your data source control. To display the data that can be sorted, you can use a GridView or a ListView control, because both controls provide a default sorting UI. The LinqDataSource control supports sorting when the AutoSort property is set to true (the default value).
AllowSorting="true"

The same is true for the AccessDataSource and SqlDataSource controls, but only when the DataSourceMode property is set to DataSet (the default value). The ObjectDataSource control supports sorting only if the object returned by the SelectMethod is a DataSet, DataTable, or DataView object.

Filtering
Data source controls provide filtering data based on the search criteria you specify. Filtering is especially convenient when working with cached data, because this means that you can provide search capabilities without having to re-run your queries. To filter data, you need to configure your data source control. The AccessDataSource or SqlDataSource controls, must have the DataSourceMode property set to DataSet.

8-24

Developing Web Applications with Microsoft Visual Studio 2010

DataSourceMode="DataSet"

When using the ObjectDataSource control, you must ensure that the underlying source object returns a DataSet or DataTable object. When using the XmlDataSource control, you can filter data using XPath queries. The LinqDataSource control supports sorting when the AutoSort property is set to true (the default value).
AllowSorting="true"

The same is true for the AccessDataSource and SqlDataSource controls, but only when the DataSourceMode property is set to DataSet (the default value). The ObjectDataSource control supports sorting only if the object returned by the SelectMethod is a DataSet, DataTable, or DataView object. You can set the FilterExpression property to specify the filter to be applied to the data returned, when using an AccessDataSource, ObjectDataSource, or SqlDataSource control. The syntax for the filter expression is based on the syntax of the Expression property of the DataColumn class. For the data source controls mentioned, you can provide a parameterized filter expression. This enables you to provide filter values at runtime without writing any code. You can specify the filter expression parameters by using the FilterParameters collection. The parameters can retrieve data from controls, the QueryString object, session state, form field values, cookie values, and user profile properties. In the filter expression, you create placeholders that correspond to items in the data source control's FilterParameters collection by specifying the number of the item on the zero-based collection. You specify a placeholder in the filter expression by placing the number of the filter parameter in '{' and '}' characters.
FirstName = '{0}' AND LastName LIKE '{1}'

Modifying
The one capability that makes the data source controls very useful is the ability to make databound controls such as the DetailsView, FormView, GridView, and ListView controls able to modify data in the data source without any additional code. The data source control performs the data modification, so that the databound controls can support updates. The AccessDataSource, ObjectDataSource, and SqlDataSource controls can be configured with data commands to insert, update, and delete data. When you use the LinqDataSource control for data modification, you do not have to provide commands to insert, update, and delete data. Those commands are automatically generated for you, as shown.
<asp:LinqDataSource ID="NorthwindLinqDataSource" ContextTypeName="NorthwindObjectContext" TableName="Products" EnableUpdate="true" EnableInsert="true" EnableDelete="true" runat="server"> </asp:LinqDataSource> <asp:DetailsView DataKeyNames="ProductID" AutoGenerateEditButton="true" AutoGenerateDeleteButton="true" AutoGenerateInsertButton="true" AllowPaging="true" DataSourceID="NorthwindLinqDataSource" ID="GridView1" runat="server"> </asp:DetailsView>

The AccessDataSource and SqlDataSource controls enable you to supply SQL commands for modifying the data. The InsertCommand, UpdateCommand, and DeleteCommand properties are used for this purpose.

Optimizing Data Management for Web Forms

8-25

The ObjectDataSource control enables you to specify a data object method for performing a specific type of update, by setting the InsertMethod, UpdateMethod, or DeleteMethod property. You can make the data-update scenarios more flexible and secure by using parameters to pass values to be inserted, updated, or deleted in a data store. Parameter values can include the values of controls on the page, ASP.NET application variables, session values, and so on. Parameter values typically come from databound controls when those controls invoke an update, insert, or delete operation. Additionally, you can create explicit parameter objects for the data source control for a given operation, which allows you to customize the parameters.

Additional Reading
For more information about binding by using data source controls, see Binding to Data Using a Data Source Control at http://go.microsoft.com/fwlink/?LinkID=203963&clcid=0x409. For more information about sorting by using data source controls, see Sorting Data with Data Source Controls at http://go.microsoft.com/fwlink/?LinkID=203964&clcid=0x409. For more information about filtering by using data source controls, see Filtering Data Using Data Source Controls at http://go.microsoft.com/fwlink/?LinkID=203965&clcid=0x409. For more information about filtering by using the XmlDataSource control, see Filtering Data Using the XmlDataSource Control at http://go.microsoft.com/fwlink/?LinkID=203966&clcid=0x409. For information on the types of parameters that can be used in the FilterParameters collection, see Using Parameters with Data Source Controls at http://go.microsoft.com/fwlink/?LinkID=2039674&clcid=0x409. Question: Which property of the LinqDataSource control should you set to enable sorting? Answer: You should set the AllowSorting property to a value of true to enable sorting.

8-26

Developing Web Applications with Microsoft Visual Studio 2010

Advanced GridView Control Techniques

Key Points
The GridView control has been around for a number of years, and it has been a favorite control for many developers over the years. Basically, it is used to display tabular data, and you can display, edit, and delete data from many different kinds of data sources, including databases, XML files, and business objects that expose data. Besides the more obvious uses, including automatically binding to and displaying data from a data source control, as well as the ability to select, sort, page through, edit, and delete data from a data source control, the GridView control also has some more advanced features. This includes utilizing templates to create custom user interface (UI) elements, as well as customized paging.

Templates
As is the case with most web server controls, the GridView control has a default look and layout, which can be customized by setting properties or by using styles. However, only some web server controls, including the GridView control, also allow you to customize their look by using templates. A template is a set of HTML elements and controls that make up the layout for a particular portion of a control. You can customize the GridView control's look by defining different templates for individual columns, as well as the pager. Templates can be created in the web form markup (.aspx) file, as XML declarations. The following example shows how you can customize the columns for a GridView at design-time.
<asp:GridView ID="CountriesGridView" runat="server" AutoGenerateColumns="False" DataSourceID="CountriesLinqDataSource"> <Columns> <asp:TemplateField HeaderText="ID" SortExpression="ID"> <EditItemTemplate> <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("ID") %>' /> </EditItemTemplate> <ItemTemplate>

Optimizing Data Management for Web Forms

8-27

<asp:Label ID="Label1" runat="server" Text='<%# Bind("ID") %>'></asp:Label> </ItemTemplate> </asp:TemplateField> <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" /> ... </Columns> </asp:GridView>

Notice how the AutoGenerateColumns property has been set to False, to prevent overriding of the customization at runtime. In addition, the columns are now specified in the Columns element, which holds two different types of columns. The last one is a typical BoundField control, which does not offer customization. However, the first one is the customized TemplateField column with a HeaderText property value of ID, and it does allow for customization. The TemplateField consists of two templates: the EditItemTemplate and the ItemTemplate. The EditItemTemplate holds the markup and controls to be used when then grid is in edit mode, and the ItemTemplate holds the markup and controls to be used when then grid is in display mode. Besides customizing the columns by using the TemplateField column, it is also possible to customize the display for an empty grid, that is, with no data to display. This is done by using the EmptyDataTemplate element.
<asp:GridView ID="CountriesGridView" runat="server" AutoGenerateColumns="True" DataSourceID="CountriesLinqDataSource"> <EmptyDataTemplate> There are no data to display. <!-- Child controls, if any --> </EmptyDataTemplate> </asp:GridView>

Custom Paging
The GridView control supports paging over the items in its data source. You set the AllowPaging property to true to enable paging. When the GridView control is bound to a data source control capable of returning a single page of data, the GridView control takes advantage of that capability. The GridView control can use custom paging in different ways. You can set the number of items to display at once by using the PageSize property.
<asp:GridView ID="ProductsGridView" PageSize="5" DataSourceID="NorthWindLinqDataSource" runat="server">

You can also set the current page of the GridView control by setting the PageIndex property. [Visual Basic]
' Display page 3

ProductsGridView.PageIndex = 3 [Visual C#]


// Display page 3 ProductsGridView.PageIndex = 3;

You can specify custom behavior by setting the PagerSettings property, which allows you to customize the appearance of the paging UI that is automatically generated by the GridView control. The GridView control can display direction controls that allow forward and backward navigation, as well as numeric controls that allow a user to move to a specific page. The PagerSettings property of the GridView control is set to a PagerSettings class, which exposes the following properties for UI customization.

8-28

Developing Web Applications with Microsoft Visual Studio 2010

Property Name FirstPageImageUrl FirstPageText LastPageImageUrl LastPageText Mode

Description Sets the URL to an image to display for the first-page button. Sets the text to display for the first-page button. Sets the URL to an image to display for the last-page button. Sets the text to display for the last-page button. Sets the mode in which to display the pager controls in a control that supports pagination. These are the valid values for this property: NextPrevious, NextPreviousFirstLast, Numeric, and NumericFirstLast. Sets the URL to an image to display for the next-page button. Sets the text to display for the next-page button. Sets the number of page buttons to display in the pager when the Mode property is set to the Numeric or NumericFirstLast value. Sets a value that specifies the location where the pager is displayed in the GridView control. The valid values are: Bottom, Top, TopAndBottom. Sets the URL to an image to display for the previous-page button. Sets the text to display for the previous-page button.

NextPageImageUrl NextPageText PageButtonCount Position

PreviousPageImageUrl PreviousPageText

You can also specify custom behavior by supplying a pager template. This is done by setting the PagerTemplate property. This property gets or sets custom content for the pager row in the GridView control. To specify which paging operation to perform, include a Button control with the CommandName property set to Page and a CommandArgument set to one of the following values: First, Last, Prev, Next, or a page number. ASP.NET Dynamic Data automatically adds a custom control named GridViewPager.ascx as the custom pager for the GridView control with the List.aspx and ListDetails.aspx page templates. Parts of the ListDetails.aspx web form are shown below.
<%@ Register src="~/DynamicData/Content/GridViewPager.ascx" tagname="GridViewPager" tagprefix="asp" %> ... <asp:GridView ID="ProductsGridView" runat="server" ... AllowPaging="True"> ... <PagerTemplate> <asp:GridViewPager runat="server" /> </PagerTemplate> ... </asp:GridView>

Additional Reading
For more information about the PagerSettings class, see PagerSettings Class at http://go.microsoft.com/fwlink/?LinkID=203968&clcid=0x409. Question: Which XML element is used for customizing the display of an empty data source in the GridView control?

Optimizing Data Management for Web Forms

8-29

Answer: You use the EmptyDataTemplate element to customize the display of an empty data source in the GridView control.

8-30

Developing Web Applications with Microsoft Visual Studio 2010

Walkthrough: Creating a GridView TemplateField

Key Points
While it is possible to create templated fields, or TemplateField objects in your markup manually, it is easier and quicker to use the GridView Tasks dialog box. This dialog box is accessible, when you open your master page, web form, or user control, in Design view. As described in the previous topic, TemplateField objects can be used when the AutoGenerateColumns property of the GridView control is set to False. This means you must manually add the columns to be displayed to the user, and these must be added to the Columns item, in your markup. 1. 2. 3. 4. When in Design view, you first select the GridView control for which you want to create the TemplateField object(s). With the GridView control selected, click the Smart Tag button, and then in the GridView Tasks dialog box, click Edit Columns. With the Fields dialog box open, in the Selected fields list, click the existing field/column that you want to convert to a TemplateField object, and then click Convert this field into a TemplateField. If you want to create a new TemplateField object, with the Fields dialog box open, click TemplateField in the Available fields list, and then click Add.

Question: Which dialog box can be used to create a TemplateField object for the GridView control? Answer: You use the Fields dialog box to create a TemplateField object for the GridView control.

Optimizing Data Management for Web Forms

8-31

How to Use the ListView and DetailsView Controls

Key Points
Both the ListView and DetailsView controls are used to display data from a data source, but they are different in how the data is presented. The ListView control is similar to the GridView control, in that it displays the data in a tabular manner, whereas the DetailsView only displays the values for a single row from the data source at a time.

ListView
While the ListView is similar to the GridView control, in functionality and default appearance, it displays the values of a data source by using user-defined templates. This means that unlike the GridView control, you can customize the individual items amongst other customization options. In order for the ListView control to display content, you must create templates for different parts of the control. The ItemTemplate is required; all other templates are optional. The LayoutTemplate property is not required. The ListView control is useful for data in any repeating structure, similar to the DataList and Repeater controls. However, unlike those controls, by default, and without any coding, the ListView control enables the user to edit, insert, and delete data, and to sort and page data. The following example shows how the ListView control can be customized by using templates.
<asp:ListView ID="DepartmentsListView" runat="server" DataSourceID="DepartmentsDataSource" DataKeyNames="DepartmentID"> <LayoutTemplate> <table runat="server" id="DepartmentsTable"> <tr runat="server" id="itemPlaceholder" /> </table> </LayoutTemplate> <ItemTemplate> <tr runat="server"> <td>

8-32

Developing Web Applications with Microsoft Visual Studio 2010

<asp:Button ID="SelectButton" runat="server" Text="Select" CommandName="Select" /> <asp:Button ID="EditButton" runat="server" Text="Edit" CommandName="Edit" /> </td> <td> <asp:Label ID="IDLabel" runat="server" Text='<%#Eval("DepartmentID") %>' /> </td> ... </tr> </ItemTemplate> <SelectedItemTemplate> <tr class="SelectedItem" runat="server"> <td> <asp:Button ID="DeleteButton" runat="server" Text="Delete" CommandName="Delete" /> <asp:Button ID="EditButton" runat="server" Text="Edit" CommandName="Edit" /> </td> <td> <asp:Label ID="IDLabel" runat="server" Text='<%#Eval("DepartmentID") %>' /> </td> ... </tr> </SelectedItemTemplate> <EditItemTemplate> <tr class="EditItem"> <td> <asp:Button ID="UpdateButton" runat="server" CommandName="Update" Text="Update" /> <asp:Button ID="CancelButton" runat="server" CommandName="Cancel" Text="Cancel" /> </td> <td> <b>ID</b><br /> <asp:Label ID="IDLabel" runat="server" Text='<%#Eval("DepartmentID") %>' /> </td> ... </tr> </EditItemTemplate> <InsertItemTemplate> <tr class="InsertItem"> <td colspan="2"> <asp:Button ID="InsertButton" runat="server" CommandName="Insert" Text="Insert" /> <asp:Button ID="CancelButton" runat="server" CommandName="Cancel" Text="Cancel" /> </td> <td> <asp:Label runat="server" ID="NameLabel" AssociatedControlID="NameTextBox" Text="Name" Font-Bold="true"/><br /> ... </td> </tr> </InsertItemTemplate> </asp:ListView>

The LayoutTemplate element is used for specifying if and how the content should be contained. In the example, the content is contained in an HTML table element, which is also evident from the HTML tr and td elements in the content templates. The SelectedItemTemplate is used to specify the appearance for the currently selected item, if any. The ItemTemplate is used to specify the appearance for all items not covered by the other templates, such as the SelectedItemTemplate, EditItemTemplate, and InsertItemTemplate templates. The EditItemTemplate is used to specify the appearance for the item

Optimizing Data Management for Web Forms

8-33

currently being modified, if any. The InsertItemTemplate is used to specify the appearance for the item currently being modified for inserting, if any.

DetailsView
The DetailsView control displays the values of a single row from a data source in a table, and by default, each column/field from the data row is displayed on its own line/table row. Each data row in the DetailsView control is created by declaring a field control. Different row field types determine the behavior of the rows in the control. Field controls derive from DataControlField, and these are field types that can be used: BoundField, ButtonField, CheckBoxField, CommandField, HyperLinkField, ImageField, and TemplateField. The HyperLinkField is often used to display e-mail addresses and URLs, and the CheckBoxField is often used to display Boolean values. The DetailsView control can be used in combination with a GridView control for master-detail scenarios, as it is done in ASP.NET Dynamic Data, in the ListDetails.aspx page template.

Additional Reading
For more information about the ListView control, see ListView Web Server Control Overview at http://go.microsoft.com/fwlink/?LinkID=203969&clcid=0x409. For more information about the DetailsView control, see DetailsView Web Server Control Overview at http://go.microsoft.com/fwlink/?LinkID=203970&clcid=0x409. Question: Which ListView control template element do you use to specify the appearance for an item that is currently being edited? Answer: The EditItemTemplate is used to specify the appearance for the item currently being modified in a ListView control.

8-34

Developing Web Applications with Microsoft Visual Studio 2010

Using the Microsoft Chart Control

Key Points
The Microsoft Chart control provides rich data visualization for developers. It enables you to create ASP.NET pages with simple, intuitive, and visually compelling charts for complex statistical or financial analysis. The Chart control enables you to add robust charting abilities to your applications with little effort. In line with the other controls in this lesson, the Microsoft Chart control is used to present data in a number of different ways, by using the many distinct chart types, most of which support 3D. The Chart control can be found in the Toolbox, on the Data tab.

By binding the Chart control to a data source controls, as shown previously, you can show the data retrieved from the data source with little or no code, simply by settings the properties in your markup. The following markup shows how little configuration you can use, in many cases, to display the data in the data source control.
<asp:Chart ID="Chart1" runat="server" DataSourceID="LinqDataSource1"> <series> <asp:Series ChartType="Bubble" Name="Series1" YValuesPerPoint="6"> </asp:Series> </series> <chartareas>

Optimizing Data Management for Web Forms

8-35

<asp:ChartArea Name="ChartArea1"> </asp:ChartArea> </chartareas> </asp:Chart>

The easiest and simplest way to configure the Chart control is to add it to your web form in Design view, specify the data source control, and then select the chart type.

Once you have selected the chart type, you can preview not only the data from the data source, but also set the member for the X and axis for the first data series. The member is a column/field from the data returned by the data source control.

Configuring a Basic Chart


These are the basic steps to setting up your Chart control, once you have placed it on your web form. 1 2 Right-click the Chart control in the design area, and then click Properties. In the Properties window, click the Categorized button. In the Chart category of the Properties window, click the ChartAreas collection property, and then click the ellipsis button (). The ChartAreas Collection Editor opens. Note: The ChartAreas collection (a ChartAreaCollection object) contains all chart areas in the Chart control. Notice that the collection already contains a chart area named "ChartArea1". a. Click Add, and then click OK. A new ChartArea object is added to the collection with the default name "ChartArea2".

Note: The chart in the design area shrinks to half the original size. This is because the newly created chart area is placed at the bottom, but does not contain a data series yet. b. In the Properties window, click the Series collection, and then click the ellipsis button. The Series Collection Editor opens.

8-36

Developing Web Applications with Microsoft Visual Studio 2010

Note: The Series collection (a SeriesCollection object) contains all data series in the Chart control. Notice that the collection already contains a series named "Series1". c. In the Series Collection editor, click Add, and then set the following properties with the newly created Series object: Value ChartArea2 Bar BarChart Click OK, and then click OK again.

Property ChartArea ChartType Name d.

Now that there are chart areas, each chart area contains one data series. However, you will not see anything when you run your application because the series do not have any data yet.

Adding Legends to the Chart


1. In the Chart category of the Properties window, click the Legends collection property, and then click the button at the right. The Legend Collection Editor opens. Note: The Legends collection (a LegendCollection object) contains all legends in the Chart control. 2. If there is not already a legend in the Legend Collection editor, click Add. a. Set the following properties with the Legend object: Property DockedToChartArea Docking IsDockedInsideChartArea b. Value ChartArea1 Right False

Click Add again, and then set the following properties with the newly created Legend object: Value ChartArea2 Right

Property DockedToChartArea Docking c. Click OK.

Note: In the design area, the second legend is shown to be empty. By default, both series are assigned to the first legend. You can assign each series to a different legend. d. e. Open the Series Collection editor again. In the Members area, select BarChart.

Optimizing Data Management for Web Forms

8-37

f.

In the Legend category of the BarChart properties area, in the Legend property's drop-down list, select Legend2, and then click OK.

Adding a Title to the Chart


In the Chart category of the Properties window, click the Titles collection property, and then click the ellipsis button. The Title Collection editor opens. Note: The Titles collection (a TitleCollection object) contains all titles in the Chart control. a. b. In the Legend Collection editor, click Add. In the Appearance category of the Title1 properties area, type a chart title in the Text property, and then click OK.

Additional Reading
For some samples of how to use the Microsoft Chart controls, see Samples Environment for Microsoft Chart Controls at http://go.microsoft.com/fwlink/?LinkID=203971&clcid=0x409. Question: Where in Visual Studio 2010 can you find the Chat control? Answer: The Chart control can be found on the Data tab of the Toolbox in Visual Studio 2010.

8-38

Developing Web Applications with Microsoft Visual Studio 2010

Lab 8A: Optimizing Data Management for Web Forms

Note: You can perform tasks in this lab either by using Visual Basic or Visual C# programming language. If you are using Visual Basic as your programming language, refer to the steps provided in the Section 1 of the lab document. If you are using Visual C# as your programming language, refer to the steps provided in Section 2 of the lab document.

Objectives
After completing this lab, you will be able to: Manage data by using the LinqDataSource control. Display data using the grid control. Display parent and child data in the list and detail controls. Display dashboard information using the chart control.

Introduction
In this lab, you will develop the administration section of the website by using various ASP.NET data source controls.

Optimizing Data Management for Web Forms

8-39

Lab Scenario

The AdventureWorks Sales team has requested the addition of an administration section to the website so that they can manage information, as well as provide a dashboard to senior management. As a first step toward this end, you need to create a set of web form pages that will enable the Sales team to do the following: View, add, edit, and delete products View sales orders View and edit customer details Display sales information in a graphical format (dashboard)

In this lab, you will develop the administration section of the website by using various ASP.NET data source controls.

8-40

Developing Web Applications with Microsoft Visual Studio 2010

Section 1: Visual Basic Exercise 1: Managing Data by Using LINQ to Entities


The main tasks in this exercise are as follows: Create a new Entity Framework data model.

Task 1: Open an existing ASP.NET web application


1. 2. 3. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the D:\Lab Files\VB\Lab 08\Starter\Exercise 01 folder.

Task 2: Create a new Entity Framework data model


1. Add an ADO.NET Entity Data Model project item named AdventureWorks.edmx. The data model should be generated from a database, by using the AdventureWorksLT2008 connection string from the Web.config file. All tables from the database, with the exception of the BuildVersion table, should be added to the data model. 2. 3. 4. Save and close the ADO.NET Entity Data Model item. Build the project and fix any errors. Close Visual Studio 2010.

Optimizing Data Management for Web Forms

8-41

Exercise 2: Customizing the GridView


The main tasks in this exercise are as follows: 1. 2. 3. 4. 5. 6. 7. 8. Create a Shopping Cart Quantity user control. Modify the ShoppingCart entity class. Convert a BoundField column to TemplateField. Add Computed column to the GridView control. Make GridView updatable. Add user control to TemplateField Implement GridView paging. Test the GridView control.

Task 1: Open an existing ASP.NET web application


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the the D:\Lab Files\VB\Lab 08\Starter\Exercise 02 folder.

Task 2: Create a Shopping Cart Quantity user control


1. 2. Create a new user control named Quantity.ascx. Add a TextBox control named QuantityTextBox to the user control.
<asp:TextBox ID="QuantityTextBox" runat="server"></asp:TextBox>

3.

Add a RequiredFieldValidator control named QuantityRequiredFieldValidator to the user control. The RequiredFieldValidator control must validate the QuantityTextBox control, and display the text You must fill in the Quantity. as the error message, if the user leaves the text box empty. The display mode must be dynamic.
<asp:RequiredFieldValidator ID="QuantityRequiredFieldValidator" runat="server" ErrorMessage="You must fill in the Quantity." ControlToValidate="QuantityTextBox" Display="Dynamic"></asp:RequiredFieldValidator>

4.

Add a public property named Text to the user control. The property must be of type String, and get and set the Text property of the QuantityTextBox control.
Public Property Text As String Get Return QuantityTextBox.Text End Get Set(ByVal value As String) QuantityTextBox.Text = value End Set End Property

5. 6.

Save and close the user control. Build the project and fix any errors.

8-42

Developing Web Applications with Microsoft Visual Studio 2010

Note: Observe the Build succeeded message in the Build pane of the Output window.

Task 3: Modify the ShoppingCart entity class


1. 2. Open the ShoppingCart.vb class file. Add a private member variable named productQuantity of type Integer to the ShoppingCart class.
Private productQuantity As Integer

3.

Modify the auto-implemented Quantity property, to get and set the productQuantity member variable.
Public Property Quantity As Integer Get Return productQuantity End Get Set productQuantity = value End Set End Property

4.

Add an auto-implemented TotalPrice property, of type Decimal.


Public Property TotalPrice As Decimal

5.

Update the TotalPrice property, when the Quantity property is set.


TotalPrice = productQuantity * ListPrice

6. 7.

Save and close the ShoppingCart entity class. Build the project and fix any errors.

Task 4: Convert a BoundField column to TemplateField


1. 2. 3. 4. Open the ShoppingCart.aspx content page in Design view. Select the gvCart GridView control. Open the Fields dialog box for the GridView control, by using the Smart Tag. Convert the Quantity field to a template field.

Task 5: Add Computed column to GridView control


1. Append a new template field with a HeaderText property value of Total Price and close the Fields dialog box. 2. Open the ShoppingCart.aspx content page in Source view. Note: Observe how the Quantity field/column has been converted into a TemplateField, and the newly added Total Price TemplateField.

Task 6: Make GridView updatable


Open the ShoppingCart.aspx content page in Design view. a. Select the gvCart GridView control.

Optimizing Data Management for Web Forms

8-43

b. c. d. e. f.

Set the AutoGenerateEditButton property to a value of True. Add an event handler for the RowCancelingEdit event. Add an event handler for the RowEditing event. Add an event handler for the RowUpdating event. Make the existing code in the Page_Load event handler execute only on first request by wrapping the existing code in the Page_Load event handler in an If statement.

If Not IsPostBack Then End If

g.

Add a new Sub/void method named BindData to the ShoppingCart1 class.

Private Sub BindData() Dim cart As List(Of ShoppingCart) = CType(Session("_cart"), List(Of ShoppingCart)) gvCart.DataSource = cart gvCart.DataBind() End Sub

h.

Add code to the gvCart_RowEditing method, for setting the edit index and bind the data by using the BindData method.

Protected Sub gvCart_RowEditing(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewEditEventArgs) Handles gvCart.RowEditing ' Set edit index gvCart.EditIndex = e.NewEditIndex ' Bind data BindData() End Sub

i.

Add code to the gvCart_RowCancelingEdit method, for resetting the edit index and bind the data by using the BindData method.
Protected Sub gvCart_RowCancelingEdit(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewCancelEditEventArgs) Handles gvCart.RowCancelingEdit ' Reset edit index gvCart.EditIndex = -1 ' Bind data BindData() End Sub

j.

Add code to the gvCart_RowUpdating method, for retrieving the existing cart from Session.
' Retrieve existing cart from session Dim cart As List(Of ShoppingCart) = CType(Session("_cart"), List(Of ShoppingCart))

k.

Append code to the gvCart_RowUpdating method, for retrieving the current row from the GridView control.

' Get current row Dim row As GridViewRow = gvCart.Rows(e.RowIndex)

l.

Append code to the gvCart_RowUpdating method, for finding the matching row in the stored cart, stored in a new variable named cartToEdit of type ShoppingCart. Use the generic List Find method with an anonymous Lambda expression.
' Find matching row in stored cart Dim cartToEdit As ShoppingCart = cart.Find(Function(cartToFind) cartToFind.ProductId = Integer.Parse(row.Cells(1).Text))

m. Append code to the gvCart_RowUpdating method, for updating the quantity value of the cartToEdit shopping cart with the value of the Text property of the Quantity user control, located in the current row of the GridView control.

8-44

Developing Web Applications with Microsoft Visual Studio 2010

Dim qty As Quantity = CType(gvCart.Rows(e.RowIndex).FindControl("Quantity1"), Quantity) cartToEdit.Quantity = Integer.Parse(qty.Text)

n.

Append code to the gvCart_RowUpdating method, to save the updated cart to Session state.

' Save updated cart to session Session("_cart") = cart

o.

Append code to the gvCart_RowUpdating method, for resetting the edit index and bind the data by using the BindData method.

' Reset edit index gvCart.EditIndex = -1 ' Bind data BindData()

p. q.

Save and close the ShoppingCart code-behind file. Build the project and fix any errors.

Task 7: Add user control to TemplateField


Add the user control to the Shopping Cart Web Form.

Note: Observe how the Quantity user control has been registered using the Register directive, and the user control has been added to the Web Form. a. Move the markup for the Quantity user control to the top of the EditItemTemplate element.
<EditItemTemplate> <uc1:Quantity ID="Quantity1" runat="server" /> <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("Quantity") %>'></asp:TextBox> </EditItemTemplate>

b. c. d. e. f.

Copy the Text attribute and value from the TextBox1 control to the Quantity1 control.
<uc1:Quantity ID="Quantity1" runat="server" Text='<%# Bind("Quantity") %>' />

Delete the TextBox1 control. Make the ProductId BoundField control read-only. Format the display of the ListPrice BoundField control using the DataFormatString attribute and a value of {0:c}. Modify the format of the TemplateField control with a HeaderText attribute value of Total Price, to appear as follows.
<asp:TemplateField HeaderText="Total Price"> <ItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Eval("TotalPrice") %>' DataFormatString="{0:c}"></asp:Label> </ItemTemplate> </asp:TemplateField>

Task 8: Implement GridView paging


Set the AllowPaging property to true for GridView control. a. b. Set the PageSize property to 1 for GridView control. Add an event handler for the PageIndexChanging event.

Optimizing Data Management for Web Forms

8-45

c.

Add code to prevent page index to change, when in edit mode, and display an appropriate error message in the lblMessage Label control, by using the following code.

' Cancel paging operation if user attempts to navigate ' to another page while in edit mode If CType(sender, GridView).EditIndex <> -1 Then ' Cancel paging operation e.Cancel = True ' Display error message Dim newPageIndex As Integer = e.NewPageIndex + 1 lblMessage.Text = "Update the item before moving to page " & newPageIndex.ToString() Else ' Clear message text lblMessage.Text = "" ' Set page index CType(sender, GridView).PageIndex = e.NewPageIndex BindData() End If

d. e.

Save and close the ShoppingCart files. Build the project and fix any errors.

Task 9: Test the GridView control


Run the application. a. b. c. d. e. On the Home page, in the Product Categories list, click Bike Stands, and then click Submit. On the Products page, in the Bike Stands list, click All-Purpose Bike Stand. On the Product Detail page, click Order. On the Shopping Cart page, click Edit. In the Quantity box, type 5, and then click Update.

Note: Observe how the Quantity and Total Price columns are updated. f. g. h. i. On the Shopping Cart page, click Continue Shopping. On the Home page, in the Product Categories list, click Cranksets, and then click Submit. On the Products page, in the Cranksets list, click HL Crankset. On the Product Detail page, click Order.

Note: Observe that the customized pager has been added to the GridView, now that more items than the specified page size have been added to the GridView. j. k. l. On the Shopping Cart page, in the GridView pager, click 2. Close Windows Internet Explorer. Close Visual Studio 2010.

Note: The page index is changed and the content updated appropriately.

8-46

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 3: Using ListView, DetailsView and Charts


The main tasks in this exercise are as follows: 1. 2. 3. 4. Create the Sales Orders Master Details view. Test the Master Details view. Create the Sales Order Items History dashboard. Test the Master Details view.

Task 1: Open an existing ASP.NET web application


Open Microsoft Visual Studio 2010. a. Open the AdventureWorks solution from the D:\Lab Files\VB\Lab 08\Starter\Exercise 03 folder.

Task 2: Create the Sales Orders Master Details view


Build the project. a. b. c. d. e. f. g. h. i. j. k. l. Open the SalesOrders.aspx content page in Design view. Place the cursor in the HTML p element at the bottom of the MainContent Content control. Add a ListView control named SalesOrdersListView to the p element. Add a new LinqDataSource control, by using the SalesOrdersListView Smart Tag. Use LINQ as the data source, and name the LinqDataSource control SalesOrdersLinqDataSource, by using the Data Source Configuration Wizard. Select the AdventureWorks.AdventureWorks2008LTEntities object context using the existing Entity Data Model as the object context for the LinqDataSource control. Select the SalesOrderHeaders table and include the SalesOrderID, OrderDate, DueDate, ShipDate and CustomerID fields for the LinqDataSource control. Select only sales orders that have already shipped, by specifying a where clause, and compare ShipDate with the DateTime.Now method. Order the sales orders by CustomerID and ShipDate, by specifying an Order By clause. Finish the Data Source Configuration Wizard. Set the SalesOrderID field as the DataKeyNames property value. Open the SalesOrders.aspx web form in Source view.
<WhereParameters> <asp:Parameter DefaultValue="DateTime.Now" Name="ShipDate" Type="DateTime" /> </WhereParameters>

m. Remove the WhereParameters element from the LinqDataSource control.

n. o. p. q.

Modify the Where property to appear as follows. Open the SalesOrders.aspx web form in Design view. Configure the SalesOrdersListView control, by using the SalesOrdersListView Smart Tag. Refresh the schema before configuring the control. Select the Grid layout and the Professional style for the SalesOrdersListView control.

Where="ShipDate &lt;= DateTime.Now"

Optimizing Data Management for Web Forms

8-47

r. s. t.

Enable paging for the SalesOrdersListView control. Disable editing and inserting a SalesOrderHeader item in the SalesOrdersListView control, by deleting the corresponding templates in Source view. Add a Select button to the AlternatingItemTemplate and ItemTemplate elements. Use the Button server control and place it at the top of the HTML tr element.
<td> <asp:Button ID="SelectButton" runat="server" Text="Select" CommandName="Select" /> </td>

u.

Add an empty HTML th element to the LayoutTemplate element. Make the th element a server control and place it at the top of the HTML tr element.

<th runat="server"> </th>

v.

Add an empty HTML td element to the SelectedItemTemplate element. Place it at the top of the HTML tr element.

<td> </td>

w. Add an empty HTML p element below the existing p element.


<p> </p>

x.

Add a new LinqDataSource control with the following markup, within the empty HTML p element.

<asp:LinqDataSource ID="SalesOrderDetailsLinqDataSource" runat="server" ContextTypeName="AdventureWorks.AdventureWorksLT2008Entities" EntityTypeName="" TableName="SalesOrderDetails" Where="SalesOrderID == @SalesOrderID"> <WhereParameters> <asp:ControlParameter ControlID="SalesOrdersListView" Name="SalesOrderID" PropertyName="SelectedValue" Type="Int32" DefaultValue="0" /> </WhereParameters> </asp:LinqDataSource>

y.

Add a DetailsView control with the following markup, at the top of the new HTML p element.

<asp:DetailsView ID="SalesOrderDetailDetailsView" runat="server" DataSourceID="SalesOrderDetailsLinqDataSource" Height="50px" Width="125px" AutoGenerateRows="False"> <Fields> <asp:BoundField DataField="SalesOrderDetailID" HeaderText="SalesOrderDetailID" SortExpression="SalesOrderDetailID" /> <asp:BoundField DataField="OrderQty" HeaderText="OrderQty" SortExpression="OrderQty" /> <asp:BoundField DataField="ProductID" HeaderText="ProductID" SortExpression="ProductID" /> <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" /> <asp:BoundField DataField="UnitPriceDiscount" HeaderText="UnitPriceDiscount" SortExpression="UnitPriceDiscount" /> <asp:BoundField DataField="LineTotal" HeaderText="LineTotal" SortExpression="LineTotal" /> <asp:BoundField DataField="rowguid" HeaderText="rowguid" SortExpression="rowguid" /> <asp:BoundField DataField="ModifiedDate" HeaderText="ModifiedDate" SortExpression="ModifiedDate" /> </Fields>

8-48

Developing Web Applications with Microsoft Visual Studio 2010

</asp:DetailsView>

Task 3: Test the Master Details view


Run the application. a. b. c. On the Sales Orders page, click Select for any item in the ListView control. The DetailsView containing the Sales Order Details is displayed below the ListView control. Close Windows Internet Explorer.

Task 4: Create the Sales Order Items History dashboard


Open the SalesOrderItemsHistory.aspx content page in Source view. a. Add an EntityDataSource control named SalesOrderItemsEntityDataSource to the MainContent Content control.

<asp:EntityDataSource ID="SalesOrderItemsEntityDataSource" runat="server" ContextTypeName="AdventureWorks.AdventureWorksLT2008Entities" CommandText="SELECT Headers.SalesOrderNumber, Headers.OrderDate, SUM(Details.OrderQty) AS SalesOrderItems FROM SalesOrderHeaders AS Headers INNER JOIN SalesOrderDetails AS Details ON Headers.SalesOrderID = Details.SalesOrderID GROUP BY Headers.SalesOrderID, Headers.SalesOrderNumber, Headers.OrderDate" ConnectionString="name=AdventureWorksLT2008Entities" DefaultContainerName="AdventureWorksLT2008Entities" EnableFlattening="False"> </asp:EntityDataSource>

b. c. d. e.

Open the SalesOrderItemsHistory.aspx content page in Design view. Add a Chart control named SalesOrderItemsHistoryChart. Set the Chart type to Bar by using the Smart Tag. Use the SalesOrderItemsEntityDataSource control as the data source, by using the DataSourceID property, the X values should come from the SalesOrderItems field, the Y values should come from the OrderDate field. Refresh the schema, after selecting the data source control. Modify the default chart area, by setting the X and Y axis titles to # Sales Order Items and Order Date. Use the ChartArea Collection Editor, accessible from the Properties window.

f.

Task 5: Test the Master Details view


Run the application. Note: Observe how the Chart shows how the number of items per order are shown by order date. a. b. Close Internet Explorer. Close Visual Studio 2010.

Task 6: Turn off the virtual machine and revert the changes
In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. a. b. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert.

Optimizing Data Management for Web Forms

8-49

c.

In the Revert Virtual Machine dialog box, click Revert.

Note: The answers to the exercises are on the Course Companion CD.

8-50

Developing Web Applications with Microsoft Visual Studio 2010

Section 2: Visual C# Exercise 1: Managing Data by Using LINQ to Entities


The main tasks in this exercise are as follows: Create a new Entity Framework Data Model.

Task 1: Open an existing ASP.NET web application


Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the D:\Lab Files\CS\Lab 08\Starter\Exercise 01 folder.

Task 2: Create a new Entity Framework Data model


Add an ADO.NET Entity Data Model project item named AdventureWorks.edmx. The data model should be generated from a database, by using the AdventureWorksLT2008 connection string from the Web.config file. All tables from the database, with the exception of the BuildVersion table, should be added to the data model. a. b. c. Close the ADO.NET Entity Data Model item. Build the project and fix any errors. Close Visual Studio 2010.

Optimizing Data Management for Web Forms

8-51

Exercise 2: Customizing the GridView


The main tasks in this exercise are as follows: 1. 2. 3. 4. 5. 6. 7. 8. Create a Shopping Cart Quantity user control. Modify the ShoppingCart entity class. Convert a BoundField column to TemplateField. Add Computed Column to the GridView control. Make GridView updatable. Add user control to TemplateField. Implement GridView paging. Test the GridView control.

Task 1: Open an existing ASP.NET web application


Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the D:\Lab Files\CS\Lab 08\Starter\Exercise 02 folder.

Task 2: Create a Shopping Cart Quantity user control


Create a new user control named Quantity.ascx. a. b. Add a TextBox control named QuantityTextBox to the user control. Add a RequiredFieldValidator control named QuantityRequiredFieldValidator to the user control. The RequiredFieldValidator control must validate the QuantityTextBox control, and display the text You must fill in the Quantity. as the error message, if the user leaves the text box empty. The display mode must be dynamic.
<asp:TextBox ID="QuantityTextBox" runat="server"></asp:TextBox>

<asp:RequiredFieldValidator ID="QuantityRequiredFieldValidator" runat="server" ErrorMessage="You must fill in the Quantity." ControlToValidate="QuantityTextBox" Display="Dynamic"></asp:RequiredFieldValidator>

c.

Add a public property named Text to the user control. The property must be of type string, and get and set the Text property of the QuantityTextBox control.

public string Text { get { return QuantityTextBox.Text; } set { QuantityTextBox.Text = value; } }

d. e.

Save and close the user control. Build the project and fix any errors.

Note: Observe the Build succeeded message in the Build pane of the Output window.

8-52

Developing Web Applications with Microsoft Visual Studio 2010

Task 3: Modify ShoppingCart Entity class


Open the ShoppingCart.cs class file. a. b. Add a private member variable named productQuantity of type int to the ShoppingCart class. Modify the auto-implemented Quantity property, to get and set the productQuantity member variable.
private int productQuantity;

public int Quantity { get { return productQuantity; } set { productQuantity = value; } }

c. d. e. f.

Add an auto-implemented TotalPrice property, of type decimal. Update the TotalPrice property, when the Quantity property is set. Save and close the ShoppingCart entity class. Build the project and fix any errors.

public decimal TotalPrice { get; set; } TotalPrice = productQuantity * ListPrice;

Task 4: Convert a BoundField column to TemplateField


Open the ShoppingCart.aspx content page in Design view. a. b. c. Select the gvCart GridView control. Open the Fields dialog box for the GridView control, by using the Smart Tag. Convert the Quantity field to a template field.

Task 5: Add Computed column to GridView control


1 2 Append a new template field with a HeaderText property value of Total Price and close the Fields dialog box. Open the ShoppingCart.aspx content page in Source view. Note: Observe how the Quantity field/column has been converted into a TemplateField, and the newly added Total Price TemplateField.

Task 6: Make GridView updatable


Open the ShoppingCart.aspx content page in Design view. a. b. c. d. Select the gvCart GridView control. Set the AutoGenerateEditButton property to a value of True. Add an event handler for the RowCancelingEdit event. Add an event handler for the RowEditing event.

Optimizing Data Management for Web Forms

8-53

e. f.

Add an event handler for the RowUpdating event. Make the existing code in the Page_Load event handler execute only on first request by wrapping the existing code in the Page_Load event handler in an if statement.

if (!IsPostBack) { }

g.

Add a new void method named BindData to the ShoppingCart class.

private void BindData() { List<ShoppingCart> cart = (List<ShoppingCart>) Session["_cart"]; gvCart.DataSource = cart; gvCart.DataBind(); }

h.

Add code to the gvCart_RowEditing method, for setting the edit index and bind the data by using the BindData method.

protected void gvCart_RowEditing(object sender, GridViewEditEventArgs e) { // Set edit index gvCart.EditIndex = e.NewEditIndex; // Bind data BindData(); }

i.

Add code to the gvCart_RowCancelingEdit method, for resetting the edit index and bind the data by using the BindData method.
protected void gvCart_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e) { // Reset edit index gvCart.EditIndex = -1; // Bind data BindData(); }

j.

Add code to the gvCart_RowUpdating method, for retrieving the existing cart from Session.
// Retrieve existing cart from session List<ShoppingCart> cart = (List<ShoppingCart>) Session["_cart"];

k.

Append code to the gvCart_RowUpdating method, for retrieving the current row from the GridView control.

// Get current row GridViewRow row = gvCart.Rows[e.RowIndex];

l.

Append code to the gvCart_RowUpdating method, for finding the matching row in the stored cart, stored in a new variable named cartToEdit of type ShoppingCart. Use the generic List Find method with an anonymous Lambda expression.
// Find matching row in stored cart ShoppingCart cartToEdit = cart.Find((cartToFind) => cartToFind.ProductId == int.Parse(row.Cells[1].Text));

m. Append code to the gvCart_RowUpdating method, for updating the quantity value of the cartToEdit shopping cart with the value of the Text property of the Quantity user control, located in the current row of the GridView control.
// Update values Quantity qty = gvCart.Rows[e.RowIndex].FindControl("Quantity1") as Quantity; cartToEdit.Quantity = int.Parse(qty.Text);

n.

Append code to the gvCart_RowUpdating method, for saving the updated cart to Session state.

8-54

Developing Web Applications with Microsoft Visual Studio 2010

// Save updated cart to session Session["_cart"] = cart;

o.

Append code to the gvCart_RowUpdating method, for resetting the edit index and bind the data by using the BindData method.

// Reset edit index gvCart.EditIndex = -1; // Bind data BindData();

p. q.

Save and close the ShoppingCart code-behind file. Build the project and fix any errors.

Task 7: Add User control to TemplateField


Add the user control to the Shopping Cart web form. a. Open the ShoppingCart.aspx content page in Source view.

Note: Observe how the Quantity user control has been registered using the Register directive, and the user control has been added to the web form. b. Move the markup for the Quantity user control to the top of the EditItemTemplate element.

<EditItemTemplate> <uc1:Quantity ID="Quantity1" runat="server" /> <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("Quantity") %>'></asp:TextBox> </EditItemTemplate>

c. d.

Copy the Text attribute and value from the TextBox1 control to the Quantity1 control. Delete the TextBox1 control.

<uc1:Quantity ID="Quantity1" runat="server" Text='<%# Bind("Quantity") %>' /> <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("Quantity") %>'></asp:TextBox>

e. f.

Make the ProductId BoundField control read-only. Format the display of the ListPrice BoundField control using the DataFormatString attribute and a value of {0:c}.

ReadOnly="true"

DataFormatString="{0:c}"

g.

Modify the format of the TemplateField control with a HeaderText attribute value of Total Price, to appear as follows.

<asp:TemplateField HeaderText="Total Price"> <ItemTemplate> <asp:Label ID="Label1" runat="server" Text='<%# Eval("TotalPrice") %>' DataFormatString="{0:c}"></asp:Label> </ItemTemplate> </asp:TemplateField>

Task 8: Implement GridView paging


Set the AllowPaging property to true for GridView control. a. Set the PageSize property to 1 for GridView control.

Optimizing Data Management for Web Forms

8-55

b. c.

Add an event handler for the PageIndexChanging event. Add code to prevent page index to change, when in edit mode, and display an appropriate error message in the lblMessage Label control, by using the following code.

// Cancel paging operation if user attempts to navigate // to another page while in edit mode if (((GridView) sender).EditIndex != -1) { // Cancel paging operation e.Cancel = true; // Display error message int newPageIndex = e.NewPageIndex + 1; lblMessage.Text = "Update the item before moving to page " + newPageIndex.ToString();

} else { // Clear message text lblMessage.Text = ""; // Set page index ((GridView) sender).PageIndex = e.NewPageIndex; BindData(); }

d. e.

Save and close the ShoppingCart files. Build the project and fix any errors.

Task 9: Test GridView control


Run the application. a. b. c. d. e. On the Home page, in the Product Categories list, click Bike Stands, and then click Submit. On the Products page, in the Bike Stands list, click All-Purpose Bike Stand. On the Product Detail page, click Order. On the Shopping Cart page, click Edit. In the Quantity box, type 5, and then click Update.

Note: Observe how the Quantity and Total Price columns are updated. f. g. h. i. On the Shopping Cart page, click Continue Shopping. On the Home page, in the Product Categories list, click Cranksets, and then click Submit. On the Products page, in the Cranksets list, click HL Crankset. On the Product Detail page, click Order.

Note: Observe that the customized pager has been added to the GridView, now that more items than the specified page size has been added to the GridView. j. On the Shopping Cart page, in the GridView pager, click 2.

Note: Observe that the page index is changed and the content updated appropriately.

8-56

Developing Web Applications with Microsoft Visual Studio 2010

k. l.

Close Windows Internet Explorer. Close Visual Studio 2010.

Optimizing Data Management for Web Forms

8-57

Exercise 3: Using ListView, DetailsView and Charts


The main tasks in this exercise are as follows: 1. 2. 3. 4. Create the Sales Orders Master Details view. Test the Master Details view. Create the Sales Order Items History dashboard. Test the Master Details view.

Task 1: Open an existing ASP.NET web application


Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the D:\Lab Files\CS\Lab 08\Starter\Exercise 03 folder.

Task 2: Create the Sales Orders Master Details view


Build the project. a. b. c. d. e. f. g. h. i. j. k. l. Open the SalesOrders.aspx content page in Design view. Select the HTML p element at the bottom of the MainContent Content control. Add a ListView control named SalesOrdersListView to the p element. Add a new LinqDataSource control, by using the SalesOrdersListView Smart Tag. Use LINQ as the data source, and name the LinqDataSource control SalesOrdersLinqDataSource, by using the Data Source Configuration Wizard. Select the AdventureWorks.AdventureWorksLT2008Entities object context from the existing Entity Data Model as the object context for the LinqDataSource control. Select the SalesOrderHeaders table and include the SalesOrderID, OrderDate, DueDate, ShipDate and CustomerID fields for the LinqDataSource control. Select only sales orders that have already shipped, by specifying a where clause, and compare ShipDate with the DateTime.Now method. Order the sales orders by CustomerID and ShipDate, by specifying an Order By clause. Finish the Data Source Configuration Wizard. Set the SalesOrderID field as the DataKeyNames property value. Open the SalesOrders.aspx web form in Source view.
<WhereParameters> <asp:Parameter DefaultValue="DateTime.Now" Name="ShipDate" Type="DateTime" /> </WhereParameters>

m. Remove the WhereParameters element from the LinqDataSource control.

n. o. p. q.

Modify the Where property to appear as follows. Open the SalesOrders.aspx web form in Design view. Configure the SalesOrdersListView control, by using the SalesOrdersListView Smart Tag. Refresh the schema before configuring the control. Select the Grid layout and the Professional style for the SalesOrdersListView control.

Where="ShipDate &lt;= DateTime.Now"

8-58

Developing Web Applications with Microsoft Visual Studio 2010

r. s. t.

Enable paging for the SalesOrdersListView control. Disable editing and inserting a SalesOrderHeader item in the SalesOrdersListView control, by deleting the corresponding templates. Add a Select button to the AlternatingItemTemplate and ItemTemplate elements. Use the Button server control and place it at the top of the HTML tr element.
<td> <asp:Button ID="SelectButton" runat="server" Text="Select" CommandName="Select" /> </td>

u.

Add an empty HTML th element to the LayoutTemplate element. Make the th element a server control and place it at the top of the HTML tr element.

<th runat="server"> </th>

v.

Add an empty HTML td element to the SelectedItemTemplate element. Place it at the top of the HTML tr element.

<td> </td>

w. Add an empty HTML p element below the existing p element.


<p> </p>

x.

Add a new LinqDataSource control with the following markup, within the empty HTML p element.

<asp:LinqDataSource ID="SalesOrderDetailsLinqDataSource" runat="server" ContextTypeName="AdventureWorks.AdventureWorksLT2008Entities" EntityTypeName="" TableName="SalesOrderDetails" Where="SalesOrderID == @SalesOrderID"> <WhereParameters> <asp:ControlParameter ControlID="SalesOrdersListView" Name="SalesOrderID" PropertyName="SelectedValue" Type="Int32" DefaultValue="0" /> </WhereParameters> </asp:LinqDataSource>

y.

Add a DetailsView control with the following markup, at the top of the new HTML p element.

<asp:DetailsView ID="SalesOrderDetailDetailsView" runat="server" DataSourceID="SalesOrderDetailsLinqDataSource" Height="50px" Width="125px" AutoGenerateRows="False"> <Fields> <asp:BoundField DataField="SalesOrderDetailID" HeaderText="SalesOrderDetailID" SortExpression="SalesOrderDetailID" /> <asp:BoundField DataField="OrderQty" HeaderText="OrderQty" SortExpression="OrderQty" /> <asp:BoundField DataField="ProductID" HeaderText="ProductID" SortExpression="ProductID" /> <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" SortExpression="UnitPrice" /> <asp:BoundField DataField="UnitPriceDiscount" HeaderText="UnitPriceDiscount" SortExpression="UnitPriceDiscount" /> <asp:BoundField DataField="LineTotal" HeaderText="LineTotal" SortExpression="LineTotal" /> <asp:BoundField DataField="rowguid" HeaderText="rowguid" SortExpression="rowguid" /> <asp:BoundField DataField="ModifiedDate" HeaderText="ModifiedDate" SortExpression="ModifiedDate" /> </Fields>

Optimizing Data Management for Web Forms

8-59

</asp:DetailsView>

Task 3: Test the Master Details view


Run the application. a. b. c. On the Shopping Cart page, click Select, for any item in the ListView control. The DetailsView containing the Sales Order Details is displayed below the ListView control. Close Windows Internet Explorer.

Task 4: Create the Sales Order Items History dashboard


Open the SalesOrderItemsHistory.aspx content page in Source view. a. Add an EntityDataSource control named SalesOrderItemsEntityDataSource to the MainContent Content control.

<asp:EntityDataSource ID="SalesOrderItemsEntityDataSource" runat="server" ContextTypeName="AdventureWorks.AdventureWorksLT2008Entities" CommandText="SELECT Headers.SalesOrderNumber, Headers.OrderDate, SUM(Details.OrderQty) AS SalesOrderItems FROM SalesOrderHeaders AS Headers INNER JOIN SalesOrderDetails AS Details ON Headers.SalesOrderID = Details.SalesOrderID GROUP BY Headers.SalesOrderID, Headers.SalesOrderNumber, Headers.OrderDate" ConnectionString="name=AdventureWorksLT2008Entities" DefaultContainerName="AdventureWorksLT2008Entities" EnableFlattening="False"> </asp:EntityDataSource>

b. c. d. e.

Open the SalesOrderItemsHistory.aspx content page in Design view. Add a Chart control named SalesOrderItemsHistoryChart. Set the Chart type to Bar by using the Smart Tag. Use the SalesOrderItemsEntityDataSource control as the data source, by using the DataSourceID property, the X values should come from the SalesOrderItems field, the Y values should come from the OrderDate field. Refresh the schema, after selecting the data source control. Modify the default chart area, by setting the X and Y axis titles to # Sales Order Items and Order Date. Use the ChartArea Collection Editor, accessible from the Properties window.

f.

Task 5: Test the Master Details view


Run the application. Note: Observe how the Chart shows how the number of items per order are shown by order date. a. b. Close Internet Explorer. Close Visual Studio 2010.

Task 6: Turn off the virtual machine and revert the changes
In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. a. b. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert.

8-60

Developing Web Applications with Microsoft Visual Studio 2010

c.

In the Revert Virtual Machine dialog box, click Revert.

Note: The answers to the exercises are on the Course Companion CD.

Optimizing Data Management for Web Forms

8-61

Lab Review

Review Questions and Answers


Question: Why did you create a templated column in the GridView control? Answer: You created the templated column in the GridView control to add a custom user control, which is used to display the shopping cart quantity. Question: For which purpose did you use the DetailsView control? Answer: You used the DetailsView control to display the details of a selected order.

8-62

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 3

Using ASP.NET Dynamic Data

Because of the amount of markup and code that must be created when you enable data in your data source to be viewed and possibly managed from a web interface, it can be advantageous to use page templates for this purpose and thus save valuable development time. Using ASP.NET Dynamic Data, you can set up your data source, a data model to manage the data, a scaffolding to determine which tables and columns get displayed, the routing to specify the way the user can request to view the various tables, and the page and field templates that determine the behavior of the tables and fields when displayed. ASP.NET Dynamic Data is a framework that enables you to build a functional, data-driven application quickly, based on an Entity Framework or LINQ to SQL data model. ASP.NET Dynamic Data is specifically used to create data-driven applications. Data-driven applications use, manipulate, and analyze data to perform tasks. ASP.NET Dynamic Data can also be used for creating websites that display and manage data that is automatically read and written to the data source, with little or no coding. This lesson explains what ASP.NET Dynamic Data is, and in which scenarios it can be used. It also discusses the scaffolding and routing features of ASP.NET Dynamic Data. In addition, you will learn how to create an ASP.NET Dynamic Data web application.

Lesson Objectives
After completing this lesson, you will be able to: Describe ASP.NET Dynamic Data and its features. Identify the scenarios in which ASP.NET Dynamic Data is used. Describe the scaffolding feature of ASP.NET Dynamic Data. Describe the routing feature of ASP.NET Dynamic Data.

Optimizing Data Management for Web Forms

8-63

Create an ASP.NET Dynamic Data web application.

8-64

Developing Web Applications with Microsoft Visual Studio 2010

What Is ASP.NET Dynamic Data?

Key Points
The ASP.NET Dynamic Data framework is used to create data-driven ASP.NET web applications. Some of the features of ASP.NET Dynamic Data is that the ASP.NET Dynamic Data framework can automatically discover the metadata of the data model at runtime, and then use this metadata to derive the UI behavior. A scaffolding framework provides a functional website to manage the data provided by the model. The scaffolding framework exposes a default behavior that you can override.

Scaffolding
Scaffolding is used to enhance the existing ASP.NET web forms page framework by dynamically displaying pages based on the data and the metadata exposed by the data model. Scaffolding provides the following capabilities: Allows you to create a data-driven web application with little or no code. Provides built-in data validation based on the database schema, as exposed by the data model. Automatically creates filters for each foreign key or Boolean field, which are derived from the database schema, as exposed by the data model. You can customize the existing filters or create your own filters.

Data Model
The data model is used to represent the information in a database and depicts how the various database objects are related. ASP.NET Dynamic Data currently supports both the ADO.NET Entity Framework data model and the LINQ to SQL data model. If you register a data model with ASP.NET Dynamic Data, the data model can perform automatic validation of the various data fields. You can also control the appearance and behavior of data at the data layer level, by annotating or applying attributes to the data model. For example, you can annotate whether a table should be part of the web application and whether a field should be shown when the data in the containing table is displayed. You can also add a display name attribute for a field that it is

Optimizing Data Management for Web Forms

8-65

different from the actual field name, a field description attribute that is used by Dynamic Data to add a tooltip when you mouse over the control that is used to display the field and value, custom formatting for different values (such as dates and times), change the order in which the fields are arranged, and specify the resources used for localizing the field names. You can include multiple data models in an ASP.NET Dynamic Data web application or an ASP.NET Dynamic Data website, but the models that are used for the scaffolding must be of the same type. ASP.NET Dynamic Data is model oriented, because the ASP.NET Dynamic Data infrastructure is entirely based on the data model. You can use the ASP.NET Dynamic Data infrastructure to control the request routing, control the look and feel of the user interface, and manage the data in the data source.

Templates
ASP.NET Dynamic Data uses a number of generic templates to display various data. This includes page templates and field templates. The templates are disk-based files, such as ASP.NET Web Form and User Control templates. These templates are used at runtime by ASP.NET Dynamic Data for generating the rendered pages and controlling the pages that contain data from the data source. Page Templates. You can use page templates to provide a default view of data entities. These templates are ASP.NET web forms configured to display data from any entity in the data model. ASP.NET Dynamic Data provides page templates for different views of data: Details view: Displays the details for a single row. Edit view: Allows the user to edit rows. Insert view: Allows the user to insert a row. List Details: Displays parent and child entities as a master and details view. List view: Displays the table rows. This is the default view.

You can modify the routing for your web application to use any page template as the default template, or to use different page templates for different purposes. You can customize the existing page templates or create custom page templates for a specific entity in your data model. Field Templates. ASP.NET Dynamic Data uses field templates to render the UI for managing the data in the individual data fields. ASP.NET Dynamic Data determines the appropriate field template from the data field types in the data model schema. ASP.NET Dynamic Data includes separate field templates to display and edit data fields. For example, for a DateTime data field, Dynamic Data uses the following templates: Text.ascx. This template displays fields of type String, Decimal, Double, and integer types as literal text. Text_Edit.ascx. This template renders a TextBox control and is used for editing text values, if the TextMode property is set to SingleLine. You can customize the built-in field templates or create new ones to specify how individual data fields are rendered. You can override the use of the default field templates by creating your own custom field templates and then annotate the data model with the UIHint attribute to use those field templates.

Entity Templates. The ASP.NET Dynamic Data entity templates are user controls that let you customize the layout for a whole data row in a table. They give you better control over table layout than page templates. When you create an ASP.NET Dynamic Data web application, Visual Studio 2010 adds a DynamicData\EntityTemplates folder to the project, which contains the default entity templates, which display data in two columns, using a label for the field name and an appropriate control for the field value.

8-66

Developing Web Applications with Microsoft Visual Studio 2010

There are entity templates for display, edit, and insert operations. Entity templates are included in the Details.aspx, Insert.aspx, and Update.aspx page templates, and you can use them in custom page templates. Entity templates use field templates to render the actual data. The entity templates are displayed on a page by using the DynamicEntity control. At run time, Dynamic Data replaces this control with the contents of the applicable entity template.

Data Controls
ASP.NET Dynamic Data enhances existing data controls to include dynamic behavior. ASP.NET 4.0 provides several template-based databound controls, including the GridView, DetailsView, ListView, and FormView web server controls. ASP.NET Dynamic Data enhances these existing data controls to include dynamic behavior. The GridView and DetailsView controls display data dynamically by using predefined ASP.NET Dynamic Data templates. You can customize these templates and use specific controls for rendering the UI for managing the data fields. This enables you to make changes in one location and affect the appearance and behavior of the data controls across the web application. The DynamicField class is used by the GridView and DetailsView controls to display a field value. The ListView and FormView controls implement the behavior by using a DynamicControl control in their templates. You must manually specify the data entity field that the ListView and FormView controls need to manage. ASP.NET Dynamic Data automatically builds the UI for these controls, based on the specified templates. DynamicControl controls do not automatically render the UI for any field; you must bind the controls to a specific data field. Note: See Lesson 2 for more information on databound controls, including the GridView, DetailsView, ListView, and FormView web server controls. At run-time, ASP.NET Dynamic Data examines the data model metadata and provides automatic validation based on that metadata. For example, if a column in the database is marked as not nullable, a RequiredFieldValidator control is automatically rendered for that column. You can also apply custom metadata to customize further how data fields are rendered and validated, such as how a data is formatted for display, and how many characters a text column allows on input.

Additional Reading
For more information about how the data model represents the information in a database and how the objects in the database are related to each other, see ASP.NET Dynamic Data Model Overview at http://go.microsoft.com/fwlink/?LinkID=181296&clcid=0x409. For more information about the DynamicControl control, see DynamicControl Class at http://go.microsoft.com/fwlink/?LinkID=181291&clcid=0x409. For more information about the DynamicField control, see the DynamicField Class at http://go.microsoft.com/fwlink/?LinkID=181305&clcid=0x409. Question: What does scaffolding do in the context of ASP.NET Dynamic Data?

Optimizing Data Management for Web Forms

8-67

Answer: Scaffolding is used to enhance the existing ASP.NET web forms page framework by dynamically displaying pages based on the data and the metadata exposed by the data model.

8-68

Developing Web Applications with Microsoft Visual Studio 2010

ASP.NET Dynamic Data Usage Scenarios

Key Points
ASP.NET Dynamic Data is a fantastic tool that can save you a lot of time when creating data-driven web applications. However, it is more appropriate to use in some scenarios than others. In which scenarios is it most appropriate to use ASP.NET Dynamic Data? Consider the following scenarios and any other scenarios you can think of, and discuss all of these scenarios in the classroom. Rapid Application Development (RAD) Administration Pages Prototypes

Optimizing Data Management for Web Forms

8-69

Scaffolding Feature of ASP.NET Dynamic Data

Key Points
Scaffolding is the feature of ASP.NET Dynamic Data that makes it possible to create pages dynamically at runtime, based on the data model, by extending the existing ASP.NET web forms page framework. These autogenerated web form pages provide create, read, update, and delete (CRUD) operations for each entity. Scaffolding must be enabled for all entities or for one or more specific entities, and data validation is built in, based on the database schema. Note: If you enable scaffolding for all entities, any user, malicious or not, may be able to work out the schema of the database. If you are creating a simple data management application, or an administration section for an application, it might be the best choice to enable scaffolding for all entities, allowing you to save development time. Scaffolding is enabled on the registration of the data context or object context in the global application file. This registration is made by using the RegisterContext method, which takes a System.Web.DynamicData.ContextConfiguration object parameter. You are required to register the data context that will use the ASP.NET Dynamic Data features, even if you are not going to use the scaffolding mechanism. This registration is made in the Global.asax.vb or Global.asax.cs file by using the RegisterContext method. The RegisterContext method accepts a ContextConfiguration object as a parameter. To enable the scaffolding mechanism while registering the data or object context, set the ScaffoldAllTables property of the ContextConfiguration object to true, to enable the scaffolding mechanism for the entire data model. [Visual Basic]
DefaultModel.RegisterContext(GetType(MyObjectContext),

8-70

Developing Web Applications with Microsoft Visual Studio 2010

New ContextConfiguration() With {.ScaffoldAllTables = True})

[Visual C#]
DefaultModel.RegisterContext(typeof(MyObjectContext), new ContextConfiguration() { ScaffoldAllTables = true });

If you choose to use this approach, you can specifically hide entities from the scaffolding mechanism by using the ScaffoldTableAttribute attribute. You can use the ScaffoldTableAttribute attribute to set the ScaffoldAllTables property to False/false when registering with the data model. You can also use the ScaffoldTableAttribute attribute to enable or disable the scaffolding mechanism for a given entity, by applying the attribute to a partial class with the same name as the entity in the data model. In the following code examples, the partial class is manually created, with the scaffolding enabled for the Customers entity. [Visual Basic]
Imports System.ComponentModel.DataAnnotations <ScaffoldTable(True)> Partial Public Class Customer ... End Class

[Visual C#]
using System.ComponentModel.DataAnnotations; [ScaffoldTable(true)] public partial class Customer { ... }

Notice that the class is named, Customer, in singular, and not Customers in plural when you use the ADO.NET Entity Data Model or LINQ to SQL to name the classes. Because the Customer class is a partial class, you must use the same name that is used in the data model. You can also control the data fields that are being exposed, by applying the ScaffoldColumnAttribute attribute to enable or disable scaffolding for a particular data field. You must apply the attribute to a data field in a metadata class associated with the partial entity class. You must create the metadata class manually. You must also associate the metadata class with the partial entity class by applying the System.ComponentModel.DataAnnotations.MetadataTypeAttribute attribute to the partial class. The following example shows how a partial class for the Customers database entity is part of the scaffolding. However, by creating the CustomerMetadata class for the Customer class, the CreatedDate field will be hidden. [Visual Basic]
Public Class CustomerMetadata <ScaffoldColumn(False)> Public CreatedDate As Object End Class <ScaffoldTable(True)> <MetadataType(GetType(CustomerMetadata))> Partial Public Class Customer ... End Class

[Visual C#]
public class CustomerMetadata

Optimizing Data Management for Web Forms

8-71

{ }

[ScaffoldColumn(false)] public object CreatedDate;

[ScaffoldTable(true)] [MetadataType(typeof(CustomerMetadata))] public partial class Customer { ... }

The public properties in the metadata class are of type Object/object, and they override or hide a public property of the corresponding entity class in the meta model.

Template Customization
You can modify how ASP.NET Dynamic Data performs tasks that do not rely on a specific database schema. You can create these modifications one time and use them for any number of projects. This type of customization lets you define a consistent behavior for any schema without having to redefine the customization every time that you add or modify a data entity.

Page Templates
You can customize the layout for all tables, by changing the page templates that are in the DynamicData\PageTemplates folder. You can use this approach to change the appearance and behavior of all the tables in a website independently from the database. You can also customize the layout for an individual table, by creating a folder under the DynamicData\CustomPages whose name matches the name of the table in the data model. In the new folder, you add a page whose name matches the name of the default page template that you want to customize. You can use this approach to change the appearance and behavior of an individual table for a specific database.

Entity Templates
You can customize the layout for all tables, by customizing the default entity templates. You can perform this customization by changing the entity templates that are in the DynamicData\EntityTemplates folder, which gives you a more control than that provided by data field customization, and is useful if you want to apply a custom UI to default or custom page templates. You can also customize the layout for an individual table, by creating custom entity templates for the table whose layout you want to customize. If you were using the Entity Framework data model, entity templates for an Address table would be named Address.ascx, Address_Edit.ascx, and Address_Insert.ascx. If you were using the LINQ to SQL data model, entity templates for an Address table would be named Addresses.ascx, Addresses_Edit.ascx, and Addresses_Insert.ascx.

Field Templates
You can customize the UI for a specific data type, by changing the default field templates in the DynamicData\FieldTemplates folder. You can customize the UI for an individual data field in the database, by creating a custom field template and then map a data field declaratively to the template in a data-bound control.

Filter Templates
You can customize the filter for a specific data type, by modifying the controls in the DynamicData\FilterTemplates folder.

8-72

Developing Web Applications with Microsoft Visual Studio 2010

You can also create a custom filter, by creating an ASP.NET user control that derives from the QueryableFilterUserControl class. You can use this approach to override a default filter or to create a data type filter if a default one does not exist.

Additional Reading
For more information about how the MetaModel.RegisterContext method registers the data context with the meta model, see MetaModel.RegisterContext Method at http://go.microsoft.com/fwlink/?LinkID=181297&clcid=0x409. For more information about how the ContextConfiguration class provides information for a datacontext instance to allow customization, see ContextConfiguration Class at http://go.microsoft.com/fwlink/?LinkID=181298&clcid=0x409. For more information about how the MetadataTypeAttribute class specifies the metadata class to associate with a data model class, see MetadataTypeAttribute Class at http://go.microsoft.com/fwlink/?LinkID=181298&clcid=0x409. For more information about page template customization, see How to: Customize the Layout of an Individual Table By Using a Custom Page Template at http://go.microsoft.com/fwlink/?LinkID=192698&clcid=0x409. For more information about entity template customization, see Walkthrough: Customizing Table Layout Using Entity Templates at http://go.microsoft.com/fwlink/?LinkID=203972&clcid=0x409. For more information about field template customization, see How to: Customize ASP.NET Dynamic Data Default Field Templates at http://go.microsoft.com/fwlink/?LinkID=203974&clcid=0x409. For more information about filter template customization, see Walkthrough: Filtering Rows in Tables That Have a Parent-Child Relationship at http://go.microsoft.com/fwlink/?LinkID=203975&clcid=0x409. Question: What is the ScaffoldColumn attribute used for? Answer: It is used to show or hide a column/field in the UI.

Optimizing Data Management for Web Forms

8-73

Routing Feature of ASP.NET Dynamic Data

Key Points
ASP.NET Dynamic Data uses ASP.NET routing to match and handle URL requests. The routes are defined in the global application file. Scaffolding infers the view and the entity that a user wants to view from the URL requested. The benefit of using the routing mechanism is that the URL requested does not have to match the physical path in the application, but it can allow both physical files and dynamically-generated pages. By default, ASP.NET Dynamic Data uses a different page template for each request (list, select, edit, and insert), but you can modify the URL routing to use any page template as the default page for a specific operation, or to use different page templates for different purposes. You can customize the routes to specify different page templates. You can also customize them to display different URLs, remove the file extension (aspx), or pass parameters by using routes, instead of query string values. The following code, which is part of the default Global.asax.vb or Global.asax.cs file, specifies the default route to use, where a template is specified for each action on any table in the data model. [Visual Basic]
routes.Add(New DynamicDataRoute("{table}/{action}.aspx") With { .Constraints = New RouteValueDictionary(New With {.Action = "List|Details|Edit|Insert"}), .Model = DefaultModel})

[Visual C#]
routes.Add(new DynamicDataRoute("{table}/{action}.aspx") { Constraints = new RouteValueDictionary(new { action = "List|Details|Edit|Insert" }), Model = DefaultModel });

8-74

Developing Web Applications with Microsoft Visual Studio 2010

The following code examples, which are part of the default Global.asax.vb or Global.asax.cs file that is commented out by default, specifies the routes to use only one page template for all operations. [Visual Basic]
routes.Add(New DynamicDataRoute("{table}/ListDetails.aspx") With { .Action = PageAction.List, .ViewName = "ListDetails", .Model = DefaultModel}) routes.Add(New DynamicDataRoute("{table}/ListDetails.aspx") With { .Action = PageAction.Details, .ViewName = "ListDetails", .Model = DefaultModel})

[Visual C#]
routes.Add(new DynamicDataRoute("{table}/ListDetails.aspx") { Action = PageAction.List, ViewName = "ListDetails", Model = DefaultModel }); routes.Add(new DynamicDataRoute("{table}/ListDetails.aspx") { Action = PageAction.Details, ViewName = "ListDetails", Model = DefaultModel });

The first route enables all actions in the page for a given table, by using the ListDetails page template. The second route enables a page to navigate to the details of a record, such as navigating to a relationship table when you have a foreign key field. The routes are analyzed in the order they appear in the code. You need to first define the specific routes and then the generic ones, just as you declare the exception type order, when you wrap code in a Try/try statement. You can specify specific routes for specific tables, by specifying a different page template than the one used by the rest of the tables. The following examples show how to specify a different page template for the Customers entity, and then define a generic page template for the other tables of the data model. [Visual Basic]
routes.Add(New DynamicDataRoute("Customers/{action}.aspx") With { .ViewName = "ListDetails", .Table = "Customers", .Model = model}) routes.Add(New DynamicDataRoute("{table}/{action}.aspx") With { .Constraints = New RouteValueDictionary( New With {.Action = "List|Details|Edit|Insert"}), .Model = model})

[Visual C#]
routes.Add(new DynamicDataRoute("Customers/{action}.aspx") { ViewName = "ListDetails", Table = "Customers", Model = model }); routes.Add(new DynamicDataRoute("{table}/{action}.aspx") {

Optimizing Data Management for Web Forms

8-75

});

Constraints = new RouteValueDictionary( new { action = "List|Details|Edit|Insert" }), Model = model

Additional Reading
For more information about ASP.NET Routing, see ASP.NET Routing at http://go.microsoft.com/fwlink/?LinkID=181301&clcid=0x409. Question: In which file is ASP.NET Dynamic Data routing defined? Answer: ASP.NET Dynamic Data routing is defined in the global application file.

8-76

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Creating an ASP.NET Dynamic Data Web Application

Key Points
In this demonstration, you will learn how to create an ASP.NET Dynamic Data web application, and how to customize it. Perform the following step to create and customize the ASP.NET Dynamic Data web application. 1. Open Visual Studio 2010. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Create a web application by using the New Project dialog box. a. b. c. d. On the File menu, click New Project. In the New Project dialog box, in the left pane, click Visual Basic or Visual C#. In the middle pane, click ASP.NET Dynamic Data Entities Web Application. In the Name box, type DDWebApp, in the Location box, type D:\Demofiles\VB or D:\Demofiles\CS, and then click OK.

3.

Add an ADO.NET Entity Data Model project item named AdventureWorks.edmx. a. b. c. In Solution Explorer, right-click DDWebApp, point to Add, and then click New Item. In the Add New Item - DDWebApp dialog box, in the left pane, click Data, and then in the middle pane, click ADO.NET Entity data Model. In the Name box, type AdventureWorks.edmx, and then click Add.

4. 5.

In the Entity Data Model Wizard, on the Choose Model Contents page, click Generate from database, and then click Next. On the Choose Your Data Connection page, click New Connection.

Optimizing Data Management for Web Forms

8-77

6.

In the Connection Properties dialog box, in the Server name box, type 10264A-GENDEV\SQLEXPRESS, in the Select or enter a database name box, type AdventureWorksLT2008R2, and then click OK. In the Entity Data Model Wizard, on the Choose Your Data Connection page, click Next. On the Choose Your Database Objects page, in the Which database objects do you want to include in your model? list, expand Tables, select the Tables check box, clear the BuildVersion (dbo)check box, and then click Finish. Save and close the AdventureWorks.edmx file. a. b. On the File menu of Visual Studio 2010, click Save AdventureWorks.edmx. In the AdventureWorks.edmx window, click the Close button.

7. 8.

9.

10. In the Global.asax.vb or Global.asax.cs file, add context registration to the RegisterRoutes procedure. [Visual Basic]
DefaultModel.RegisterContext(GetType(AdventureWorksLT2008R2Entities), New ContextConfiguration() With {.ScaffoldAllTables = True})

[Visual C#]
DefaultModel.RegisterContext(typeof(AdventureWorksLT2008R2Entities), new ContextConfiguration() { ScaffoldAllTables = true });

In the Global.asax.vb or Global.asax.cs window, add the following code at the top of to the RegisterRoutes procedure.

[Visual Basic]
DefaultModel.RegisterContext(GetType(AdventureWorksLT2008R2Entities), New ContextConfiguration() With {.ScaffoldAllTables = True})

[Visual C#]
DefaultModel.RegisterContext(typeof(AdventureWorksLT2008R2Entities), new ContextConfiguration() { ScaffoldAllTables = true });

Note: Point out that this will register the Entity Data model object context for use by using the Dynamic Data field, and enable the automatic scaffolding of the data model. 11. Save and close the Global.asax.vb or Global.asax.cs file. a. b. On the File menu of Visual Studio 2010, click Save Global.asax.vb or Save Global.asax.cs. In the Global.asax.vb or Global.asax.cs window, click the Close button.

12. Build and run the web application. On the Debug menu of Visual Studio 2010, click Start Without Debugging. The page displayed in the browser displays a list of the tables you added to the data model. 13. Test the web application for the Dynamic Data functionality and view some of the dynamically generated pages.

8-78

Developing Web Applications with Microsoft Visual Studio 2010

a.

In the Dynamic Data Site Windows Internet Explorer window, click Addresses. The page displays the List view that contains the data from the Addresses table.

b.

In the Addresses - Windows Internet Explorer window, click Details, to the left of an address. The page displays the Details view that contains the data for the selected row from the Addresses table.

c.

In the Addresses - Windows Internet Explorer window, click Show all items, and then click PostalCode. The page displays the List view that contains the data of addresses, sorted by postal code.

d.

In the Addresses - Windows Internet Explorer window, in the first row, under CustomerAddresses, click View CustomerAddresses. The page displays the List view that contains the data of customer addresses.

e. f. g.

In the Address list, click All. In the CustomerAddresses - Windows Internet Explorer window, at the end of the page, click Insert new item to create a new customer address. In the CustomerAddresses - Windows Internet Explorer window, at the end of the page, click Insert, and view the smart validation that has been added to the required fields, and then click Cancel. The page displays the List view that contains the data from the CustomerAddresses table. This is the default view and the one you are returned to, after cancelling.

h.

In the CustomerAddresses - Windows Internet Explorer window, to the left of a customer address, click Edit to modify a customer address. The page displays the Edit view that contains the data for the selected row from the CustomerAddresses table.

i.

In the CustomerAddresses - Windows Internet Explorer window, at the end of the page, click Cancel to cancel the edit operation.

14. Close Windows Internet Explorer. In the CustomerAddresses Windows Internet Explorer window, click the Close button.

15. Close Visual Studio 2010. In the DDWebApp Microsoft Visual Studio window, click the Close button.

Additional Reading
For more information about how to create a data-driven website with minimal or no additional code, see the Walkthrough: Creating a New ASP.NET Dynamic Data Web Site Using Scaffolding at http://go.microsoft.com/fwlink/?LinkID=181302&clcid=0x409. Question: What is the RegisterContext method used for? Answer: The RegisterContext method is used for registering the data or object context.

Optimizing Data Management for Web Forms

8-79

Lab 8B: Optimizing Data Management for Web Forms

Note: You can perform tasks in this lab either by using Visual Basic or Visual C# programming language. If you are using Visual Basic as your programming language, refer to the steps provided in the Section 1 of the lab document. If you are using Visual C# as your programming language, refer to the steps provided in Section 2 of the lab document.

Objectives
After completing this lab, you will be able to: Manage data by using ASP.NET Dynamic Data.

Introduction
In this lab, you will develop the administration section of the website by using various ASP.NET data source controls and by using the ASP.NET Dynamic Data framework.

8-80

Developing Web Applications with Microsoft Visual Studio 2010

Lab Scenario

The AdventureWorks Sales team has requested the addition of an administration section to the website so that they can manage information, as well as provide a dashboard to senior management. As a first step toward this end, you need to create a set of web form pages that will enable the Sales team to do the following: View, add, edit, and delete products View sales orders View and edit customer details

In this lab, you will develop the administration section of the website by using the ASP.NET Dynamic Data framework.

Optimizing Data Management for Web Forms

8-81

Section 1: Visual Basic Exercise 4: Managing Data by Using ASP.NET Dynamic Data
The main tasks in this exercise are as follows: 1. 2. 3. 4. Create a new ASP.NET Dynamic Data web application. Add a new ADO.NET Entity Data Model. Register the object context. Run the application.

Task 1: Create a new ASP.NET Dynamic Data web application


Open Microsoft Visual Studio 2010. Create an ASP.NET Dynamic Data web application named AWDynamicData by using the New Project dialog box, and the ASP.NET Dynamic Data Entities Web Application project template. Place the project in the D:\Lab Files\VB\Lab 08\Starter\Exercise 04 folder.

Task 2: Add a new ADO.NET Entity Data Model


Add an ADO.NET Entity Data Model project item named AWEDM.edmx. a. Generate the model from the AdventureWorksLT2008R2 database, on the .\SQLEXPRESS server, and select only the Customer (SalesLT), SalesOrderDetail (SalesLT), and SalesOrderHeader (SalesLT) tables. Save and close the AWEDM.edmx file.

b.

Task 3: Register the object context


In the Global.asax.vb file, add context registration to the RegisterRoutes procedure, registering all tables for the AWDynamicData.AdventureWorksLT2008R2Entities object context.
DefaultModel.RegisterContext(GetType(AWDynamicData.AdventureWorksLT2008R2Entities), New ContextConfiguration() With {.ScaffoldAllTables = True})

Save and close the Global.asax.vb file.

Task 4: Run the application


Build and run the web application. a. b. c. d. e. f. g. h. i. The page displayed in the browser displays a list of the tables you added to the data model. View the Customers page, showing all customers. The page displays the List view that contains the data from the Customers table. View the Details view, for a customer. The page displays the Details view that contains the data for the selected row from the Customers table. View the Customers page, showing all customers, by clicking Show all items. Sort the customers by the LastName column. The page displays the List view that contains the data of customers, sorted by last name. View the sales order headers associated with the second customer displayed from the top.

8-82

Developing Web Applications with Microsoft Visual Studio 2010

j. k. l.

The page displays the List view that contains the data of customer sales order headers. Filter the sales order headers by entries that have the OnlineOrderFlag column set to True. The page now displays no sales order headers, because none of the sales order headers have the OnlineOrderFlag set to true.

m. View the customers page. n. o. p. q. r. s. t. Create a new customer, by clicking Insert new item. Save the new customer, with empty fields, and then cancel the new customer. The page displays the List view that contains the data from the Customers table. This is the default view and the one you are returned to, after cancelling. Edit the last customer displayed. The page displays the Edit view that contains the data for the selected row from the Customers table. Cancel the edit and close Windows Internet Explorer. Close Microsoft Visual Studio 2010.

Task 5: Turn off the virtual machine and revert the changes
In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. a. b. c. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert. In the Revert Virtual Machine dialog box, click Revert.

Optimizing Data Management for Web Forms

8-83

Section 2: Visual C# Exercise 4: Managing Data by Using ASP.NET Dynamic Data


The main tasks in this exercise are as follows: 1. 2. 3. 4. Create a new ASP.NET Dynamic Data web application. Add a new ADO.NET Entity Data Model. Register the object context. Run the application.

Task 1: Create a new ASP.NET Dynamic Data web application


Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd. a. b. Open Microsoft Visual Studio 2010. Create an ASP.NET Dynamic Data web application named AWDynamicData by using the New Project dialog box, and the ASP.NET Dynamic Data Entities Web Application project template. Place the project in the D:\Lab Files\CS\Lab 08\Starter\Exercise 04 folder.

Task 2: Add a new ADO.NET Entity Data Model


Add an ADO.NET Entity Data Model project item named AWEDM.edmx. a. Generate the model from the AdventureWorksLT2008R2 database, on the .\SQLEXPRESS server, and select only the Customer (SalesLT), SalesOrderDetail (SalesLT), and SalesOrderHeader (SalesLT) tables. Save and close the AWEDM.edmx file.

b.

Task 3: Register the object context


In the Global.asax.cs file, add context registration to the RegisterRoutes procedure, registering all tables for the AWDynamicData.AdventureWorksLT2008R2Entities object context.
DefaultModel.RegisterContext(typeof(AWDynamicData.AdventureWorksLT2008R2Entities), new ContextConfiguration() { ScaffoldAllTables = true });

Save and close the Global.asax.cs file.

Task 4: Run the application


Build and run the web application. a. b. c. d. e. f. The page displayed in the browser displays a list of the tables you added to the data model. View the Customers page, showing all customers. The page displays the List view that contains the data from the Customers table. View the Details view, for a customer. The page displays the Details view that contains the data for the selected row from the Customers table. View the Customers page, showing all customers, by clicking Show all items.

8-84

Developing Web Applications with Microsoft Visual Studio 2010

g. h. i. j. k. l.

Sort the customers by the LastName column. The page displays the List view that contains the data of customers, sorted by last name. View the sales order headers associated with the second customer displayed from the top. The page displays the List view that contains the data of customer sales order headers. Filter the sales order headers by entries that have the OnlineOrderFlag column set to True. The page now displays no sales order headers, because none of the sales order headers have the OnlineOrderFlag set to true.

m. View the customers page. n. o. p. q. r. s. t. Create a new customer, by clicking Insert new item. Save the new customer, with empty fields, and then cancel the new customer. The page displays the List view that contains the data from the Customers table. This is the default view and the one you are returned to, after cancelling. Edit the last customer displayed. The page displays the Edit view that contains the data for the selected row from the Customers table. Cancel the edit and close Windows Internet Explorer. Close Microsoft Visual Studio 2010.

Task 5: Turn off the virtual machine and revert the changes
In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. a. b. c. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert. In the Revert Virtual Machine dialog box, click Revert.

Note: The answers to the exercises are on the Course Companion CD.

Optimizing Data Management for Web Forms

8-85

Lab Review

Review Questions and Answers


Question: What is the use of the ScaffoldAllTables property? Answer: The ScaffoldAllTables property specifies that all entities in the data model should be made available for managing in the UI.

8-86

Developing Web Applications with Microsoft Visual Studio 2010

Module Review and Takeaways

Review Questions and Answers


Question: Which component of the ADO.NET Entity Framework enables you to query, insert, update, and delete data, all expressed as strongly-typed CLR objects? Answer: Object Services is the component of the ADO.NET Entity Framework that enables you to query, insert, update, and delete data, all expressed as strongly-typed CLR objects. Question: Name at least three data source controls. Answer: EntityDataSource, LinqDataSource, ObjectDataSource, SiteMapDataSource, SqlDataSource, and XmlDataSource. Question: What is a templated control? Answer: A templated control is an ASP.NET server control that can be customized with one or more templates used for specifying behavior and appearance. Question: What are the features of Dynamic Data? Answer: Dynamic Data offers the following features: Web scaffolding that can run a web application that is based on reading the underlying database schema. Scaffolding is a mechanism that enhances an existing ASP.NET web form page framework by dynamically displaying pages based on the data model, without a physical page behind the scenes. Dynamic Data scaffolding can generate a standard UI from the data model. Full data access operations such as create, update, remove, and display operations, relational operations, and data validation.

Optimizing Data Management for Web Forms

8-87

Automatic support for foreign-key relationships. Dynamic Data detects relationships between tables and creates UI that makes it easy for users to view data from related tables. The ability to customize the UI that is rendered to display and edit specific data fields, and to display and edit data fields for a specific table. The ability to customize data field validation. This lets you keep the business logic in the data layer separate from the presentation layer.

Real-World Issues and Scenarios


1. You need to display data in a tabular format by using a single server control, but you need to control the overall layout, the layout of the individual items, the selected item, the item being edited, and the item being inserted. What is the easiest way to do this? Use the ListView server control. You need to create a specific view for a single entity in your data model when using an ASP.NET Dynamic Data web application. How do you do this? Create a subfolder in the DynamicData\CustomPages folder, and name the subfolder the same as the entity in your data context, but use a plural ending. Then, create a new content page and add it to the subfolder.

2.

Best Practices
Mention some best practices in the context of your own business situations. Do not modify the generated DataContext or ObjectContext classes. Instead, create partial classes and place the custom code in partial classes. When the DataContext or ObjectContext classes are regenerated, any changes are overridden.

8-88

Developing Web Applications with Microsoft Visual Studio 2010

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-1

Module 9
Ensuring Quality by Debugging, Unit Testing, and Refactoring
Contents:
Lesson 1: Debugging and Refactoring Code Lesson 2: Unit Testing Code Lesson 3: Processing Unhandled Exceptions Lesson 4: Test-Driven Development Lab 9: Debugging, Unit Testing and Refactoring 9-3 9-22 9-30 9-37 9-43

9-2

Developing Web Applications with Microsoft Visual Studio 2010

Module Overview

Developers will spend more time debugging and refactoring code than they will initially writing it. To avoid additional debugging and refactoring cycles, unit tests can be implemented to isolate and ensure that code is working properly. If an error should make it to production, there are mechanisms to handle these issues. Whether it is debugging, refactoring, unit testing, or managing unhandled exceptions, Visual Studio 2010 makes it easier than ever to perform these tasks. The goal of this module is to teach the basics of debugging and refactoring code by using Visual Studio 2010.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-3

Lesson 1

Debugging and Refactoring Code

You have created your application and resolved the build errors. You must now correct those logic errors that keep your application from running correctly. You can do this using the integrated debugging functions in the Visual Studio 2010 debugger. These functions allow you to stop at procedure locations, inspect memory and register values, change variables, observe message traffic, and get a closer look at what your code does.

Lesson Objectives
After completing this lesson, you will be able to: Understand the basics of debugging. Debug a web application. Understand the basics of refactoring. Refactor code by using Visual Studio 2010.

9-4

Developing Web Applications with Microsoft Visual Studio 2010

Overview of Debugging

Debugging is the process of observing the run-time behavior of your application, and then locating and fixing logic errors. A modern debugger lets you break, or suspend, the execution of your application, and subsequently lets you examine the code, evaluate and edit variables in your application, view registers, see the instructions created from your source code, and view the memory space used by your application. By using breakpoints, you can instruct the debugger to pause execution whenever a breakpoint in your code is hit.

Enable Debugging for an ASP.NET web application


To debug your web application, you need to enable debugging in the Project Designer and in the Web.config file. These are the steps to perform for enabling debugging, with your web application open in Visual Studio 2010. 1. 2. 3. 4. 5. In Solution Explorer, right-click the name of your web application, and then click Property Pages. In the Project Designer, click Web. In the Project Designer, on the Web page, in the Debuggers area, select the ASP.NET check box. In Solution Explorer, double-click Web.config. Locate the opening compilation tag. In the compilation tag, add the debug attribute or modify the value of the debug attribute, if it already exists, to true.

Note: If you do not set the debug attribute to true and try to start a debugging session, a dialog box will appear, offering to create a Web.config file with the attribute set.
<configuration> <system.web> <compilation ... debug="true">

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-5

. . . </compilation> </system.web> </configuration>

A website can contain multiple virtual directories and subdirectories, and Web.config files may exist in each one. ASP.NET applications inherit settings from Web.config files at higher levels in the URL path. Hierarchical configuration files allow you to change settings for several ASP.NET applications at the same time, such as for all applications below it in the hierarchy. However, if debug is set in a file lower in the hierarchy, it will override the higher value. Note: Enabling debug mode will greatly affect the performance of your ASP.NET application. Remember to disable debug mode before you deploy a release application or conduct performance measurements.

Debugging Permissions
For remote debugging, local and remote computers must be on a domain setup or a workgroup setup. To debug the ASP.NET worker process you must have permission to debug that process. By default, ASP.NET applications run as the ASPNET user. If the worker process is running as ASPNET, or as NETWORK SERVICE, you must have Administrator privileges to debug it.

9-6

Developing Web Applications with Microsoft Visual Studio 2010

Overview of Debugging Using Visual Studio 2010 Debugging Tools

The Visual Studio debugger is a powerful tool that allows you to observe the run-time behavior of your program, and locate logic errors. The debugger works with all Visual Studio programming languages and their associated libraries. With Edit and Continue, you can make changes to your code while debugging, and then continue execution. The Visual Studio 2010 debugger has been enhanced by the addition of the following features: Breakpoint enhancements, which include the ability to search in the Breakpoints window, the ability to label breakpoints, the ability to import and export breakpoints, and string comparison for breakpoint conditions in native debugging. A newly redesigned Threads window provides filtering, call-stack searching and expansion, and grouping. New columns display affinity masks, process names, and managed IDs. You can customize which columns appear and in what order. Use the Parallel Stacks and Parallel Tasks debugger tool windows to visualize and debug parallel code that is written in C++, C#, or Visual Basic. Enhanced DataTips can float on top of other windows or be pinned. DataTips now have a comment field. Floating DataTips that are open persist between debug sessions. For dump debugging, a new summary page displays basic information about the contents of the dump file before you begin to debug. This page offers quick links to the most common next steps, such as setting your symbol paths and starting to debug. The debugger now fully supports debugging of managed dumps for applications that are using common language-run-time (CLR) version 4.0. The Watch window and DataTips provide an icon to warn you when evaluating an expression that requires other threads to run, which can change the program state and cause debug events such as breakpoints to be ignored. If you click the icon, the threads run. Enhancements to symbol loading. See How to: Specify Symbol Locations and Loading Behavior at http://go.microsoft.com/fwlink/?LinkID=204072&clcid=0x409.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-7

Debug mixed-mode native and managed code on 64-bit operating systems.

Question: What percentage of your time development do you spend debugging? Question: Without a debugger what is another way to debug an application?

9-8

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Enabling Debugging of a Web Application

In this demonstration, you will see how to enable debugging of a web application. 1. Open Microsoft Visual Studio. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Create a new ASP.NET web application by using the New Project dialog box. a. b. c. d. On the File menu, click New Project. In the New Project dialog box, in the left pane, click Visual Basic or Visual C#. In the middle pane, click ASP.NET Web Application. In the Name box, type DebugWebApp, in the Location box, type D:\Demofiles\VB or D:\Demofiles\CS, and then click OK.

3.

Build the project. In the DebugWebApp Microsoft Visual Studio window, on the Build menu, click Build DebugWebApp. Open the Web.config file. In Solution Explorer, double-click Web.config.

4.

5. 6. 7.

Navigate to the self-closing system.web element and notice the attributes and values in the compilation tag. In Solution Explorer, right-click DebugWebApp, and then click Properties. Open the Web page. In the Properties Designer, click Web.

8. 9.

Examine the various options on the Web page. In the Debuggers section, ensure the ASP.NET check box is selected.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-9

10. Close the Properties Designer. In the DebugWebApp window, click the Close button.

11. Close Microsoft Visual Studio 2010. In the DebugWebApp - Microsoft Visual Studio window, click the Close button.

9-10

Developing Web Applications with Microsoft Visual Studio 2010

What is Refactoring?

Refactoring is the process of improving your code, after it has been written, by changing the internal structure and format of the code, without changing the external behavior of the code. Visual Studio 2010 provides the following refactoring commands on the Refactor menu, when you have a Visual C# project open: Rename Extract Method Encapsulate Field Extract Interface Remove Parameters Reorder Parameters

These commands invoke functionality that does exactly what the name says, and each is covered later in this topic and Lesson.

Multi-Project Refactoring
Visual Studio 2010 supports multi-project refactoring for projects that are in the same solution. All of the refactoring functionality that corrects references across files corrects those references across all projects of the same programming language. This works for any project-to-project references. For example, if you have a console application that references a class library, when you rename the name of a class library type by using the Rename refactoring functionality, the references to the class library type in the console application are also updated.

Changes Review
Much of the refactoring functionality provides an opportunity for you to review all the reference changes that a refactoring operation would perform on your code, before committing to those changes. For this

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-11

refactoring functionality, a Preview reference changes option will appear in the Refactoring dialog box. After selecting that option and accepting the refactoring operation, the Preview Changes dialog box opens. Notice that the Preview Changes dialog box has two views. The bottom view displays your code with all the reference updates due to the refactoring operation. If you click Cancel in the Preview Changes dialog box stops the refactoring operation, and no changes are made to your code.

Refactoring Warnings
If the compiler does not have a complete understanding of your program, and the refactoring engine might not update all of the appropriate references, the Refactoring Warning dialog box is displayed. This warning dialog box also provides an opportunity for you to preview your code in the Preview Changes dialog box before you commit changes. If a method contains a syntax error, which the IDE indicates with a red wavy line under the code in error, then the refactoring engine will not update any references to an element within that method. By default, if you execute a refactoring operation without previewing reference changes and a compilation error is detected in your program, then the development environment displays this warning dialog box. If you execute a refactoring operation that has Preview reference changes enabled, and a compilation error is detected in your program, then the development environment will display the following warning message at the bottom of the Preview Changes dialog box, in lieu of displaying the Refactoring Warning dialog box: Your project or one of its dependencies does not currently build. References may not be updated. This refactoring warning is only available for refactoring operations that provide the Preview reference changes option.

Error-Tolerant Refactoring and Verification Results Key Points


Refactoring is error tolerant. In other words, you can perform a refactoring in a project that cannot build. However, in these cases the refactoring process might not update ambiguous references correctly. The Verification Results dialog box can notify you if the refactoring engine detects compile errors or discovers that a refactoring operation inadvertently causes a code reference to bind to something different from what it was originally bound to (rebinding issue). To turn on the verification results feature, on the Tools menu, click Options. In the Options dialog box, expand Text Editor, and then expand C#. Click Advanced and select the Verify results of refactoring check box. The Verification Results dialog box distinguishes the difference between two kinds of rebinding issues. References whose definition will no longer be the renamed symbol: This kind of rebinding issue occurs when a reference no longer refers to a renamed symbol. For example, consider the following code:
[Visual C#] class Example { private int a; public Example(int b) { a = b; }

9-12

Developing Web Applications with Microsoft Visual Studio 2010

[Visual Basic] Class Example Private a As Integer Sub New(ByVal b As Integer) a = b End Sub End Class

If you use refactoring to rename a to b, the Verification Results dialog box appears. The reference to the renamed variable a now binds to the parameter that is passed to the constructor instead of binding to the field. References whose definition will now become the renamed symbol: This kind of rebinding issue occurs when a reference that previously did not refer to the renamed symbol now does refer to it. For example, consider the following code:
[Visual C#] class Example { private static void Method(object a) { } private static void OtherMethod(int a) { } static void Main(string[] args) { Method(5); }

[Visual Basic] Class Example Private Shared Sub Method(ByVal a As Object) End Sub Private Shared Sub OtherMethod(ByVal a As Integer) End Sub Shared Sub Main(ByVal args As String()) Method(5) End Sub End Class

If you use refactoring to rename OtherMethod to Method, the Verification Results dialog box appears. The reference in Main now refers to the overloaded method that accepts an int parameter instead of the overloaded method that accepts an object parameter. Question: What problems have you encountered by refactoring code without the use of a tool? Question: What percentage of your development time do you spend refactoring code? Question: What third-party tools have you used to accomplish refactoring?

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-13

Extract Method Refactoring

Extract Method is a refactoring operation that provides an easy way to create a new method from a code fragment in an existing member. Using Extract Method, you can create a new method by extracting a selection of code from inside the code block of an existing member. The new, extracted method contains the selected code, and the selected code in the existing member is replaced with a call to the new method. Turning a fragment of code into its own method lets you quickly and accurately reorganize code for better reuse and readability. Extract Method has the following benefits: Encourages best coding practices by emphasizing discrete, reusable methods. Encourages self-documenting code through good organization. When descriptive names are used, high-level methods can read more like a series of comments. Encourages the creation of finer-grained methods to simplify overriding. Reduces code duplication.

When you use the Extract Method command, the new method is inserted following the source member in the same class.

9-14

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Extract Method Refactoring

In this demonstration, you will learn how to extract a method from existing code. The solution from the Enable Debugging of a Web Application demonstration is being used. 1. Open Microsoft Visual Studio. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the DebugWebApp solution from the D:\Demofiles\CS\DebugWebApp folder. a. b. In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project. In the Open Project dialog box, in the File name box, type D:\Demofiles\CS\DebugWebApp\DebugWebApp.sln, and then click Open.

3. 4.

Open Default.aspx in Code view. In Solution Explorer, right-click Default.aspx and then click View Code. In the Page_Load method, type in the following code:
[Visual C#] protected void Page_Load(object sender, EventArgs e) { var i = 1; var j = 2; var answer = i + j; }

5. 6. 7.

Select the three lines of code you just added. Right-click the selection, point to Refactor, and then click Extract Method. In the Extract Method dialog box, in the New method name box, type Add, and then click OK. Note: The code has been extracted into a new method, and the function has been called in its place.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-15

8. Build the project. In the DebugWebApp Microsoft Visual Studio window, on the Build menu, click Build DebugWebApp. 9. Close Microsoft Visual Studio 2010. In the DebugWebApp - Microsoft Visual Studio window, click the Close button.

9-16

Developing Web Applications with Microsoft Visual Studio 2010

Encapsulate Field Refactoring

The Encapsulate Field refactoring operation enables you to quickly create a property from an existing field, and then seamlessly update your code with references to the new property. When a field is public, other objects have direct access to that field and can modify it, undetected by the object that owns that field. By using properties to encapsulate that field, you can disallow direct access to fields. To create the new property, the Encapsulate Field operation changes the access modifier for the field that you want to encapsulate to private, and then generates get and set accessors for that field. In some cases, only a get accessor is generated, such as when the field is declared read-only. The refactoring engine updates your code with references to the new property in the areas specified in the Update References section of the Encapsulate Field dialog box.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-17

Demonstration: Encapsulate Field Refactoring

In this demonstration, you will see how to encapsulate a field. The solution from the Enable Debugging of a Web Application demonstration is being used. 1. Open Microsoft Visual Studio. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the DebugWebApp solution from the D:\Demofiles\CS\DebugWebApp folder. a. b. In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project. In the Open Project dialog box, in the File name box, type D:\Demofiles\CS\DebugWebApp\DebugWebApp.sln, and then click Open.

3. 4. 5.

In Solution Explorer, right-click DebugWebApp, point to Add, and then click Class. In the Add New Item DebugWebApp dialog box, in the Name box, type Person, and then click Add. Create a single private variable named name, by adding the following code
[Visual C#] public class Person { private string name; }

6. 7. 8.

In the Person.cs window, right-click name, point to Refactor, and then click Encapsulate Field. In the Encapsulate Field dialog box, click OK. In the Preview Reference Changes - Encapsulate Field dialog box, click Apply. Note: The new property with accessors has been created.

9-18

Developing Web Applications with Microsoft Visual Studio 2010

9.

Build the project. In the DebugWebApp Microsoft Visual Studio window, on the Build menu, click Build DebugWebApp.

10. Close Microsoft Visual Studio 2010. In the DebugWebApp - Microsoft Visual Studio window, click the Close button.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-19

Extract Interface Refactoring

Extract Interface is a refactoring operation that provides an easy way to create a new interface with members that originate from an existing class, structure, or interface. When several clients use the same subset of members from a class, structure, or interface, or when multiple classes, structures, or interfaces have a subset of members in common, it can be useful to embody the subset of members in an interface. Extract Interface generates an interface in a new file, and positions the cursor at the beginning of the new file. You can specify which members to extract into the new interface, the name of the new interface, and the name of the generated file using the Extract Interface dialog box.

9-20

Developing Web Applications with Microsoft Visual Studio 2010

Demonstration: Extract Interface Refactoring

In this demonstration, you will see how to extract an interface from an existing class. The solution from the Enable Debugging of a Web Application demonstration is being used. 1. Open Microsoft Visual Studio. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the DebugWebApp solution from the D:\Demofiles\CS\DebugWebApp folder. a. b. In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project. In the Open Project dialog box, in the File name box, type D:\Demofiles\CS\DebugWebApp\DebugWebApp.sln, and then click Open.

3. 4.

Open the Person.cs file. In Solution Explorer, double-click Person.cs. Add the age member variable, Age property, and Hire method to the Person class.
[Visual C#] public class Person { private string name; public string Name { get { return name; } set { name = value; } } private int age; public int Age { get { return age; } set { age = value; }

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-21

} public void Hire() { // implementation Code }

In the Person.cs window, in the Person class, append the following code.
[Visual C#] private int age; public int Age { get { return age; } set { age = value; } } public void Hire() { // implementation Code }

5. 6.

Right-click Person, point to Refactor, and then click Extract Interface. In the Extract Interface dialog box, select the Age, Hire(), and Name check boxes, and then click OK. Note: The new interface is now created in a new file.

7.

Display the Person.cs file, and notice how the class now implements the new interface. In the DebugWebApp Microsoft Visual Studio window, click Person.cs.

8.

Build the project. In the DebugWebApp Microsoft Visual Studio window, on the Build menu, click Build DebugWebApp.

9.

Close Microsoft Visual Studio 2010. In the DebugWebApp - Microsoft Visual Studio window, click the Close button.

9-22

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 2

Unit Testing Code

The primary goal of unit testing is to take the smallest piece of testable software in the application, isolate it from the remainder of the code, and determine whether it behaves exactly as you expect. Each unit is tested separately before integrating it into modules to test the interfaces between modules. Unit testing has proven its value in that a large percentage of defects are identified during its use.

Lesson Objectives
After completing this lesson, you will be able to: Understand the basics of unit testing. Create and run unit tests. Understand the steps of unit testing.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-23

What is Unit Testing?

The most common approach to unit testing requires drivers and stubs to be written. The driver simulates a calling unit, and the stub simulates a called unit. The investment of developer time in this activity sometimes results in demoting unit testing to a lower level of priority and that is almost always a mistake. Even though the drivers and stubs cost time and money, unit testing provides some undeniable advantages. It allows for automation of the testing process, reduces difficulties of discovering errors contained in more complex pieces of the application, and test coverage is often enhanced because attention is given to each unit. For example, if you have two units and decide it would be more cost effective to glue them together and initially test them as an integrated unit, an error could occur in a variety of places: Is the error due to a defect in unit 1? Is the error due to a defect in unit 2? Is the error due to defects in both units? Is the error due to a defect in the interface between the units? Is the error due to a defect in the test?

Finding the error (or errors) in the integrated module is much more complicated than first isolating the units, testing each, and then integrating them and testing the whole. Drivers and stubs can be reused so that the constant changes that occur during the development cycle can be retested frequently without writing large amounts of additional test code. In effect, this reduces the cost of writing the drivers and stubs on a per-use basis, and the cost of retesting is better controlled. Unit testing takes the smallest piece of testable software in an application and isolates it from the rest of the project. This allows the developer to test that piece of code, isolating it so that external influences dont affect the testing. This method of testing helps find the majority of defects in a system. There are two parts to a unit test.

9-24

Developing Web Applications with Microsoft Visual Studio 2010

Driver: The driver is the calling mechanism that isolates the testable software and looks for a particular result. Stub: The stub represents the code that is being tested. There are two phases to creating a unit test. The first phase is generating a unit test file that contains a skeleton version of a test method for each method in the code that you are testing. Each skeleton test method is generated with empty variables and a placeholder Assert statement. The second phase is initializing the variables and replacing the placeholder Assert statement with an appropriate one. You use the Create Unit Tests dialog box to generate unit tests for any or all of the methods in the code that you are testing. Question: Have you ever isolated an error in an integrated module, and then applied a fix? Question: What percentage of your development time is spent writing tests?

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-25

Steps to Creating a Unit Test

There are several steps to creating a unit test. Create the code that is to be tested. Any code that has been written can be tested. Typically, the code is in properties or in methods. Event procedures can be tested, but it is better practice to put all code in separate methods. Use the Create Unit Test feature in Visual Studio. Once there is code to be tested, use the Create Unit Tests dialog box to specify what is to be tested. This can be accessed through the Test menu, or by rightclicking the code. Once the dialog box has been opened, you can specify which items you want to test.

9-26

Developing Web Applications with Microsoft Visual Studio 2010

Selecting an item will create the unit tests for it. Create a Unit Test. There are two phases to creating a unit test. Phase 1 is generating a unit test file. This file contains a skeleton version of a test method for each method you are testing. It is created with empty variables and a placeholder Assert statement. Phase 2 is initializing the variables and replacing them with relevant values that you are testing. Add validation. Before you can run a test, you must replace the variables with meaningful data so you that know that the method performs properly. As well, the placeholder Assert statement should be replaced for one that is appropriate for that method. Typically the Assert.AreEqual method is used.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-27

Demonstration: Creating and Running a Unit Test

In this demonstration, you will see how to create and run a unit test. 1. Open Microsoft Visual Studio. 2. On the Start menu of 10264A-GEN-DEV, point to All Programs, click Microsoft Visual Studio 2010, and then click Microsoft Visual Studio 2010.

Open the UnitTest solution from the D:\Demofiles\CS or D:\Demofiles\VB folder. a. b. In the Start Page Microsoft Visual Studio window, on the File menu, click Open Project. In the Open Project dialog box, in the File name box, type D:\Demofiles\CS\UnitTest.sln or D:\Demofiles\VB\UnitTest.sln, and then click Open.

3.

Open the Person.cs or Person.vb file. In Solution Explorer, double-click Person.cs or Person.vb.
[Visual C#] public int Age { get { return personAge; } set { if (value < 21) throw new Exception("Age must be greater than 21"); } personAge = value;

4.

Modify the Age property as follows:

[Visual Basic] Public Property Age As Integer Get Return personAge

9-28

Developing Web Applications with Microsoft Visual Studio 2010

End Get Set(ByVal value As Integer) If value < 21 Then Throw New Exception("Age must be greater than 21") End If personAge = value End Set End Property

5. 6. 7.

Right-click anywhere in the code for the Age property, and then click Create Unit Tests. In the Create Unit Tests dialog box, ensure the Age check box is selected, and then click OK. In the New Test Project dialog box, click Create. Note: Notice the new project created for unit testing.

8. 9.

In the open PersonTest.cs or PersonTest.vb file, review the AgeTest test method. Change the declaration code for the expected local variable as follows.
[Visual C#] int expected = 25; [Visual Basic] Dim expected As Integer = 25

10. Delete the following code.


[Visual C#] Assert.Inconclusive("Verify the correctness of this test method."); [Visual Basic] Assert.Inconclusive("Verify the correctness of this test method.")

11. Right-click the AgeTest method declaration, and then click Run Tests. Note: In the Test Results window, notice the AgeTest test passed. 12. Change the declaration code for the expected local variable as follows.
[Visual C#] int expected = 2; [Visual Basic] Dim expected As Integer = 2

13. Right-click the AgeTest method declaration, and then click Run Tests. Note: In the Test Results window, notice the AgeTest test failed. 14. Close Microsoft Visual Studio 2010. In the UnitTest - Microsoft Visual Studio window, click the Close button.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-29

Optional Unit Test Steps

There are several optional unit-test steps that will make your testing more effective. Create a Test Category. You can manage multiple tests into testing categories. This makes selecting which tests to run during a testing cycle easier. You add test categories as attributes to your test methods. You can use logical operators with test categories, to run tests from multiple categories together, or to limit the tests that you run to tests that belong to multiple categories. Create a Test List. Test lists are similar to test categories. However, you can run tests from multiple unit test files, across a build, or you can use them as a list to enforce a check-in policy. Check-in policies are used with source control applications such as the Microsoft Team Foundation Server (TFS) 2010. View Code Coverage. If you collect code coverage information, you can use the Code Coverage window to see what percentage of methods in the code are covered by your unit tests. Question: How can unit test help you document code? Question: Which third-party tools have you used to write unit tests?

9-30

Developing Web Applications with Microsoft Visual Studio 2010

Lesson 3

Processing Unhandled Exceptions

When a run-time error occurs on a web application in production, it is important to notify a developer and to log the error so that it can be diagnosed at a later time. It is also important to provide the end user relevant support information to allow him or her to continue using the web application. This lesson provides an overview of how ASP.NET processes runtime errors, and looks at one way to have custom code execute whenever an unhandled exception bubbles up to the ASP.NET runtime. This lesson also explains how to implement a custom error page that provides the end user with relevant support information, and matches your sites look and feel.

Lesson Objectives
After completing this lesson, you will be able to: Display a custom error page. Process unhandled exceptions.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-31

Displaying a Custom Error Page

Unfortunately, runtime errors are unavoidable. Even the best developers are guilty of creating code with issues. The classes in the .NET Framework signal an error by throwing an exception. Exceptions can be handled using try/catch/finally blocks. If code within a try block throws an exception, control is transferred to the appropriate catch block, where the developer can attempt to recover from the error. If there is no matching catch block, or if the code that threw the exception is not in a try block, the exception percolates up the call stack in search of try/catch/finally blocks. If the exception rises all the way up to the ASP.NET runtime without being handled, the HttpApplication class' Error event is raised, and the configured error page is displayed. By default, ASP.NET displays an error page that is commonly referred to as the Yellow Screen of Death (YSOD). There are two versions of the YSOD: one shows the exception details, a stack trace, and other information helpful to developers debugging the application; the other simply states that there was a run-time error. None of these pages is useful to the end user, and can ultimately affect their perception of the application. This can be avoided by directing end users to an error page that maintains the site's look and feel with more user-friendly prose describing the situation.

Configuring Error Pages


The customErrors section in a Web.config file has two attributes that affect which error page is shown: defaultRedirect and mode. The defaultRedirect attribute is optional. If provided, it specifies the URL of the custom error page, and indicates that the custom error page should be shown instead of the Runtime Error YSOD. The mode attribute is required, and accepts one of three values: On, Off, or RemoteOnly. On: Indicates that the custom error page or the Runtime Error YSOD is shown to all visitors, regardless of whether they are local or remote. Off: Specifies that the Exception Details YSOD be displayed to all visitors, regardless of whether they are local or remote. RemoteOnly: Indicates that the custom error page or the Runtime Error YSOD is shown to remote visitors, while the Exception Details YSOD is shown to local visitors only.

9-32

Developing Web Applications with Microsoft Visual Studio 2010

Unless you specify otherwise, ASP.NET acts as if you have set the mode attribute to RemoteOnly and have not specified a defaultRedirect attribute value. In other words, the default behavior is that the Exception Details YSOD is displayed to local visitors, while the Runtime Error YSOD is shown to remote visitors. You can override this default behavior by adding a customErrors section to your web application's Web.config file. Every web application should have a custom error page. It provides a more professional-looking alternative to the Runtime Error YSOD, it is easy to create, and configuring the application to use the custom error page takes only a few moments. The first step is adding an informative and themed custom error page to your solution. Specify the URL of the error page in the customErrors elements defaultRedirect attribute. Add the following markup to your application's Web.config file:
<configuration> ... <system.web> ... <customErrors mode="RemoteOnly" defaultRedirect="~/CustomErrorPage.aspx" /> ... </system.web> </configuration>

This will configure the application to show the Exception Details YSOD to users visiting locally, while using the custom error page CustomErrorPage.aspx for those users visiting remotely.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-33

Processing Unhandled Exceptions

Errors that occur in development environments are observed by developers who can examine the exception details, and the steps required to reproduce the error. Errors that occur in a production environment are observed by end users. Unless end users take the time to report the details of an error, developers are not notified of the error and the error details. Only errors that are encountered in the development environment will be remedied. For these reasons, it is important that any error in the production environment is logged to some persistent store, and that the developers are alerted to this error. Events provide an object a mechanism for signaling that something interesting has occurred, and for another object to execute code in response. As an ASP.NET developer you are accustomed to thinking in terms of events. If you want to run some code when the visitor clicks a particular button, you create an event handler for that button's Click event and put your code there. Given that the ASP.NET runtime raises its Error event whenever an unhandled exception occurs, it follows that the code for logging the error's details would go in an event handler. But how do you create an event handler for the Error event? The Error event is one of many events in the HttpApplication class that is raised at certain stages in the HTTP pipeline during the lifetime of a request. For example, the HttpApplication class' BeginRequest event is raised at the start of every request; the AuthenticateRequest event is raised when a security module has identified the requestor. These HttpApplication events give the page developer a means to execute custom logic at the various points in the lifetime of a request. Event handlers for the HttpApplication events can be placed in a special file named Global.asax. To create this file in your web application, add a new item to the root of your website using the Global Application Class project item template.
[Visual C#] using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Security;

9-34

Developing Web Applications with Microsoft Visual Studio 2010

using System.Web.SessionState; namespace xxx { public class Global : System.Web.HttpApplication { void Application_Start(object sender, EventArgs e) { // Code that runs on application startup } void Application_End(object sender, EventArgs e) { // Code that runs on application shutdown } void Application_Error(object sender, EventArgs e) { // Code that runs when an unhandled error occurs } void Session_Start(object sender, EventArgs e) { // Code that runs when a new session is started } void Session_End(object sender, EventArgs e) { // Code that runs when a session ends. // Note: The Session_End event is raised only when the sessionstate mode // is set to InProc in the Web.config file. If session mode is set to StateServer // or SQLServer, the event is not raised. } } }

[Visual Basic] Imports System.Web.SessionState Public Class Global_asax Inherits System.Web.HttpApplication Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) ' Fires when the application is started End Sub Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) ' Fires when the session is started End Sub Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs) ' Fires at the beginning of each request End Sub Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs) ' Fires upon attempting to authenticate the use

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-35

End Sub Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs) ' Fires when an error occurs End Sub Sub Session_End(ByVal sender As Object, ByVal e As EventArgs) ' Fires when the session ends End Sub Sub Application_End(ByVal sender As Object, ByVal e As EventArgs) ' Fires when the application ends End Sub End Class

When the Application_Error event handler executes, you should notify a developer of the error, and log its details. To accomplish this, you first need to determine the details of the exception that was raised. For this purpose, you can use the Server object's GetLastError method.
[Visual C#] protected void Application_Error(object sender, EventArgs e) { // Get the error details HttpException lastErrorWrapper = Server.GetLastError() as HttpException; } [Visual Basic] Protected Sub Application_Error(sender As Object, e As EventArgs) ' Get the error details Dim lastErrorWrapper As HttpException = TryCast(Server.GetLastError(), HttpException) End Sub

The GetLastError method returns an object of type Exception, which is the base type for all exceptions in the .NET Framework. However, in the code shown, the Exception object returned by GetLastError is cast to an HttpException object. If the Error event is being fired because an exception was thrown during the processing of an ASP.NET resource, then the exception that was thrown is wrapped within an HttpException. To get the actual exception that precipitated the Error event, you can access the InnerException property. If the Error event was raised because of an HTTP-based exception, such as a request for a non-existent page, an actual HttpException is thrown, but it does not have an inner exception. The following code uses the GetLastErrormessage to retrieve information about the exception that triggered the Error event, storing the HttpException in a variable named lastErrorWrapper. It then stores the type, message, and stack trace of the originating exception in three string variables, checking to see if the lastErrorWrapper is the actual exception that triggered the Error event (in the case of HTTPbased exceptions), or if it's merely a wrapper for an exception that was thrown while processing the request.
[Visual C#] protected void Application_Error(object sender, EventArgs e) { // Get the error details HttpException lastErrorWrapper = Server.GetLastError() as HttpException; Exception lastError = lastErrorWrapper; if (lastErrorWrapper.InnerException != null) lastError = lastErrorWrapper.InnerException; string lastErrorTypeName = lastError.GetType().ToString(); string lastErrorMessage = lastError.Message;

9-36

Developing Web Applications with Microsoft Visual Studio 2010

string lastErrorStackTrace = lastError.StackTrace;

[Visual Basic] Protected Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs) ' Get the error details Dim lastErrorWrapper As HttpException = TryCast(Server.GetLastError(), HttpException) Dim lastError As Exception = lastErrorWrapper If Not lastErrorWrapper.InnerException Is Nothing Then lastError = lastErrorWrapper.InnerException End If Dim lastErrorTypeName As String = lastError.[GetType]().ToString() Dim lastErrorMessage As String = lastError.Message Dim lastErrorStackTrace As String = lastError.StackTrace End Sub

At this point, you have all the information you need to write code that will log the exception's details to a database table. You can create a database table with columns for each of the error details of interest (the type, the message, the stack trace, and so on) along with other useful pieces of information (such as the URL of the requested page and the name of the user currently logged on). In the Application_Error event handler you can then connect to the database and insert a record into the table. Likewise, you can add code to alert a developer of the error via email. The error logging libraries examined in the coming modules provide such functionality out of the box, so there's no need to build this error logging and notification yourself. Question: Have you ever experienced a default error page on a production site? How did your perception of the site change? Question: Have you ever experienced a custom error page on a production site? Did the custom error page provide you relevant information that improved your experience?

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-37

Lesson 4

Test-Driven Development

Test-driven development (TDD) is one of the core practices of Extreme Programming (XP). The practice extends the feedback approach, and requires that you develop test cases before you develop code. Using TDD, developers develop functionality to pass the existing test cases. Next, the test team adds new test cases to test the existing functionality, and runs the entire test suite to ensure that the code fails (either because the existing functionality needs to be modified or because required functionality is not yet included). The developers then modify the functionality or create new functionality so that the code can withstand the failed test cases. This cycle continues until the test code passes all of the test cases that the team can create. The developers then refactor the functional code to remove any duplicate or dead code and make it more maintainable and extensible.

Objectives
Learn the difference between test-driven and traditional development. Learn how to execute test-driven development.

9-38

Developing Web Applications with Microsoft Visual Studio 2010

Advantages of Test-Driven over Traditional Development

Test-driven development (TDD) reverses the traditional development process. Instead of writing functional code first and then testing it, the team writes the test code before the functional code. The team does this in very small stepsone test and a small amount of corresponding functional code at a time. The developers do not write code for new functionality until a test fails because some functionality is not present. Only when a test is in place do developers do the work required to ensure that the test cases in the test suite pass. In subsequent iterations, when the team has the updated code and another set of test cases, the code may break several existing tests as well as the new tests. The developers continue to develop or modify the functionality to pass all of the test cases. TDD allows you to start with an unclear set of requirements, and relies on the feedback loop between the developers and the customers for input on the requirements. The customer, or a customer representative, is the part of the core team, and immediately provides feedback about the functionality. This practice ensures that the requirements evolve over the course of the project cycle. Testing before writing functional code ensures that the functional code addresses all of the requirements, without including unnecessary functionality. With TDD, you do not need to have a well-defined architectural design before beginning the development phase, as you do with traditional development life cycle methodologies. TDD allows you to tackle smaller problems first, and then evolve the system as the requirements become more clear later in the project cycle. Other advantages of TDD are as follows: Promotes loosely coupled and highly cohesive code, because the functionality is evolved in small steps. Each piece of the functionality needs to be self-sufficient in terms of the helper classes and the data that it acts on so that it can be successfully tested in isolation. The test suite acts as documentation for the functional specification of the final system. The system uses automated tests, which significantly reduce the time taken to retest the existing functionality for each new build of the system.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-39

When a test fails, you have a clear idea of the tasks that you must perform to resolve the problem. You also have a clear measure of success when the test no longer fails. This increases your confidence that the system actually meets the customer requirements.

TDD helps ensure that your source code is thoroughly unit tested. However, you must still consider traditional testing techniques, such as functional testing, user acceptance testing, and system integration testing. Much of this testing can also be done early in your project. In fact, in XP, the acceptance tests for a user story are specified by the project stakeholder(s), either before, or in parallel to the code being written, giving stakeholders confidence that the system meets their requirements. Question: What obstacles do you envision when transitioning from traditional development to testdriven development? Question: For what percentage of your code do you write unit tests?

9-40

Developing Web Applications with Microsoft Visual Studio 2010

The Test-Driven Development Process

To execute TDD, follow these steps. 1. 2. Create the test code. Use an automated test framework to create the test code. The test code drives the development of functionality. Write/modify the functional code. Write the functional code for the application block so that it can pass all test cases from the test code. The first iteration involves developing new functionality; subsequent iterations involve modifying the functionality based on the failed test cases. Create additional tests. Develop additional tests to test the functional code. Test the functional code. Test the functional code based on the test cases developed in steps 3 and 1. Repeat steps 2 through 4 until the code passes all of the test cases. Refactor the code. Modify the code so that there is no dead code or duplication. The code should adhere to best practices for maintainability, performance, and security.

3. 4. 5.

Step 1: Create the Test Code


You create the test code before any code is written for the functionality of the application block. The general guidelines for writing the test code are as follows: Your goal is to write test code that tests basic functionality. Write a test case for each code requirement. The developers will write the functional code based on the tests, so that the test case passes. Avoid writing code for multiple test cases at any one time. Write code for a single test case, and proceed through the remaining cycle of coding and refactoring. Write code that tests only small pieces of functionality. If the test code is complex, divide it into smaller tests so that each one tests only a small piece of functionality.

You will not be able to compile the test code until the developer writes the functional code. The developer then writes the code so that the test compiles and passes.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-41

Step 2: Write or Modify the Functional Code


In step 2, your goal is to develop functionality that passes the test cases that were created in step 1. If you are in the first iteration, in all probability the test code will not compile and you can assume that it failed. You must modify the functionality being tested so that the test code compiles and can be executed. After the functionality passes all of the test cases created in step 1, the developer stops developing the module. The outcome of step 2 is code that implements basic functionality. However, in the later iterations, when additional test cases are created to test the functionality, the code in the previous example will fail. The developers must make further changes in subsequent iterations so that all of the functionality can pass the additional test cases. The developers continue to improve the functionality until all of the existing test cases pass.

Step 3: Create Additional Tests


After step 2, the code has the basic functionality to pass all of the test cases that were created in step 1. The tester must now test this functionality for various types of input. You should ensure that the amount of time spent developing additional test cases is proportionate to the criticality of the feature. For example, if various code paths in an API need to be tested by providing different input, you can write multiple test stubs, with each stub catering to one possible code path. The general guidelines for creating these additional tests are as follows: Create additional tests that could possibly break the code. Continue to create these additional tests until you have no more test cases. Write test cases that focus on the goal of the code (what the user needs the code to do), rather than the implementation. For example, if the goal of a function is to return values from a database that is based on some identifier, test the function by passing both valid and invalid identifier values, rather than testing only those values that the current implementation supports (which can be only a valid set of values). If all of the test cases created in step 1 have passed but the functionality still does not work as intended, you have probably missed an important test scenario, and must develop additional test cases that reproduce the failure of the functionality. These test cases are in addition to the existing test cases that pass invalid input to the API to force an exception. Avoid writing separate test cases for each unique combination of input. The number of test cases you write should be based on the risk assessment of the feature, and on ensuring that all critical scenarios and the majority of test input have been accounted for.

Step 4: Test the Functional Code


The next step is to test the functionality by using the additional test cases. To do so, execute all of the test cases from step 1 and step 3, and note any test cases that fail the test. The developers must then make changes to the functional code so that it passes all of the existing test cases. Repeat steps 2, 3, and 4 until the testers can no longer create additional test cases that break the functionality of the code. Each time a test fails, the developers fix the functionality based on the test cases and submit the improved code to the testers for a new round of testing.

Step 5: Refactor the Code


After the completion of the previous steps, the code can be run and is capable of handling all of the test cases. In this step, the developers refactor the code to make it maintainable and extensible, so that changes in one part of the module can be worked on in isolation without changing the actual interfaces exposed to the end user.

9-42

Developing Web Applications with Microsoft Visual Studio 2010

In addition to making code easier to maintain, refactoring removes duplicate code and can reduce code complexity. This helps to ensure that the basic principles of loosely coupled and highly cohesive design are followed without breaking the functionality in any way. Question: Have you ever authored tests as part of requirements gathering? Question: How does authoring tests before development change your mindset? Question: What design considerations will you need to make to accomplish test-driven development?

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-43

Lab 9: Debugging, Unit Testing, and Refactoring

Objectives
After completing this lab, you will be able to: Configure error handling. Debug code. Configure logging. Create unit tests. Implement the test-first/test-driven development methodology.

Introduction
In this lab you will configure error handling in a web application, debug code to identify errors, log errors to the event log, and create and run unit tests.

9-44

Developing Web Applications with Microsoft Visual Studio 2010

Lab Scenario

Adventure Works has requested that you look into how you can improve the quality of the coding. As a first step toward this end, your team has determined you should look into the following functionality and features of Visual Studio 2010 and the .NET Framework: Configure error handling Debug code Log errors Implement a code-first development methodology Implement a test-first/test-driven development methodology

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-45

Exercise 1: Configuring Error Handling


The main tasks for this exercise are as follows: Create a generic error page for unhandled errors. Modify Global.asax and Web.config to redirect to the generic error page when an unhandled error occurs.

Task 1: Open an existing ASP.NET web application


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the D:\Lab Files\CS\Lab 09\Starter\Exercise 01 or D:\Lab Files\VB\Lab 09\Starter\Exercise 01 folder.

Task 2: Create a generic error page for unhandled errors


1. 2. 3. 4. Add a new Web Form named CustomErrorPage. Add the text CUSTOM ERROR PAGE to the CustomErrorPage Web Form. Save the AdventureWorks project. Close the CustomErrorPage Web Form.

Task 3: Modify Web.config to redirect to the generic error page when an unhandled
error occurs
1. 2. 3. 4. 5. Open the Web.config file. Add the following markup to the system.web element.
<customErrors mode="On" defaultRedirect="~/CustomErrorPage.aspx"/>

Save and close the Web.config file. Run the application. Click the Submit button. Note: The custom error page is displayed.

6. 7.

Close Windows Internet Explorer. Close Visual Studio 2010. Results: After this exercise, you should have created a custom error page for unhandled exceptions.

9-46

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 2: Debugging Code


The main tasks for this exercise are as follows: Run the application. Debug Default.aspx. Debug a java script error using breakpoints and single-stepping. Debug Default.aspx.js.

Task 1: Open an existing ASP.NET web application


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the D:\Lab Files\CS\Lab 09\Starter\Exercise 02 or D:\Lab Files\VB\Lab 09\Starter\Exercise 02 folder.

Task 2: Run the application


1. 2. Set Default.aspx as the project start page. Run the application in Debug mode.

Task 3: Debug Default.aspx


1. Click the Submit button.

Note: In Visual Studio, in the FormatException was unhandled by user code pane, the error text Input string was not in a correct format is displayed. 2. Press F5 to continue.

Note: The custom error page is displayed. Do not close Internet Explorer. 3. In Visual Studio, place a breakpoint in Default.aspx.cs or Default.aspx.vb on the following line of code.
[Visual C#] string category = lbCategories.SelectedValue;

[Visual Basic] Dim category As String = lbCategories.SelectedValue

4.

Click the Back button on your browser.

Note: The Home page is displayed. 5. Click the Submit button.

Note: Visual Studio is now shown, with the breakpoint highlighted. 6. Press F10 to step over the line of code that sets the local variable category to the selected value of the list.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-47

7. 8. 9.

Hover the mouse over category and notice it is an empty string, which cannot be parsed by the code in the Products page. Press SHIFT+F5 to end debugging. In Visual Studio, modify the line of code that sets the local variable category to the selected value of the list, as follows.
[Visual C#] string category = lbCategories.SelectedValue == string.Empty ? "5" : lbCategories.SelectedValue; [Visual Basic] Dim category As String = IIf(lbCategories.SelectedValue = String.Empty, "5", lbCategories.SelectedValue)

Note: If the breakpoint disappears after modifying the line of code, place the cursor on the line of code, and then press F9. 10. Run the application in Debug mode. 11. Click the Submit button. Note: Visual Studio is now shown, with the breakpoint highlighted. 12. Press F10 to step over the line of code that sets the local variable category to the selected value of the list. 13. Hover the mouse over category and notice it is a string with the value of 5. 14. Press F5 to continue. Note: The Products page is displayed, showing a list of Mountain Bikes. 15. Close Windows Internet Explorer. 16. Remove all breakpoints by pressing CTRL+SHIFT+F9.

Task 4: Debug a java script error using breakpoints and single stepping
Run the application in Debug mode. Note: The Home page is displayed.

Task 5: Debug Default.aspx.js


1. Click the Select First button. Note: A dialog box with an alert message is now shown. 2. 3. In the Message from webpage message box, click OK three times. In Visual Studio, place a breakpoint in Default.aspx.js on the following line of code.

9-48

Developing Web Applications with Microsoft Visual Studio 2010

for (i = 0; i < 3;

i++) {

4.

Click the Back button in your browser. Note: The Home page is displayed.

5.

Click the Select First button. Note: Visual Studio is now shown, with the breakpoint highlighted.

6. 7. 8. 9.

Press F10 to step over the statements of code, until a message box is displayed. In the Message from webpage message box, click OK. Repeat the previous two steps twice. Press F5. Note: The Products page is displayed.

10. Close Windows Internet Explorer. 11. Close Visual Studio 2010. Results: After this exercise, you should have experience debugging Visual C# or Visual Basic, and java script code.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-49

Exercise 3: Logging
The main tasks for this exercise are as follows: Configure logging to an Error Log. Set the logging level in the Web.config file to allow for future debugging. Create a generic error handler.

Task 1: Open an existing ASP.NET web application


1. 2. Open Microsoft Visual Studio 2010. Open the AdventureWorks solution from the D:\Lab Files\CS\Lab 09\Starter\Exercise 03 or D:\Lab Files\VB\Lab 09\Starter\Exercise 03 folder.

Task 2: Configure logging to an Error Log


1. 2. Open Products.aspx in Code view. Import the System.Diagnostics namespace.
[Visual C#] using System.Diagnostics; [Visual Basic] Imports System.Diagnostics

3.

Modify the Page_Load method with the following code.


[Visual C#] protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { string categoryName = string.Empty; string categoryId = string.Empty; if (Request["id"] != null) { categoryId = Request["id"]; } try {

categoryName = DataAccessLayer.Products.GetCategoryName(int.Parse(categoryId)); } catch (Exception ex) { EventLog Log = new EventLog(); Log.Source = "Application"; Log.WriteEntry(ex.Message, EventLogEntryType.Error); } lblCategory.Text = categoryName; var data = DataAccessLayer.Products.GetProductsByCategory(int.Parse(categoryId)); gvProducts.DataSource = data; gvProducts.DataBind();

[Visual Basic]

9-50

Developing Web Applications with Microsoft Visual Studio 2010

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load If Not Page.IsPostBack Then Dim categoryName As String = String.Empty Dim categoryID As String = String.Empty If Not Request("id") Is Nothing Then categoryID = Request("id") End If categoryName = AdventureWorks.DataAccessLayer.Products.GetCategoryName(Integer.Parse(categoryID)) Catch ex As Exception Dim Log As New EventLog() Log.Source = "Application" Log.WriteEntry(ex.Message, EventLogEntryType.[Error]) End Try lblCategory.Text = categoryName Dim data = AdventureWorks.DataAccessLayer.Products.GetProductsByCategory(Integer.Parse(categoryID )) gvProducts.DataSource = data gvProducts.DataBind() End If End Sub Try

4.

Run the application. Note: The custom error page is displayed.

5.

Open the Event Viewer and show the Application log entry. If necessary, sort the Application log entries by date and time.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-51

6. 7.

Close the Event Viewer. Close Windows Internet Explorer.

Task 3: Set the logging level in the Web.config file to allow for future debugging
1. 2. 3. Open the Web.config file. In the opening compilation tag, ensure that the value of the debug attribute is set to true.
<compilation debug="true" ...>

Close the Web.config file.

Task 4: Create a generic error handler


1. Open the Global.asax file. 2. In Solution Explorer, double-click Global.asax.
[Visual C#] using System.Diagnostics; [Visual Basic] Imports System.Diagnostics

Import the System.Diagnostics namespace.

3.

Modify the Application_Error method with the following code.


[Visual C#] void Application_Error(object sender, EventArgs e) { string message = "Url: " + Request.Path + " Error: " + Server.GetLastError().ToString(); EventLog log = new EventLog();

9-52

Developing Web Applications with Microsoft Visual Studio 2010

log.Source = "Application"; log.WriteEntry(message, EventLogEntryType.Error);

[Visual Basic] Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs) Dim message As String = "Url: " & Request.Path & " Error: " & Server.GetLastError().ToString() Dim log As New EventLog() log.Source = "Application" log.WriteEntry(message, EventLogEntryType.Error) End Sub

4.

Build the project and fix any errors. In the AdventureWorks Microsoft Visual Studio window, on the Build menu, click Build AdventureWorks.

5.

Close Visual Studio 2010. In the AdventureWorks Microsoft Visual Studio window, click the Close button

Results: After this exercise, you should have experience installing a generic error handler for logging that can be called by a single method and all modules.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-53

Exercise 4: Creating Unit Tests


The main tasks for this exercise are as follows: Create a method to add two numbers. Add a test project. Edit the test method to pass. Run the test. Edit the test method to fail. Run the tests.

Task 1: Open an existing ASP.NET web application


1. 2. Open Microsoft Visual Studio 2010. Open the MyClassLibrary solution from the D:\Lab Files\CS\Lab 09\Starter\Exercise 04 or D:\Lab Files\VB\Lab 09\Starter\Exercise 04 folder.

Task 2: Create a method to add two numbers


1. 2. Open the Calculator.cs or Calculator.vb file. Add the following code to Calculator class.
[Visual C#] public int Add(int p1, int p2) { return p1 + p2; } [Visual Basic] Public Function Add(ByVal p1 As Integer, ByVal p2 As Integer) As Integer Return p1 + p2 End Function

3. 4.

Save Calculator.cs or Calculator.vb. Build the project and fix any errors.

Task 3: Add a test project


Add a test project named CalculatorTestProject for the Add method.

Task 4: Edit the test method to pass


1. In the AddTest method, modify the value assigned to local variable p1 to 2.
[Visual C#] int p1 = 2; [Visual Basic] Dim p1 As Integer = 2

2.

In the AddTest method, modify the value assigned to local variable p2 to 3.


[Visual C#] int p2 = 3; [Visual Basic] Dim p2 As Integer = 3

9-54

Developing Web Applications with Microsoft Visual Studio 2010

3.

In the AddTest method, modify the value assigned to local variable expected to 5.
[Visual C#] int expected = 5; [Visual Basic] Dim expected As Integer = 5

4.

Remove the following code.


[Visual C#] Assert.Inconclusive("Verify the correctness of this test method."); [Visual Basic] Assert.Inconclusive("Verify the correctness of this test method.")

5.

Ensure the AddTest method appears as follows.


[Visual C#] [TestMethod()] public void AddTest() { Calculator target = new Calculator(); int p1 = 2; // TODO: Initialize to an int p2 = 3; // TODO: Initialize to an int expected = 5; // TODO: Initialize int actual; actual = target.Add(p1, p2); Assert.AreEqual(expected, actual); }

// TODO: Initialize to an appropriate value appropriate value appropriate value to an appropriate value

[Visual Basic] <TestMethod()> _ Public Sub AddTest() Dim target As Calculator = New Calculator() ' TODO: Initialize to an appropriate value Dim p1 As Integer = 2 ' TODO: Initialize to an appropriate value Dim p2 As Integer = 3 ' TODO: Initialize to an appropriate value Dim expected As Integer = 5 ' TODO: Initialize to an appropriate value Dim actual As Integer actual = target.Add(p1, p2) Assert.AreEqual(expected, actual) End Sub

Task 5: Run the test


Start the test. Note: In the Test Result window, you can see that the AddTest test passed.

Task 6: Edit the test method to fail


1. In the AddTest method, modify the value assigned to local variable expected to 6.
[Visual C#] int expected = 6; [Visual Basic] Dim expected As Integer = 6

2.

Ensure the AddTest method appears as follows.


[Visual C#]

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-55

[TestMethod()] public void AddTest() { Calculator target = new Calculator(); int p1 = 2; // TODO: Initialize to an int p2 = 3; // TODO: Initialize to an int expected = 6; // TODO: Initialize int actual; actual = target.Add(p1, p2); Assert.AreEqual(expected, actual); }

// TODO: Initialize to an appropriate value appropriate value appropriate value to an appropriate value

[Visual Basic] <TestMethod()> _ Public Sub AddTest() Dim target As Calculator = New Calculator() ' TODO: Initialize to an appropriate value Dim p1 As Integer = 2 ' TODO: Initialize to an appropriate value Dim p2 As Integer = 3 ' TODO: Initialize to an appropriate value Dim expected As Integer = 6 ' TODO: Initialize to an appropriate value Dim actual As Integer actual = target.Add(p1, p2) Assert.AreEqual(expected, actual) End Sub

Task 7: Run the tests


1. Start the test.

Note: In the Test Result window, you can see that the AddTest test failed. 2. Close Visual Studio 2010.

Results: After this exercise, you should have experience creating unit tests for existing methods.

9-56

Developing Web Applications with Microsoft Visual Studio 2010

Exercise 5: Implementing the Test-First/Test-Driven Development Methodology


The main tasks for this exercise are as follows: Create tests. Create method stub. Run the tests. Add logic to stub methods. Run the tests.

Task 1: Open an existing ASP.NET web application


1. 2. Open Microsoft Visual Studio 2010. Open the MyClassLibrary solution from the D:\Lab Files\CS\Lab 09\Starter\Exercise 05 or D:\Lab Files\VB\Lab 09\Starter\Exercise 05 folder.

Task 2: Create tests


1. 2. Open CalculatorTest.cs or CalculatorTest.vb file in the CalculatorTestProject project. Add the following code to CalculatorTest class.
[Visual C#] [TestMethod()] public void ClassMultiplyMethodTest() { Calculator target = new Calculator(); Assert.IsNotNull(target); int expected = 6; int unexpected = 5; int actual = target.Multiply(3, 2); Assert.AreEqual(expected, actual); Assert.AreNotEqual(unexpected, actual);

[TestMethod()] public void ClassSubtractMethodTest() { Calculator target = new Calculator(); Assert.IsNotNull(target); int expected = 1; int unexpected = 6; int actual = target.Subtract(3, 2); Assert.AreEqual(expected, actual); Assert.AreNotEqual(unexpected, actual);

[Visual Basic] <TestMethod()> Public Sub ClassMultiplyMethodTest() Dim target As New Calculator() Assert.IsNotNull(target)

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-57

Dim expected As Integer = 6 Dim unexpected As Integer = 5 Dim actual As Integer = target.Multiply(3, 2) Assert.AreEqual(expected, actual) Assert.AreNotEqual(unexpected, actual) End Sub <TestMethod()> Public Sub ClassSubtractMethodTest() Dim target As New Calculator() Assert.IsNotNull(target) Dim expected As Integer = 1 Dim unexpected As Integer = 6 Dim actual As Integer = target.Subtract(3, 2) Assert.AreEqual(expected, actual) Assert.AreNotEqual(unexpected, actual) End Sub

3.

Save the CalculatorTest.cs or CalculatorTest.vb file.

Task 3: Create method stub


1. 2. Open the Calculator.cs or Calculator.vb file in the ClassLibrary project. Add the following code to the Calculator class.
[Visual C#] public int Multiply(int p1, int p2) { throw new NotImplementedException(); } public int Subtract(int p1, int p2) { throw new NotImplementedException(); } [Visual Basic] Public Function Multiply(ByVal p1 As Integer, ByVal p2 As Integer) As Integer Throw New NotImplementedException() End Function Public Function Subtract(ByVal p1 As Integer, ByVal p2 As Integer) As Integer Throw New NotImplementedException() End Function

3.

Build the solution and fix any errors.

Task 4: Run the tests


1. 2. Open the CalculatorTest.cs or CalculatorTest.vb file. Start the ClassMultiplyMethodTest test. Note: In the Test Result window, you can see that the ClassMultiplyMethodTest test failed. 3. Start the ClassSubtractMethodTest test.

9-58

Developing Web Applications with Microsoft Visual Studio 2010

Note: In the Test Result window, you can see that the ClassSubtractMethodTest test failed. 4. Close the CalculatorTest.cs or CalculatorTest.vb file.

Task 5: Add logic to the stub methods


1. Replace the Multiply method in the Calculator class with following code.
[Visual C#] public int Multiply(int p1, int p2) { return p1 * p2; } [Visual Basic] Public Function Multiply (ByVal p1 As Integer, ByVal p2 As Integer) As Integer Return p1 * p2 End Function

2.

Replace the Subtract method in the Calculator class with following code.
[Visual C#] public int Subtract(int p1, int p2) { return p1 - p2; } [Visual Basic] Public Function Subtract(ByVal p1 As Integer, ByVal p2 As Integer) As Integer Return p1 - p2 End Function

3.

Build the solution and fix any errors.

Task 6: Run the tests


1. 2. Open CalculatorTest.cs or CalculatorTest.vb file in the CalculatorTestProject project. Start the ClassMultiplyMethodTest test. Note: In the Test Result window, you can see that the ClassMultiplyMethodTest test passed. 3. Start the ClassSubtractMethodTest test. Note: In the Test Result window, you can see that the ClassSubtractMethodTest test passed. 4. 5. Close the CalculatorTest.cs or CalculatorTest.vb file. Close Visual Studio 2010.

Task 7: Turn off the virtual machine and revert the changes
1. 2. 3. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Turn Off. In the Turn Off Machine dialog box, click Turn Off. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click Revert.

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-59

4.

In the Revert Virtual Machine dialog box, click Revert. Results: After this exercise, you should have experience creating tests first, and then implementing methods.

9-60

Developing Web Applications with Microsoft Visual Studio 2010

Lab Review

Question: Why was the generic error handler implemented in the Global.asax file? Question: Where was a custom error page configured? Question: What are the advantages and disadvantages of using the Event Log for logging errors?

Ensuring Quality by Debugging, Unit Testing, and Refactoring

9-61

Module Review and Takeaways

Review Questions
1. 2. 3. 4. 5. 6. Do you believe unit testing will decrease the time you spend debugging? Have you ever broken code because of refactoring? Do you dedicate cycles to refactoring code? After applying a fix to an integrated module have you ever broken other modules? How have existing tests provided you with the intent of the original developer? What is the most helpful custom error page youve ever encountered? What features did it include?

Common Issues and Troubleshooting Tips Related to ASP.NET 4.0


Issue Security when writing to Error Log Troubleshooting tip Depending on operating systems, writing to the error log requires elevated security.

Real-world Issues and Scenarios

Unit test coverage requires additional effort, time, and money. These issues must be factored into estimates when starting a project. If you do not account for these, your project will be late and over budget. Your code is only as good as your tests. Writing a simple test that does not fully exercise your code does you no good. Tests that fully exercise the code give you meaningful results. Unit testing is not a replacement for Quality Assurance. Unit tests are authored through the eyes of a developer. Additional testing from an end user perspective should always be executed.

9-62

Developing Web Applications with Microsoft Visual Studio 2010

Mocking external components can be very complicated. Depending on the framework you use, mocking external systems or code without an interface can be extremely complicated to mock. Without mocks, it is very hard to isolate code and fully test it.

Best Practices
Supplement or modify the following best practices for your own work situations: Dont make unnecessary assertions. Test only one code unit at a time. Mock out all external services and state. Avoid unnecessary preconditions. Dont unit-test configuration settings. Name your unit tests clearly and consistently.

Tools
Tool NUnit Use for NUnit is an open source unittesting framework for all .NET languages. NMock is a dynamic mock object library for .NET. Mock objects make it easier to test single componentsoften single classeswithout relying on real implementations of all of the other components. Where to find it http://go.microsoft.com/fwlink/ ?LinkID=204073&clcid=0x409 http://go.microsoft.com/fwlink/ ?LinkID=204074&clcid=0x409

NMock

Das könnte Ihnen auch gefallen