Sie sind auf Seite 1von 497

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
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 1-3
Lesson 2: Overview of ASP.NET 4.0 1-15
Lesson 3: Introduction to the MVC Framework 1-19
Lesson 4: Overview of the Request Life Cycle 1-23
Lab 1: Adventure Works Website Review 1-28

Module 2: Designing a Web Application


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

Module 3: Developing MVC Models


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

Module 4: Developing MVC Controllers


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

Module 5: Developing MVC Views


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

Module 6: Designing for Discoverability


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

Module 7: Writing Server-Side Code for Web Forms


Lesson 1: Overview of the Structure of a Web Application 7-3
Lesson 2: Controlling View State 7-10
xii Developing Web Applications with Microsoft® Visual Studio® 2010

Lesson 3: Localizing a Web Application 7-16


Lesson 4: Persisting Data on a Web Forms Page 7-27
Lesson 5: Validating User Input 7-33
Lab 7: Writing Server-Side Code for Web Forms 7-42

Module 8: Optimizing Data Management for Web Forms


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

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


Lesson 1: Debugging and Refactoring Code 9-3
Lesson 2: Unit Testing Code 9-22
Lesson 3: Processing Unhandled Exceptions 9-30
Lesson 4: Test-Driven Development 9-37
Lab 9: Debugging, Unit Testing and Refactoring 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 it’s
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 Role


10264A-GEN-DEV 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 1-3
Lesson 2: Overview of ASP.NET 4.0 1-15
Lesson 3: Introduction to the MVC Framework 1-19
Lesson 4: Overview of the Request Life Cycle 1-23
Lab 1: Exploring the Adventure Works Website 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 application’s 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 application’s
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 IIS’s core modules and their responsibilities, such as Security and Management.
Gaining a deeper understanding of IIS’s 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.
• In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then click
Yes.
2. In Internet Information Services (IIS) Manager, expand 10264A-GEN-DEV (10264A-GEN-
DEV\Admin), and then expand Sites.
3. 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. In the Connections pane, click Demo.
2. In the Actions pane, click Edit Permissions.
3. In the demo Properties dialog box, click Security.

4. Click Edit.
5. In the Permissions for demo dialog box, click Add.
6. 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.
7. In the Permissions for demo dialog box, click OK.
8. In the demo Properties dialog box, click OK.

Set Connection String


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

3. In the Actions pane, click Add.


4. 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. Click OK.
6. In the Connection Strings pane, click Content View.
7. In the Demo Content pane, click web.config.

Note: A web.config file is added to the website’s root directory.

8. In the Connections pane, right-click Demo, and then click Explore.


9. 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. In the Connections pane, click Default Web Site, and then click Demo.
2. In the Demo Content pane, click Features View.
3. In the Demo Home pane, in the ASP.NET section, double-click Application Settings..
Overview of Web Application Architecture and Design 1-13

4. In the Actions pane, click Add.


5. In the Add Application Setting dialog box, specify the settings per the following.

6. Click OK.
7. 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. Close Microsoft Visual Studio 2010.


9. Close Windows Explorer.

Restart the Website


1. In the Connections pane, click Default Web Site, and then click Demo.
2. 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. In the Application Pools pane, click DefaultAppPool, and then in the Actions pane, in the
Application Pool Tasks section, click Recycle.
3. 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 request-
processing 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.
• 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 MVC project.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click New Project, or
press CTRL+SHIFT+N.
b. 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.
c. In the New Project dialog box, in the middle pane, click ASP.NET MVC 2 Web Application.
d. 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. In the Create Unit Test dialog box, select the No, do not create a unit test project option, and
then click OK.
4. 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


• In Solution Explorer, expand the Models folder.
6. View all the code in the AccountModels code file.
a. In Solution Explorer, double-click the AccountModels.cs or AccountModels.vb code file.
b. In the AccountModels.cs or AccountModels.vb window, press CTRL+M, CTRL+L.
c. 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. In the AccountModels.cs or AccountModels.vb window, click the Close button.


7. 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. The Web Forms page event life cycle begins with a request to a Page resource.
2. The HTTP handler processes the request and initializes the correct Page resource to handle the
request.
3. The page initializes, and all server controls in the page raise their initialization events as well.
4. On postbacks (when a HTTP Post request is received), Postback Data (data that is available in the
form) is loaded.
5. The page loads and all server controls raise their Load event.
6. On postbacks, the RaisePostBackEvent event is raised that can be accessed programmatically.
7. The view state is saved and the event is raised.
8. The page and all server controls are rendered into markup (HTML) and returned to the web server.
9. 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. The browser initiates a request.
2. ASP.NET Routing routes the request to the appropriate resource, initiates the necessary controller,
and invokes the action on the controller.
3. The controller requests the necessary data from the model and does a lookup to determine the view
that is required to render the response.
4. The controller passes the viewdata built from the data structure given by the model to the view.
5. The view takes the viewdata and renders the response.
6. 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 page’s 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 page’s 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. Open the AdventureWorks solution in Visual Studio 2010.
2. Start the web application.
3. Browse the products list.
4. Add products to the shopping cart.
5. Place an order.
6. Explore the life cycle of a Web Forms page.
7. Open the AdventureWorksMvc solution in Visual Studio 2010.
8. Explore the life cycle of an MVC request.

 Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd.
2. Open Microsoft Visual Studio 2010.
3. Open the AdventureWorks solution at the following location.

Programming Language Location

Microsoft Visual C#® D:\Lab Files\CS\Lab 01\Starter\WebForms

Microsoft Visual Basic® 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. Add one pair of Men’s Bib-Shorts, size M, to the shopping cart.
2. Continue shopping.

 Task 5: Place an order


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

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


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

4. Switch to Windows® Internet Explorer®.


5. Open the Home page.

Note: The debugger reaches your breakpoint in the Page_Load method.

6. Step through the web application startup until you reach the end of Page_Load method.
7. 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. Open a second instance of Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution at the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 01\Starter\MVC

Visual Basic D:\Lab Files\VB\Lab 01\Starter\MVC

 Task 8: Explore the life cycle of an MVC request


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

Note: The debugger reaches the breakpoint in the Application_Start method.

7. Examine the static/Shared RegisterRoutes method.


8. Step through the web application startup until you reach the last line of code in the Index action
method of the Home controller.
9. 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. View the AdventureWorks solution in Visual Studio 2010.
2. Examine the markup and code found in the Default.aspx Web Forms page.
3. View AdventureWorksMvc solution in Visual Studio 2010.
1. Examine the markup and code used for rendering the default MVC page.
2. 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. Examine the code in the Default.aspx.cs or Default.aspx.vb code file.
2. 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 Location

C# D:\Lab Files\CS\Lab 01\Starter\MVC

Visual Basic D:\Lab Files\VB\Lab 01\Starter\MVC

2. Examine the code in the HomeController.cs or HomeController.vb code file.


3. 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. Exploring the life cycle of a Web Forms page.
2. Exploring the life cycle of a MVC request.

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


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

5. View the code-behind file for the Default Web Form.


6. 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 page’s Load event, the text is added to the lblAdvertisement Label control.

8. Close Windows Internet Explorer.


9. Close Visual Studio 2010.

 Task 2: Explore the life cycle of a MVC request


1. Switch to the Visual Studio 2010 instance with the AdventureWorks solution open.
2. Open the Views\Home\Index.aspx view.
3. Locate the Content control with the ContentPlaceHolderID property value of MainContent.
4. 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. Locate the Index method in the file.
7. 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 controller’s 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. In Microsoft Hyper-V™ Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and
then click Turn Off.
2. In the Turn Off Machine dialog box, click Turn Off.
3. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click
Revert.
4. 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. What are some of the key features of IIS 7.0?
2. What is the purpose of the Adventure Works website?
3. What does it mean when we say that the architecture of IIS 7.0 is modular?
4. What is the MVC framework?
5. 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 2-3
Lesson 2: Web Application Design Essentials 2-9
Lesson 3: Visual Studio 2010 Tools and Technologies for
Web Application Design 2-19
Lab 2: Redesigning the Adventure Works Website 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 competitor’s site: Any distraction from finding and purchasing the products your e-
commerce 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 question’s
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
isn’t 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 client’s 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 client’s state throughout the client’s 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 Microsoft’s 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 in-
line 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 exception-
handling 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 application’s markup (HTML) so that
search engines can index it easily and properly. A significant portion of your site’s 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 site’s 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 engine’s 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. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd.
2. Open Microsoft Visual Studio 2010.
3. Open the AdventureWorks solution at the following location.

Programming Language Location

Visual C#® D:\Lab Files\CS\Lab 02\Solution\Exercise 01

Visual Basic® 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. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorks solution at the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 02\Starter\Exercise 03

Visual Basic D:\Lab Files\VB\Lab 02\Starter\Exercise 03

 Task 2: Add required assemblies to the project


1. Add references to the System.Web.Abstractions assembly to the project.
2. 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. Open the Web.config file in the root AdventureWorks folder.
2. 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.


The final Web.config file should appear as follows
[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>
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. Open the project, AdventureWorks.csproj or AdventureWorks.vbproj file in Notepad for direct
editing.
2. Locate the ProjectTypeGuids element.
[Visual C#]
<ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-
00c04f79efbc}</ProjectTypeGuids>

[Visual Basic]
<ProjectTypeGuids{349c5851-65df-11da-9384-00065b846f21};{F184B08F-C81C-45F6-A57F-
5ABD9991F28F}</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-9384-
00065b846f21};{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-9384-
00065b846f21};{F184B08F-C81C-45F6-A57F-5ABD9991F28F}</ProjectTypeGuids>
...

4. Save the project file.


5. Reload the AdventureWorks project.
6. Test the new project type by opening the Add New Item dialog box.
7. Close Visual Studio 2010.
Designing a Web Application 2-35

 Task 6: Turn off the virtual machine and revert the changes
1. In Microsoft Hyper-V™ Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and
then click Turn Off.
2. In the Turn Off Machine dialog box, click Turn Off.
3. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click
Revert.
4. 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. What are the stages of the application development process?
2. What value is there in identifying business goals during the design process?
3. How do design considerations factor into your decision to use Web Forms or MVC?
4. What similarities do Web Forms and MVC share?
5. What are some key differences between Web Forms and MVC?
6. Which business scenarios fit well with each framework?
7. What value is there in adding MVC functionality to an existing Web Forms application?

Real-world Issues and Scenarios


1. 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?
2. Your organization has determined that search engine optimization needs to be addressed in an
existing Web Forms application. What are your options?
3. 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 3-3
Lesson 2: Working with Data in MVC Models 3-10
Lesson 3: Creating a Data Repository 3-16
Lab 3: Creating MVC Models 3-30
3-2 Developing Web Applications with Microsoft® Visual Studio® 2010

Module Overview

The ASP.NET MVC Framework is Microsoft’s 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 parent-
child relationships—you 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 aren’t 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.
• 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 project, with an associated Unit Test project.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click New Project, or
press CTRL+SHIFT+N.
b. 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.
c. In the Create Unit Test Project dialog box, ensure the Yes, create a unit test project check box
is selected, and then click OK.
3. Add a new class named Blog to the Models folder.
a. In Solution Explorer, right-click Models, point to Add and then click New Item, or press
CTRL+SHIFT+A.
b. 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-to-
one 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 Microsoft’s 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.
• 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 MvcApplication1 solution at the following location.

Programming Language Location

Visual C# D:\Demofiles\CS\MvcApplication1

Visual Basic D:\Demofiles\VB\MvcApplication1

a. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project, or
press CTRL+SHIFT+O.
b. 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. In Solution Explorer, right-click Models, point to Add, and then click New Item.
b. In the Add New Item – MvcApplication1 dialog box, in the left pane, click Data.
c. 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. In the Entity Data Model Wizard, on the Choose Model Contents page, click Generate from
database, and then click Next.
4. 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. In the Choose Data Source dialog box, in the Data source list, click Microsoft SQL Server, and
then click OK.
b. 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-gen-
dev\sqlexpress.AdventureWorksLT2008R2.Sales(LT), and then click Next.
6. 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.

7. Add a new data repository class named BlogRepository to the Models folder.
a. In Solution Explorer, right-click Models, point to Add, and then click New Item.
b. In the Add New Item – MvcApplication1 dialog box, in the left pane, click Visual C# or Visual
Basic.
c. 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. In Solution Explorer, in the Models folder, right-click Blog.cs or Blog.vb, and then click Delete.
b. 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. Open the AdventureWorksMvc solution in Visual Studio 2010.
2. Open AdventureWorks database.
3. Examine the table schemas.
4. Add Relationships between tables using Diagrams.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd.
2. Open Microsoft Visual Studio 2010.
3. Open the AdventureWorksMvc solution at the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 03\Starter\Exercise 01

Visual Basic 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. Display the list of tables.
2. Open the Customer (SalesLT) table in the Table Designer.
Developing MVC Models 3-33

3. Examine the schema of the table.


4. 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. Close the Database Designer and do not save the diagram.


3. 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. Open the AdventureWorksMvc solution in Visual Studio 2010.
2. Add Entity Data Model to the web application.
3. Add data repository.
4. Implement list, select, insert, update, and delete operations.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution at the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 03\Starter\Exercise 02

Visual Basic 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. Save all modified files.


8. 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. Open the AdventureWorksMvc solution in Visual Studio 2010.
2. Add a partial class to the Models folder.
3. Add business rules validation.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution at the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 03\Starter\Exercise 03

Visual Basic D:\Lab Files\VB\Lab 03\Starter\Exercise 03

 Task 2: Add a partial class to the Models folder


1. Add a new class named Blog to the Models folder.
2. 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. Build the solution, and fix any errors.


4. Close Visual Studio 2010.

 Task 4: Turn off the virtual machine and revert the changes
1. In Microsoft Hyper-V™ Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and
then click Turn Off.
2. In the Turn Off Machine dialog box, click Turn Off.
3. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click
Revert.
4. 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. Name some other object-relational mapping tools besides LINQ to SQL and the Entity Framework.
2. What is the name of the pattern that is used to map the database tables to the classes?
3. How is the Data Mapper pattern different from the Active Record pattern?
4. 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.
2. 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.

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 4-3
Lesson 2: Creating Action Methods 4-13
Lab 4: Developing MVC Controllers 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 method’s 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.
• 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 project, with an associated Unit Test project.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click New Project, or
press CTRL+SHIFT+N.
b. 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.
c. In the Create Unit Test Project dialog box, ensure that Yes, create a unit test project is
selected, and then click OK.
3. Create a controller named BlogController in the Controllers folder. The controller should include
action methods for create, update, delete, and details scenarios.
a. In Solution Explorer, right-click Controllers, point to Add and then click Controller.
b. 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 Description

Authorization 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.

Action 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.
4-8 Developing Web Applications with Microsoft® Visual Studio® 2010

Filter type Description

Result 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.

Exception 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.

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. Filters that are applied to a controller automatically apply to every action method in that controller.
2. 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.
3. Filters with the same order number are applied in an undetermined order.
4. 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.
• 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 MvcApplication1 solution from the following location.

Programming Language Location

Visual C# D:\Demofiles\CS\MvcApplication1

Visual Basic D:\Demofiles\VB\MvcApplication1

a. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project, or
press CTRL+SHIFT+O.
b. 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.
6. Add a customErrors element to the Web.config file.
<system.web>

<customErrors mode="On" />


</system.web>

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 method’s 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 methods—how 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 Control action return

Void/Sub or The ControllerActionInvoker object returns an EmptyResult object.


null/Nothing

ActionResult The ControllerActionInvoker object calls the ExecuteResult method on


the result.

Object (excluding The result is passed to a CreateActionResult, which creates a new


ActionResult) 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 Helper method Description

ViewResult View 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.

PartialViewResult PartialView Renders a partial view, which defines a section of a


view that can be rendered inside another view.

RedirectResult Redirect Redirects to another action method by using its


URL.

RedirectToRouteResult RedirectToAction Redirects to another action method.


RedirectToRoute

ContentResult Content Returns a user-defined content type.


4-18 Developing Web Applications with Microsoft® Visual Studio® 2010

Action result Helper method Description

JsonResult Json Returns a serialized Json object.

JavaScriptResult JavaScript Returns a script that can be executed on the client.

FileResult File Returns binary output to write to the response.

EmptyResult (None) 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 controller’s 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 controller’s TempDataDictionary object before it calls the
controller’s 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 request’s 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 today’s
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 Description

Errors Returns a ModelErrorCollection object that contains any errors that


occurred during model binding.

Value 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.
• 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 DemoHello solution from the following location.

Programming Language Location

Visual C# D:\Demofiles\CS

Visual Basic D:\Demofiles\VB


c. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project, or
press CTRL+SHIFT+O.
d. 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. Run the project by pressing CTRL+F5.
b. In the Hello Page - Windows Internet Explorer window, click Hello.
c. 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. Close Windows® Internet Explorer®.


4. Retrieve data from the QueryString.
a. Run the project by pressing CTRL+F5.
b. In the Hello Page - Windows Internet Explorer window, click Hello.
c. 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. Close Internet Explorer.


5. 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. In Solution Explorer, click DemoHello.


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

f. In the Enter Your Name box, type your name, and then click Submit.

Note: The value entered in the text box is displayed.

g. Close Internet Explorer.


6. 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. Run the project by pressing CTRL+F5.


c. In the Hello Page- Windows Internet Explorer window, click Hello.
d. Append the following text to the URL in the address bar, and then press ENTER.
/FormCollectionDemo

e. In the Enter Your Name box, type your name, and then click Submit.
f. In the AutoComplete dialog box, click No.

Note: The value entered in the text box, retrieved from the FormCollection object, is
displayed.

g. Close Internet Explorer.


h. 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. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd.
2. Open Microsoft Visual Studio 2010.
3. Open the AdventureWorksMvc solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 04\Starter\Exercise 01

Visual Basic D:\Lab Files\VB\Lab 04\Starter\Exercise 01

 Task 2: Create a controller named BlogController


1. Create a controller named BlogController in the Controllers folder. The controller should not
include action methods for create, update, delete, and details scenarios.
2. 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. Build the solution, and fix any errors.


5. 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. Open the AdventureWorksMvc solution in Visual Studio 2010.
2. Add a blogRepository object.
3. Add code to the Index action method.
4. Create a Blogger action method.
5. Create a Details action method.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 04\Starter\Exercise 02

Visual Basic 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. Build the solution, and fix any errors.


5. 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. Open the AdventureWorksMvc solution in Visual Studio 2010.


2. Create a Create action method.
3. Create a Create action method that accepts an HTTP Post.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 04\Starter\Exercise 03

Visual Basic 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. Build the solution, and fix any errors.


5. 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. Open the AdventureWorksMvc solution in Visual Studio 2010.
2. Create an Edit action method.
3. Create an Edit action method for an HTTP Post request.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 04\Starter\Exercise 04

Visual Basic 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. Build the solution, and fix any errors.


5. 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. Open the AdventureWorksMvc solution in Visual Studio 2010.
2. Create a Delete action method.
3. Create a Delete action method for an HTTP Post request

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 05\Starter\Exercise 03

Visual Basic 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. Build the solution, and fix any errors.


5. Close Visual Studio 2010.

 Task 4: Turn off the virtual machine and revert the changes
1. In Microsoft Hyper-V™ Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and
then click Turn Off.
2. In the Turn Off Machine dialog box, click Turn Off.
3. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click
Revert.
4. 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. What are the responsibilities of the controller class?
2. What are some possible action filters?
3. What are some ways to pass data to a view?
4. 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 5-3
Lesson 2: Implementing Strongly-Typed MVC Views 5-14
Lesson 3: Implementing Partial MVC Views 5-28
Lab 5: Developing MVC Views 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
controller’s 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.
• 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 project, without an associated Unit Test project.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click New Project, or
press CTRL+SHIFT+N.
b. 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.
c. In the Create Unit Test Project dialog box, ensure No, do not create a unit test project is
selected, and then click OK.
3. Delete the Home\About view.
a. In Solution Explorer, expand Views, expand Home, right-click About.aspx, and then click
Delete.
b. In the Microsoft Visual Studio dialog box, click OK.
4. Create an empty view named About in the Home folder.
a. In Solution Explorer, right-click Home, point to Add and then click View.
b. In the Add View dialog box, in the View name box, type About, clear the Create a strongly-
typed 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

• In the MvcApplication1 – Microsoft Visual Studio window, on the Build menu, click Build
Solution, or press CTRL+SHIFT+B.
6. Run the application.
a. In Solution Explorer, click MvcApplication1.
b. In the MvcApplication1 – Microsoft Visual Studio window, on the Debug menu, click Start
Without Debugging, or press CTRL+F5.
c. 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>

<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 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.
• 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 project, without an associated Unit Test project.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click New Project, or
press CTRL+SHIFT+N.
b. 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.
c. In the Create Unit Test Project dialog box, ensure No, do not create a unit test project is
selected, and then click OK.
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. In Solution Explorer, right-click Models, point to Add, and then click Class.
b. In the Add New Item dialog box, in the Name box, type Person.cs or Person.vb, and then click
Add.
c. 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. In Solution Explorer, expand Views, right-click Home, point to Add and then click View.
b. [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.
c. [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.
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. In Solution Explorer, expand Controllers, and then double-click HomeController.


b. 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. In Solution Explorer, click StronglyTypedView.
b. 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 view’s ViewData object. The parent
view’s 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.
[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>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) %>
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.
• 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 StronglyTypedView solution used in the previous demonstration.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project, or
press CTRL+SHIFT+O.
b. 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. In Solution Explorer, expand Views, right-click Home, point to Add, and then click View.
b. [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. In Solution Explorer, expand Views, right-click Home, point to Add, and then click View.
b. 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.
5. 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. In Solution Explorer, click StronglyTypedView.
b. 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 strongly-
typed 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. Add a Blog menu item to the Site.Master page.
2. Add a view to display the complete list of blogs.
3. Test the new view.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd.
2. Open Microsoft Visual Studio 2010.
3. Open the AdventureWorksMvc solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 05\Starter\Exercise 01

Visual Basic D:\Lab Files\VB\Lab 05\Starter\Exercise 01

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


1. Open the Site.Master page.
2. 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. Add a Blog subfolder to the Views folder.
2. Add an empty view named Index.aspx, based on the Site.Master page, to the Blog folder.
3. 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. Run the application.
2. Display the Blog view.
3. Close Internet Explorer.
4. 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:
• Add a strongly-typed details view named Details.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 05\Starter\Exercise 02

Visual Basic D:\Lab Files\VB\Lab 05\Starter\Exercise 02

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


1. Add an empty, strongly-typed view of type Blog, named Details based on the Site.Master master
page, to the Blog folder.
2. 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. Test the Details view.


5. Close Internet Explorer.
6. 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. Add a strongly-typed view named Blogger to list all of the blogs for a particular blogger.
2. Add a strongly-typed view named Create.
3. Use TempData to add a confirmation message to the Index view.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 05\Starter\Exercise 03

Visual Basic D:\Lab Files\VB\Lab 05\Starter\Exercise 03

 Task 2: Add a strongly-typed view named Blogger to list all of the blogs for a particular
blogger
1. Add an empty, strongly-typed view named Blogger based on the Site.Master master page, to the
Blog folder.
2. 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 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 %>
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. Run the application.


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

6. Add a blog entry.


7. Close Internet Explorer.

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


1. Open the Index view.
2. 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. Run the application.


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

6. Add another blog entry.


7. Close Internet Explorer.
8. 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. Create a partial view named Blog.
2. Create an edit view named Edit, which uses the Blog partial view.
3. Edit a blog entry.
4. Update the Create view to use the Blog partial view.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 05\Starter\Exercise 04

Visual Basic D:\Lab Files\VB\Lab 05\Starter\Exercise 04

 Task 2: Create a partial view named Blog


1. Add an empty, strongly-typed partial view of type Blog, named Blog, to the Blog folder.
2. 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. Add an empty, strongly-typed view of type Blog, named Edit, based on the Site.Master master page,
to the Blog folder.
2. 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. Run the application.
2. Navigate directly to the Blogger view by using the following route.
Developing MVC Views 5-51

blog/blogger/1

3. Edit a blog entry.


4. 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. Run the application.


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

5. Add another blog entry.


6. Close Internet Explorer.
7. 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. Add a strongly-typed view named Delete that uses the default markup provided by the Add View
dialog box.
2. Delete a blog entry.

 Task 1: Open the AdventureWorksMvc solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorksMvc solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 05\Starter\Exercise 05

Visual Basic D:\Lab Files\VB\Lab 05\Starter\Exercise 05

 Task 2: Add a strongly-typed view named Delete that uses the default markup provided
by the Add View dialog box
1. Build the solution.
2. 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.
3. Update the markup and code that renders the Back to List link to match the following.
<%: Html.ActionLink("Back to List", "Blogger") %>

4. 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. Navigate directly to the Blogger view by using the following route.


blog/blogger/1

3. Select a blog entry.


4. Close Internet Explorer.
5. Close Visual Studio 2010.

 Task 4: Turn off the virtual machine and revert the changes
1. In Microsoft Hyper-V™ Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and
then click Turn Off.
2. In the Turn Off Machine dialog box, click Turn Off.
3. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click
Revert.
4. 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 6-3
Lesson 2: Discoverability Files 6-12
Lesson 3: Using ASP.NET Routing 6-22
Lab 6: Designing for Discoverability 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 website’s 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 website’s 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 website’s 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. 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.
b. In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then click
Yes.
2. In Internet Information Services (IIS) Manager, in the right pane, in the Site Analysis section, click
Create a new analysis.
3. 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 page’s 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. 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.
b. In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then click
Yes.
2. In Internet Information Services (IIS) Manager, in the right pane, in the Site Analysis section, click
View existing reports.
3. 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 page’s
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. On the Start menu, click Control Panel.
b. In Control Panel, click System and Security, and then click Administrative Tools.
c. Right-click Internet Information Services (IIS) Manager, and then click Run as administrator.
2. In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then press
ENTER.
3. 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 file’s 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.
• On the Start menu, click Control Panel.
2. In Control Panel, click System and Security, and then click Administrative Tools.
3. Right-click Internet Information Services (IIS) Manager, and then click Run as administrator.
4. In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then press
ENTER.
5. 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. In the Search Engine Optimization pane, in the Sitemaps and Sitemap Indexes section, click
Create a new sitemap.
b. In the Choose Site dialog box, in the Site list, click Default Web Site, and then click OK.
c. In the Add Sitemap dialog box, in the File Name box, type Sitemap.xml, and then click OK.
d. 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

• In the Control Panel\System and Security\Administrative Tools window, click the Close
button.
9. 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 Location

Visual C#® D:\Demofiles\CS

Visual Basic® D:\Demofiles\VB

a. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project, or
press CTRL+SHIFT+O.
b. 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. In Solution Explorer, right-click WebFormsRouting, and then click Add Reference.
b. In the Add Reference dialog box, click .NET.
c. 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. In Solution Explorer, click WebFormsRouting.
b. 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 application’s 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using 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 browser’s 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 browser’s 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 System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using 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. On the File menu, click New Project.
b. In the Installed Templates section, expand Visual Basic or Visual C#, and then click Web.
c. In the list of project types, click ASP.NET MVC 2 Web Application.
d. In the Name box, type Routes.
e. In the Location box, type D:\Demofiles\CS\Module06 or D:\Demofiles\VB\Module06, and
then click OK.
f. 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. In the Solution Explorer window, right-click Controllers, point to Add, and then click Controller.
b. 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. In the Solution Explorer window, right-click Views, point to Add, and then click New Folder.
b. In the text box, type Address, and then press ENTER.
c. In the Solution Explorer window, right-click Address, point to Add, and then click View.
d. In the Add View dialog box, in the View name box, type List, and then click Add.
8. 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. In Solution Explorer, click Routes.
b. 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 non-
nullable 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 non-
nullable 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. In the Routes – Microsoft Visual Studio window, click Global.asax.cs or Global.asax.vb.


b. 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. In the Solution Explorer window, click Routes.
b. 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.


• In the window The resource cannot be found. – Windows Internet Explorer, click the Close
button.
5. 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. Add and verify reference to System.Web.Routing.
2. Edit the Global.asax file to use ASP.NET URL mapping for the page listing products by category.
3. Test the pages.
4. Add a second route to map a URL to the following product ID: http://localhost/product/1.
5. Test the pages.

 Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd.
2. Open Microsoft Visual Studio 2010.
3. Open the AdventureWorks solution at the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 06\Starter\Exercise 01

Visual Basic D:\Lab Files\VB\Lab 06\Starter\Exercise 01

 Task 2: Add and verify a reference to the System.Web.Routing assembly


1. Add a reference to the System.Web.Routing assembly.
2. Verify a reference to the System.Web.Routing assembly.

 Task 3: Map the page listing products by category


1. Open the Global.asax file.
2. Import the System.Web.Routing namespace in the Global.asax code file.
3. 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. Open the Products.aspx.cs or Products.aspx.vb code file.


6. 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. Run the application.
2. 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. Open the Global.asax file.
2. 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. Open the ProductDetail.aspx.cs or ProductDetail.aspx.vb code file.


4. 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. Run the application.
2. 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. Close Internet Explorer.


4. 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. Create a sitemap file to list products.
2. Modify the robots.txt file to include the sitemap.

 Task 1: Create a sitemap file to list products


1. Open Internet Information Services (IIS) Manager as an administrator.
2. In Control Panel, click System and Security, and then click Administrative Tools.
3. Right-click Internet Information Services (IIS) Manager, and then click Run as administrator.
4. In the User Account Control dialog box, in the Password box, type Pa$$w0rd, and then press
ENTER.
5. Open the Search Engine Optimization feature.
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.

 Task 2: Modify the robots.txt file to include the sitemap


1. Select the Default Web site.
2. Open the Search Engine Optimization feature.
3. Add a new allow rule for the default website and Sitemap.xml file.
4. Close Internet Information Services (IIS) Manager.
5. Close Administrative Tools.
6. 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. Add Navigation Controls to the web application.
2. Use the FindControl function to locate a control.

 Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorks solution at the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 06\Starter\Exercise 03

Visual Basic D:\Lab Files\VB\Lab 06\Starter\Exercise 03

 Task 2: Add Navigation Controls to the web application


1. Create a Web.sitemap file in the root directory of the website.
2. 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. Save and close the Web.sitemap file.


4. Open the Site.Master master page.
5. 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. Save and close the Site.Master file.


8. Run the application.
Designing for Discoverability 6-51

9. Close Internet Explorer.

 Task 3: Use the FindControl function to locate a control


1. Open the Site.Master code-behind file.
2. 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. Place Breakpoint on the new line of code.


4. Debug the application.
5. Single-step over the selected line of code.
6. 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. Stop debugging.
8. Close Visual Studio 2010.

 Task 4: Turn off the virtual machine and revert the changes
1. In Microsoft Hyper-V™ Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and
then click Turn Off.
2. In the Turn Off Machine dialog box, click Turn Off.
3. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click
Revert.
4. 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. What can every developer do to ensure future content is properly indexed by search engines?
2. What can developers do to gauge the level of optimization for legacy websites?
3. What can developers do to ensure that new content is indexed by search engines?
4. What can developers do to prevent unwanted content from being indexed by search engines?
5. 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 Troubleshooting tip

Low Page Ranks Valid HTML, Descriptive HTML, Descriptive URLs, Descriptive Meta
Data

Unindexed Content Sitemap File

Unwanted Content Indexed Robots File

Unoptimized Website IIS SEO Toolkit

Real-world Issues and Scenarios


1. Website does not appear in results of relevant search engine queries.
2. New content does not appear in results of relevant search engine queries.
6-54 Developing Web Applications with Microsoft® Visual Studio® 2010

3. Unintended content appears in results of relevant search engine queries.


4. 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 Use for Where to find it

Visual Studio 2010 HTML Intellisense http://go.microsoft.com/fwlink/?LinkID=203985&clcid=0x409

IIS SEO Toolkit Site Analysis 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 7-3
Lesson 2: Controlling View State 7-10
Lesson 3: Localizing a Web Application 7-16
Lesson 4: Persisting Data on a Web Forms Page 7-27
Lesson 5: Validating User Input 7-33
Lab 7: Writing Server-Side Code for Web Forms 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 Description

App_Browsers 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.

App_Data 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.

App_GlobalResources 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.

App_LocalResources Contains resources (.resx and .resources files) that are associated with a
specific page, user control, or master page in an application.
Writing Server-Side Code for Web Forms 7-5

Folder Description

App_Themes 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.

App_WebReferences 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.

Bin 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.

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 Description

.aspx An ASP.NET Web Forms file (page) that can contain web controls and presentation
and business logic.

.ascx A web user control file that defines a custom, reusable control.

.ashx A generic handler file.

.config A configuration file (typically Web.config) that contains XML elements that
represent settings for ASP.NET features.

.master A master page that defines the layout for other web pages in the application.

.svc A WCF service file.

.asmx An XML web services file that contains classes and methods that are available to
other web applications by way of SOAP.

.axd A handler file used to manage website administration requests, typically Trace.axd.

.resx A resource file that contains resource strings that refer to images, localizable text, or
other data.

.cs or .vb Class source-code file that is compiled at run time.

Global.asax 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 don’t 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. Open the .aspx or .ascx file for which you want to generate a resource file for, in Design mode.
2. 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 isn’t, 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.
• 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 Localization solution from the following location.

Programming Language Location

Visual C#® D:\Demofiles\CS

Visual Basic® D:\Demofiles\VB

a. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project, or
press CTRL+SHIFT+O.
b. 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.
3. Open Default.aspx.
• In Solution Explorer, double-click Default.aspx.
4. Add a Label server control after the h2 element, with the following attributes.

Attribute Value

ID HelloLabel

Text Hello in English

a. Place the cursor after the h2 element.


Writing Server-Side Code for Web Forms 7-23

b. Open the Toolbox, expand Standard, and then double-click Label.


<asp:Label ID="HelloLabel" runat="server" Text="Hello in English"></asp:Label>

5. 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. Notice the newly added attributes, meta:resourcekey, for both the page and the Label server
control.
9. 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. On the File menu, click Save App_LocalResources\Default.aspx.resx, or press CTRL+S.
b. 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. In Solution Explorer, in the App_LocalResources folder, right-click Default.aspx.resx, and then
click Copy.
b. In Solution Explorer, right-click App_LocalResources, and then click Paste.
c. In Solution Explorer, in the App_LocalResources folder, right-click Copy of Default.aspx.resx,
and then click Rename.
d. 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. On the File menu, click Save App_LocalResources\Default.aspx.de.resx, or press CTRL+S.
b. 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 Value

ID HeaderText

meta:resourcekey HeaderText

a. Place the cursor within the h2 element, just before the text Localization.
b. Open the Toolbox, expand Standard, and then double-click Localize.
c. 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. Place the cursor after the HelloLabel element.
b. Type the following text and then press ENTER.
<br/><br/>

c. Open the Toolbox, expand Standard, and then double-click Literal.


d. 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. In Solution Explorer, right-click Localization, point to Add, point to Add ASP.NET Folder, and
then click App_GlobalResources.
b. In Solution Explorer, right-click App_GlobalResources, point to Add, and then click New Item.
c. 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. On the File menu, click Save App_GlobalResources\WebResources.resx, or press CTRL+S.
b. 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. In Solution Explorer, in the App_GlobalResources folder, right-click WebResources.resx, and
then click Copy.
b. In Solution Explorer, right-click App_GlobalResources, and then click Paste.
c. In Solution Explorer, in the App_LocalResources folder, right-click Copy of WebResources.resx,
and then click Rename.
d. 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 Fußzeile....
• In the Resource Editor, in the row with a value in the Name column of FooterText, in the Value
box, type Dies ist der Fußzeile....
30. Save and close the resource file.
a. On the File menu, click Save App_GlobalResources\WebResources.de.resx, or press CTRL+S.
b. 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. Place the cursor after the DescriptionLiteral element.
b. Type the following text and the press ENTER.
<h3></h3>

c. Place the cursor between the opening and closing h3 tags.


d. Open the Toolbox, expand Standard, and then double-click Label.
e. 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. In the Home Page - Windows Internet Explorer window, on the Tools menu, click Internet
Options.
b. In the Internet Options dialog box, click Languages.
c. In the Language Preference dialog box, click Add.
d. In the Add Language dialog box, in the Language list, click German (Germany) [de-DE], and
then click OK.
e. In the Language Preference dialog box, in the Language list, click German (Germany) [de-
DE], 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 doesn’t
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 validation—when 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 client-
side 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/en-
us/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 customer’s 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. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd.
2. 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.
3. Open the AdventureWorks solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 07\Starter\Exercise 01

Visual Basic D:\Lab Files\VB\Lab 07\Starter\Exercise 01

 Task 2: Create resource files for Default.aspx


1. Analyze the markup in Default.aspx.
2. 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. Switch back to Source view of Default.aspx.


4. 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. Notice that the Page directive at the top of the page now contains the following information.
<%@ Page ... culture="auto" meta:resourcekey="PageResource1" uiculture="auto" %>

6. 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.
9. Localize the hard-coded Welcome to AdventureWorks! text implicitly, by adding a Localize server
control within the h2 element, with the following attributes.

Attribute Value

ID lclWelcome

Text Welcome to AdventureWorks!

meta:resourcekey LocalizeResource1

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 Value

ID ProductCategoriesLiteral

Text <%$ 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. Open the Site.Master master page.
2. 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 Value

ID LoginLiteral

Text Log In
3. Delete the text Log In from the a element.

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 Value

ID WelcomeLiteral

Text Welcome
5. 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. Open the Site.Master master page in Design view.


7. 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. Run the application.
2. 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. Close Internet Explorer.


4. Close Visual Studio 2010.

Results: After this exercise, you should have a web application that supports different languages, and
shows the site in the user’s 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. Use a cookie collection to persist user information, setting scope and lifetime to save the last chosen
category.
2. Store system-wide information in the Application object, to hold the number of simultaneous visitors
on the site.
3. Use the session object to store the shopping cart.
4. Configure session state to run in SQL Server.

 Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorks solution from the following location.

Programming
Language Location

Visual C# D:\Lab Files\CS\Lab 07\Starter\Exercise 02

Visual Basic 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. Open the Default.aspx Web Form in Code view.
2. 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. Open Global.asax in Code view.
2. 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. Open the ProductDetails Web Form in Code view.
2. 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. Open the ShoppingCart Web Form in Code view.


4. Analyze the code in the Page_Load method.

 Task 5: Configure session state to run in SQL Server


1. Open the Web.config file.
2. 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.
6. Close the SQL Server Command Line Tool, by running the following command from the Visual
Studio Command Prompt (2010).
quit

7. Close the Visual Studio Command Prompt (2010).


8. 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. Configure the view state to persist page data.
2. Disable the view state and its effects.

 Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorks solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 07\Starter\Exercise 03

Visual Basic D:\Lab Files\VB\Lab 07\Starter\Exercise 03

 Task 2: Configure view state to persist page data


1. Run the application.
2. View the source of the Default.aspx page in Internet Explorer, by using the View Source
functionality.
3. Analyze the HTML code, and pay special attention to the __VIEWSTATE field.
4. Close the View Source window.
5. Close Internet Explorer.
6. Open the Default.aspx Web Form.
7. 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. Run the application.


9. 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. Run the application.


3. Click Submit.

Note: The lbCategories server control is now empty because it is not being populated by the
server code on a postback.

4. Close Internet Explorer.


5. 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. Run the application.


7. 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. Close Internet Explorer.


9. 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. Add credit card fields to the check-out page.
2. Add and configure a RequiredFieldValidator control for the txtCreditCard control.
3. Add and configure a RegularExpressionValidator control for the credit card field.

 Task 1: Open the AdventureWorks solution in Visual Studio 2010


1. Open Microsoft Visual Studio 2010.
2. Open the AdventureWorks solution from the following location.

Programming Language Location

Visual C# D:\Lab Files\CS\Lab 07\Starter\Exercise 04

Visual Basic D:\Lab Files\VB\Lab 07\Starter\Exercise 04

 Task 2: Add credit card fields to the check-out page


1. Open the ShoppingCart.aspx Web Form.
2. 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. ControlToValidate = txtCreditCard
b. ErrorMessage = Please enter a valid credit card number.
c. Text = *
d. 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][0-
9]{13})$">
</asp:RegularExpressionValidator>

3. Open the ShoppingCart Web Form in Code view.


4. 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. Run the application.


6. Select Bib-Shorts on the Product Categories list, and click Submit.
7. On the Products page, click Men's Bib-Shorts, L.
8. On the Men's Bib-Shorts, L page, click Order.
9. 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. In Microsoft Hyper-V™ Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and
then click Turn Off.
2. In the Turn Off Machine dialog box, click Turn Off.
3. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click
Revert.
4. 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. What are the names of the two ASP.NET folders used for resources?
2. How is control state different from view state?
3. What is the default location for resource (.resx) files .resx, when a web application is built?
4. 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.
2. 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?

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 8-3
Lesson 2: Using Data Source Controls 8-18
Lesson 3: Using ASP.NET Dynamic Data 8-62
Lab 8A: Optimizing Data Management for Web Forms 8-38
Lab 8B: Optimizing Data Management for Web Forms 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.
• 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 EDM solution from the D:\Demofiles\VB or D:\Demofiles\CS folder.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project.
b. 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. In Solution Explorer, right-click EDM, point to Add, and then click New Item.
b. 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.
c. In the Name box, type AdventureWorks.edmx, and then click Add.
d. In the Entity Data Model Wizard, on the Choose Model Contents page, click Generate from
database, and then click Next.
e. On the Choose Your Data Connection page, click New Connection.
f. If the Choose Data Source dialog box opens, in the Data source list, click Microsoft SQL
Server, and then click Continue.
g. In the Connection Properties dialog box, in the Server name box, type 10264A-GEN-
DEV\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. 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.
i. 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. Review the entity properties.


k. 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. In the AdventureWorks.edmx window, click and possibly expand the Mapping Details -
Customer window.
b. Under Column Mappings, in particular, observe how the NameStyle SQL Server bit column
is mapped to a .NET Framework Boolean/bool data type.
15. Close the ADO.NET Entity Data Model item.
• In the AdventureWorks.edmx window, click the Close button.
16. Close Visual Studio 2010.
a. In the EDM – Microsoft Visual Studio window, click the Close button.
b. 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"

Try
' Submit changes
adventureWorksObjectContext.SaveChanges()
Catch ex As Exception
Response.Write(ex.Message & "<br/>" & ex.InnerException.Message)
End Try
End Using

[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
{
// Submit changes
adventureWorksObjectContext.SaveChanges();
}
catch (Exception ex)
{
Response.Write(ex.Message + "<br/>" + ex.InnerException.Message);
}
}

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 framework—since 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 Description

AccessDataSource 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.

EntityDataSource 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.

LinqDataSource 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.

ObjectDataSource 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.
8-20 Developing Web Applications with Microsoft® Visual Studio® 2010

Data Source control Description

SiteMapDataSource Used with ASP.NET site navigation for databinding controls.

SqlDataSource 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.

XmlDataSource 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.
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, two-
way 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 Description

FirstPageImageUrl Sets the URL to an image to display for the first-page button.

FirstPageText Sets the text to display for the first-page button.

LastPageImageUrl Sets the URL to an image to display for the last-page button.

LastPageText Sets the text to display for the last-page button.

Mode 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.

NextPageImageUrl Sets the URL to an image to display for the next-page button.

NextPageText Sets the text to display for the next-page button.

PageButtonCount Sets the number of page buttons to display in the pager when the
Mode property is set to the Numeric or NumericFirstLast value.

Position Sets a value that specifies the location where the pager is displayed in
the GridView control. The valid values are: Bottom, Top,
TopAndBottom.

PreviousPageImageUrl Sets the URL to an image to display for the previous-page button.

PreviousPageText Sets the text to display for the previous-page button.

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. When in Design view, you first select the GridView control for which you want to create the
TemplateField object(s).
2. With the GridView control selected, click the Smart Tag button, and then in the GridView Tasks
dialog box, click Edit Columns.
3. 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.
4. 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 Right-click the Chart control in the design area, and then click Properties.
2 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:
Property Value

ChartArea ChartArea2

ChartType Bar

Name BarChart

d. Click OK, and then click OK again.


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 Value

DockedToChartArea ChartArea1

Docking Right

IsDockedInsideChartArea False

b. Click Add again, and then set the following properties with the newly created Legend object:

Property Value

DockedToChartArea ChartArea2

Docking Right

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. Open the Series Collection editor again.


e. 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. In the Legend Collection editor, click Add.


b. 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. Log on to the 10264A-GEN-DEV virtual machine as Student, with the password, Pa$$w0rd.

2. Open Microsoft Visual Studio 2010.

3. 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. Save and close the ADO.NET Entity Data Model item.

3. Build the project and fix any errors.

4. 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. Create a Shopping Cart Quantity user control.

2. Modify the ShoppingCart entity class.

3. Convert a BoundField column to TemplateField.

4. Add Computed column to the GridView control.

5. Make GridView updatable.

6. Add user control to TemplateField

7. Implement GridView paging.

8. Test the GridView control.

 Task 1: Open an existing ASP.NET web application


1. Open Microsoft Visual Studio 2010.

2. 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. Create a new user control named Quantity.ascx.

2. 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. Save and close the user control.

6. 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. Open the ShoppingCart.vb class file.

2. 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. Save and close the ShoppingCart entity class.

7. Build the project and fix any errors.

 Task 4: Convert a BoundField column to TemplateField


1. Open the ShoppingCart.aspx content page in Design view.

2. Select the gvCart GridView control.

3. Open the Fields dialog box for the GridView control, by using the Smart Tag.

4. 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. Set the AutoGenerateEditButton property to a value of True.


c. Add an event handler for the RowCancelingEdit event.
d. Add an event handler for the RowEditing event.
e. Add an event handler for the RowUpdating event.
f. 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. Save and close the ShoppingCart code-behind file.


q. 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. Copy the Text attribute and value from the TextBox1 control to the Quantity1 control.
<uc1:Quantity ID="Quantity1" runat="server" Text='<%# Bind("Quantity") %>' />

c. Delete the TextBox1 control.


d. Make the ProductId BoundField control read-only.
e. Format the display of the ListPrice BoundField control using the DataFormatString attribute
and a value of {0:c}.
f. 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.
b. 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. Save and close the ShoppingCart files.


e. Build the project and fix any errors.

 Task 9: Test the GridView control


• Run the application.
a. On the Home page, in the Product Categories list, click Bike Stands, and then click Submit.
b. On the Products page, in the Bike Stands list, click All-Purpose Bike Stand.
c. On the Product Detail page, click Order.
d. On the Shopping Cart page, click Edit.
e. In the Quantity box, type 5, and then click Update.

Note: Observe how the Quantity and Total Price columns are updated.

f. On the Shopping Cart page, click Continue Shopping.


g. On the Home page, in the Product Categories list, click Cranksets, and then click Submit.
h. On the Products page, in the Cranksets list, click HL Crankset.
i. 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. On the Shopping Cart page, in the GridView pager, click 2.


k. Close Windows® Internet Explorer®.
l. 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. Create the Sales Orders Master Details view.

2. Test the Master Details view.

3. Create the Sales Order Items History dashboard.

4. 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. Open the SalesOrders.aspx content page in Design view.
b. Place the cursor in the HTML p element at the bottom of the MainContent Content control.
c. Add a ListView control named SalesOrdersListView to the p element.
d. Add a new LinqDataSource control, by using the SalesOrdersListView Smart Tag.
e. Use LINQ as the data source, and name the LinqDataSource control
SalesOrdersLinqDataSource, by using the Data Source Configuration Wizard.
f. Select the AdventureWorks.AdventureWorks2008LTEntities object context using the existing
Entity Data Model as the object context for the LinqDataSource control.
g. Select the SalesOrderHeaders table and include the SalesOrderID, OrderDate, DueDate,
ShipDate and CustomerID fields for the LinqDataSource control.
h. Select only sales orders that have already shipped, by specifying a where clause, and compare
ShipDate with the DateTime.Now method.
i. Order the sales orders by CustomerID and ShipDate, by specifying an Order By clause.
j. Finish the Data Source Configuration Wizard.
k. Set the SalesOrderID field as the DataKeyNames property value.
l. Open the SalesOrders.aspx web form in Source view.
m. Remove the WhereParameters element from the LinqDataSource control.
<WhereParameters>
<asp:Parameter DefaultValue="DateTime.Now" Name="ShipDate" Type="DateTime" />
</WhereParameters>

n. Modify the Where property to appear as follows.


Where="ShipDate &lt;= DateTime.Now"

o. Open the SalesOrders.aspx web form in Design view.


p. Configure the SalesOrdersListView control, by using the SalesOrdersListView Smart Tag.
Refresh the schema before configuring the control.
q. Select the Grid layout and the Professional style for the SalesOrdersListView control.
Optimizing Data Management for Web Forms 8-47

r. Enable paging for the SalesOrdersListView control.


s. Disable editing and inserting a SalesOrderHeader item in the SalesOrdersListView control, by
deleting the corresponding templates in Source view.
t. 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. On the Sales Orders page, click Select for any item in the ListView control.
b. The DetailsView containing the Sales Order Details is displayed below the ListView control.
c. 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. Open the SalesOrderItemsHistory.aspx content page in Design view.


c. Add a Chart control named SalesOrderItemsHistoryChart.
d. Set the Chart type to Bar by using the Smart Tag.
e. 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.
f. 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.

 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. Close Internet Explorer.


b. 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. In the Turn Off Machine dialog box, click Turn Off.
b. 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. Close the ADO.NET Entity Data Model item.
b. Build the project and fix any errors.
c. 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. Create a Shopping Cart Quantity user control.

2. Modify the ShoppingCart entity class.

3. Convert a BoundField column to TemplateField.

4. Add Computed Column to the GridView control.

5. Make GridView updatable.

6. Add user control to TemplateField.

7. Implement GridView paging.

8. 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. Add a TextBox control named QuantityTextBox to the user control.
<asp:TextBox ID="QuantityTextBox" runat="server"></asp:TextBox>

b. 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>

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. Save and close the user control.


e. 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. Add a private member variable named productQuantity of type int to the ShoppingCart class.
private int productQuantity;

b. Modify the auto-implemented Quantity property, to get and set the productQuantity member
variable.
public int Quantity
{
get
{
return productQuantity;
}
set
{
productQuantity = value;
}
}

c. Add an auto-implemented TotalPrice property, of type decimal.


public decimal TotalPrice { get; set; }

d. Update the TotalPrice property, when the Quantity property is set.


TotalPrice = productQuantity * ListPrice;

e. Save and close the ShoppingCart entity class.


f. Build the project and fix any errors.

 Task 4: Convert a BoundField column to TemplateField


• Open the ShoppingCart.aspx content page in Design view.
a. Select the gvCart GridView control.
b. Open the Fields dialog box for the GridView control, by using the Smart Tag.
c. 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.
b. Set the AutoGenerateEditButton property to a value of True.
c. Add an event handler for the RowCancelingEdit event.
d. Add an event handler for the RowEditing event.
Optimizing Data Management for Web Forms 8-53

e. Add an event handler for the RowUpdating event.


f. 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. Save and close the ShoppingCart code-behind file.


q. 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. Copy the Text attribute and value from the TextBox1 control to the Quantity1 control.
<uc1:Quantity ID="Quantity1" runat="server" Text='<%# Bind("Quantity") %>' />

d. Delete the TextBox1 control.


<asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("Quantity")
%>'></asp:TextBox>

e. Make the ProductId BoundField control read-only.


ReadOnly="true"

f. Format the display of the ListPrice BoundField control using the DataFormatString attribute
and a value of {0:c}.
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. Add an event handler for the PageIndexChanging event.


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 (((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. Save and close the ShoppingCart files.


e. Build the project and fix any errors.

 Task 9: Test GridView control


• Run the application.
a. On the Home page, in the Product Categories list, click Bike Stands, and then click Submit.
b. On the Products page, in the Bike Stands list, click All-Purpose Bike Stand.
c. On the Product Detail page, click Order.
d. On the Shopping Cart page, click Edit.
e. In the Quantity box, type 5, and then click Update.

Note: Observe how the Quantity and Total Price columns are updated.

f. On the Shopping Cart page, click Continue Shopping.


g. On the Home page, in the Product Categories list, click Cranksets, and then click Submit.
h. On the Products page, in the Cranksets list, click HL Crankset.
i. 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. Close Windows® Internet Explorer®.


l. 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. Create the Sales Orders Master Details view.

2. Test the Master Details view.

3. Create the Sales Order Items History dashboard.

4. 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. Open the SalesOrders.aspx content page in Design view.
b. Select the HTML p element at the bottom of the MainContent Content control.
c. Add a ListView control named SalesOrdersListView to the p element.
d. Add a new LinqDataSource control, by using the SalesOrdersListView Smart Tag.
e. Use LINQ as the data source, and name the LinqDataSource control
SalesOrdersLinqDataSource, by using the Data Source Configuration Wizard.
f. Select the AdventureWorks.AdventureWorksLT2008Entities object context from the existing
Entity Data Model as the object context for the LinqDataSource control.
g. Select the SalesOrderHeaders table and include the SalesOrderID, OrderDate, DueDate,
ShipDate and CustomerID fields for the LinqDataSource control.
h. Select only sales orders that have already shipped, by specifying a where clause, and compare
ShipDate with the DateTime.Now method.
i. Order the sales orders by CustomerID and ShipDate, by specifying an Order By clause.
j. Finish the Data Source Configuration Wizard.
k. Set the SalesOrderID field as the DataKeyNames property value.
l. Open the SalesOrders.aspx web form in Source view.
m. Remove the WhereParameters element from the LinqDataSource control.
<WhereParameters>
<asp:Parameter DefaultValue="DateTime.Now" Name="ShipDate" Type="DateTime" />
</WhereParameters>

n. Modify the Where property to appear as follows.


Where="ShipDate &lt;= DateTime.Now"

o. Open the SalesOrders.aspx web form in Design view.


p. Configure the SalesOrdersListView control, by using the SalesOrdersListView Smart Tag.
Refresh the schema before configuring the control.
q. Select the Grid layout and the Professional style for the SalesOrdersListView control.
8-58 Developing Web Applications with Microsoft® Visual Studio® 2010

r. Enable paging for the SalesOrdersListView control.


s. Disable editing and inserting a SalesOrderHeader item in the SalesOrdersListView control, by
deleting the corresponding templates.
t. 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. On the Shopping Cart page, click Select, for any item in the ListView control.
b. The DetailsView containing the Sales Order Details is displayed below the ListView control.
c. 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. Open the SalesOrderItemsHistory.aspx content page in Design view.


c. Add a Chart control named SalesOrderItemsHistoryChart.
d. Set the Chart type to Bar by using the Smart Tag.
e. 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.
f. 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.

 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. Close Internet Explorer.


b. 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. In the Turn Off Machine dialog box, click Turn Off.
b. 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 data-
context 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.
• 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 web application by using the New Project dialog box.
a. On the File menu, click New Project.
b. In the New Project dialog box, in the left pane, click Visual Basic or Visual C#.
c. In the middle pane, click ASP.NET Dynamic Data Entities Web Application.
d. 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. In Solution Explorer, right-click DDWebApp, point to Add, and then click New Item.
b. 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.
c. In the Name box, type AdventureWorks.edmx, and then click Add.
4. In the Entity Data Model Wizard, on the Choose Model Contents page, click Generate from
database, and then click Next.
5. 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-GEN-
DEV\SQLEXPRESS, in the Select or enter a database name box, type AdventureWorksLT2008R2,
and then click OK.
7. In the Entity Data Model Wizard, on the Choose Your Data Connection page, click Next.
8. 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.
9. Save and close the AdventureWorks.edmx file.
a. On the File menu of Visual Studio 2010, click Save AdventureWorks.edmx.
b. In the AdventureWorks.edmx window, click the Close button.
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. On the File menu of Visual Studio 2010, click Save Global.asax.vb or Save Global.asax.cs.
b. 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. In the Address list, click All.
f. In the CustomerAddresses - Windows Internet Explorer window, at the end of the page, click
Insert new item to create a new customer address.
g. 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. Create a new ASP.NET Dynamic Data web application.

2. Add a new ADO.NET Entity Data Model.

3. Register the object context.

4. 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.
b. Save and close the AWEDM.edmx file.

 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. The page displayed in the browser displays a list of the tables you added to the data model.
b. View the Customers page, showing all customers.
c. The page displays the List view that contains the data from the Customers table.
d. View the Details view, for a customer.
e. The page displays the Details view that contains the data for the selected row from the
Customers table.
f. View the Customers page, showing all customers, by clicking Show all items.
g. Sort the customers by the LastName column.
h. The page displays the List view that contains the data of customers, sorted by last name.
i. 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. The page displays the List view that contains the data of customer sales order headers.
k. Filter the sales order headers by entries that have the OnlineOrderFlag column set to True.
l. 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. Create a new customer, by clicking Insert new item.
o. Save the new customer, with empty fields, and then cancel the new customer.
p. 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.
q. Edit the last customer displayed.
r. The page displays the Edit view that contains the data for the selected row from the Customers
table.
s. Cancel the edit and close Windows Internet Explorer.
t. 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. In the Turn Off Machine dialog box, click Turn Off.
b. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then
click Revert.
c. 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. Create a new ASP.NET Dynamic Data web application.

2. Add a new ADO.NET Entity Data Model.

3. Register the object context.

4. 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. Open Microsoft Visual Studio 2010.
b. 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.
b. Save and close the AWEDM.edmx file.

 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. The page displayed in the browser displays a list of the tables you added to the data model.
b. View the Customers page, showing all customers.
c. The page displays the List view that contains the data from the Customers table.
d. View the Details view, for a customer.
e. The page displays the Details view that contains the data for the selected row from the
Customers table.
f. View the Customers page, showing all customers, by clicking Show all items.
8-84 Developing Web Applications with Microsoft® Visual Studio® 2010

g. Sort the customers by the LastName column.


h. The page displays the List view that contains the data of customers, sorted by last name.
i. View the sales order headers associated with the second customer displayed from the top.
j. The page displays the List view that contains the data of customer sales order headers.
k. Filter the sales order headers by entries that have the OnlineOrderFlag column set to True.
l. 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. Create a new customer, by clicking Insert new item.
o. Save the new customer, with empty fields, and then cancel the new customer.
p. 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.
q. Edit the last customer displayed.
r. The page displays the Edit view that contains the data for the selected row from the Customers
table.
s. Cancel the edit and close Windows Internet Explorer.
t. 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. In the Turn Off Machine dialog box, click Turn Off.
b. In Hyper-V Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then
click Revert.
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-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.
2. 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.

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 9-3
Lesson 2: Unit Testing Code 9-22
Lesson 3: Processing Unhandled Exceptions 9-30
Lesson 4: Test-Driven Development 9-37
Lab 9: Debugging, Unit Testing and Refactoring 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. In Solution Explorer, right-click the name of your web application, and then click Property Pages.
2. In the Project Designer, click Web.
3. In the Project Designer, on the Web page, in the Debuggers area, select the ASP.NET check box.
4. In Solution Explorer, double-click Web.config.
5. 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.
• 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 web application by using the New Project dialog box.
a. On the File menu, click New Project.
b. In the New Project dialog box, in the left pane, click Visual Basic or Visual C#.
c. In the middle pane, click ASP.NET Web Application.
d. 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.
4. Open the Web.config file.
• In Solution Explorer, double-click Web.config.
5. Navigate to the self-closing system.web element and notice the attributes and values in the
compilation tag.
6. In Solution Explorer, right-click DebugWebApp, and then click Properties.
7. Open the Web page.
• In the Properties Designer, click Web.
8. Examine the various options on the Web page.
9. 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.
• 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 DebugWebApp solution from the D:\Demofiles\CS\DebugWebApp folder.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project.
b. In the Open Project dialog box, in the File name box, type
D:\Demofiles\CS\DebugWebApp\DebugWebApp.sln, and then click Open.
3. Open Default.aspx in Code view.
• In Solution Explorer, right-click Default.aspx and then click View Code.
4. 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. Select the three lines of code you just added.


6. Right-click the selection, point to Refactor, and then click Extract Method.
7. 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.
• 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 DebugWebApp solution from the D:\Demofiles\CS\DebugWebApp folder.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project.
b. In the Open Project dialog box, in the File name box, type
D:\Demofiles\CS\DebugWebApp\DebugWebApp.sln, and then click Open.
3. In Solution Explorer, right-click DebugWebApp, point to Add, and then click Class.
4. In the Add New Item – DebugWebApp dialog box, in the Name box, type Person, and then click
Add.
5. Create a single private variable named name, by adding the following code
[Visual C#]
public class Person
{
private string name;
}

6. In the Person.cs window, right-click name, point to Refactor, and then click Encapsulate Field.
7. In the Encapsulate Field dialog box, click OK.
8. 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.
• 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 DebugWebApp solution from the D:\Demofiles\CS\DebugWebApp folder.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project.
b. In the Open Project dialog box, in the File name box, type
D:\Demofiles\CS\DebugWebApp\DebugWebApp.sln, and then click Open.
3. Open the Person.cs file.
• In Solution Explorer, double-click Person.cs.
4. 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. Right-click Person, point to Refactor, and then click Extract Interface.


6. 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
don’t 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 right-
clicking 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.
• 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 UnitTest solution from the D:\Demofiles\CS or D:\Demofiles\VB folder.
a. In the Start Page – Microsoft Visual Studio window, on the File menu, click Open Project.
b. 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.
4. Modify the Age property as follows:
[Visual C#]
public int Age
{
get { return personAge; }
set
{
if (value < 21)
throw new Exception("Age must be greater than 21");

personAge = value;
}
}

[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. Right-click anywhere in the code for the Age property, and then click Create Unit Tests.
6. In the Create Unit Tests dialog box, ensure the Age check box is selected, and then click OK.
7. In the New Test Project dialog box, click Create.

Note: Notice the new project created for unit testing.

8. In the open PersonTest.cs or PersonTest.vb file, review the AgeTest test method.
9. 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 site’s 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 HTTP-
based 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 steps—one 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 test-
driven 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. Create the test code. Use an automated test framework to create the test code. The test code drives
the development of functionality.
2. 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.
3. Create additional tests. Develop additional tests to test the functional code.
4. 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.
5. 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.

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. Open Microsoft Visual Studio 2010.
2. 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. Add a new Web Form named CustomErrorPage.
2. Add the text CUSTOM ERROR PAGE to the CustomErrorPage Web Form.
3. Save the AdventureWorks project.
4. Close the CustomErrorPage Web Form.

 Task 3: Modify Web.config to redirect to the generic error page when an unhandled
error occurs
1. Open the Web.config file.
2. Add the following markup to the system.web element.
<customErrors mode="On" defaultRedirect="~/CustomErrorPage.aspx"/>

3. Save and close the Web.config file.


4. Run the application.
5. Click the Submit button.

Note: The custom error page is displayed.

6. Close Windows® Internet Explorer®.


7. 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. Open Microsoft Visual Studio 2010.
2. 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. Set Default.aspx as the project start page.
2. 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. Hover the mouse over category and notice it is an empty string, which cannot be parsed by the code
in the Products page.
8. Press SHIFT+F5 to end debugging.
9. 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. In the Message from webpage message box, click OK three times.


3. 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. Press F10 to step over the statements of code, until a message box is displayed.
7. In the Message from webpage message box, click OK.
8. Repeat the previous two steps twice.
9. 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. Open Microsoft Visual Studio 2010.
2. 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. Open Products.aspx in Code view.
2. 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

Try
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

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. Close the Event Viewer.


7. Close Windows Internet Explorer.

 Task 3: Set the logging level in the Web.config file to allow for future debugging
1. Open the Web.config file.
2. In the opening compilation tag, ensure that the value of the debug attribute is set to true.
<compilation debug="true" ...>

3. Close the Web.config file.

 Task 4: Create a generic error handler


1. Open the Global.asax file.
• In Solution Explorer, double-click Global.asax.
2. Import the System.Diagnostics namespace.
[Visual C#]
using System.Diagnostics;

[Visual Basic]
Imports System.Diagnostics

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. Open Microsoft Visual Studio 2010.
2. 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. Open the Calculator.cs or Calculator.vb file.
2. 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. Save Calculator.cs or Calculator.vb.


4. 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(); // TODO: Initialize to an appropriate value
int p1 = 2; // TODO: Initialize to an appropriate value
int p2 = 3; // TODO: Initialize to an appropriate value
int expected = 5; // TODO: Initialize to an appropriate value
int actual;
actual = target.Add(p1, p2);
Assert.AreEqual(expected, actual);
}

[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(); // TODO: Initialize to an appropriate value
int p1 = 2; // TODO: Initialize to an appropriate value
int p2 = 3; // TODO: Initialize to an appropriate value
int expected = 6; // TODO: Initialize to an appropriate value
int actual;
actual = target.Add(p1, p2);
Assert.AreEqual(expected, actual);
}

[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. Open Microsoft Visual Studio 2010.
2. 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. Open CalculatorTest.cs or CalculatorTest.vb file in the CalculatorTestProject project.
2. 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. Open the Calculator.cs or Calculator.vb file in the ClassLibrary project.
2. 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. Open the CalculatorTest.cs or CalculatorTest.vb file.
2. 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. Open CalculatorTest.cs or CalculatorTest.vb file in the CalculatorTestProject project.
2. 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. Close the CalculatorTest.cs or CalculatorTest.vb file.


5. Close Visual Studio 2010.

 Task 7: Turn off the virtual machine and revert the changes
1. In Hyper-V™ Manager, in the Virtual Machines pane, right-click 10264A-GEN-DEV, and then click
Turn Off.
2. In the Turn Off Machine dialog box, click Turn Off.
3. 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. Do you believe unit testing will decrease the time you spend debugging?
2. Have you ever broken code because of refactoring?
3. Do you dedicate cycles to refactoring code?
4. After applying a fix to an integrated module have you ever broken other modules?
5. How have existing tests provided you with the intent of the original developer?
6. What is the most helpful custom error page you’ve ever encountered? What features did it include?

Common Issues and Troubleshooting Tips Related to ASP.NET 4.0


Issue Troubleshooting tip

Security when writing to Error Log 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:
• Don’t make unnecessary assertions.
• Test only one code unit at a time.
• Mock out all external services and state.
• Avoid unnecessary preconditions.
• Don’t unit-test configuration settings.
• Name your unit tests clearly and consistently.

Tools
Tool Use for Where to find it

NUnit NUnit is an open source unit- http://go.microsoft.com/fwlink/


testing framework for all .NET ?LinkID=204073&clcid=0x409
languages.

NMock NMock is a dynamic mock object http://go.microsoft.com/fwlink/


library for .NET. Mock objects ?LinkID=204074&clcid=0x409
make it easier to test single
components—often single
classes—without relying on real
implementations of all of the
other components.

Das könnte Ihnen auch gefallen