Vous êtes sur la page 1sur 626

Programming the Microsoft .

NET Framework with C# (Prerelease)

Delivery Guide
Course Number: 2349A

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Part Number: X08-39992 Released: 07/2001

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

Course Number: 2349A Part Number: X08-39992 Released: 07/2001


BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Programming the Microsoft .NET Framework with C# (Prerelease)

iii

Contents
Introduction
Course Materials .................................................................................................. 2 Prerequisites......................................................................................................... 3 Course Outline ..................................................................................................... 4 Microsoft Certified Professional Program ........................................................... 8 Facilities............................................................................................................. 10

Module 1: Overview of the Microsoft .NET Framework


Overview.............................................................................................................. 1 Overview of the Microsoft .NET Framework...................................................... 2 Overview of Namespaces .................................................................................. 12 Review ............................................................................................................... 15

Module 2: Introduction to a Managed Execution Environment


Overview.............................................................................................................. 1 Writing a .NET Application................................................................................. 2 Compiling and Running a .NET Application..................................................... 10 Multimedia: Application Loading and Single-File Assembly Execution .......... 26 Lab 2: Building a Simple .NET Application...................................................... 28 Review ............................................................................................................... 31

Module 3: Working with Components


Overview.............................................................................................................. 1 An Introduction to Key .NET Framework Development Technologies .............. 2 Creating a Simple .NET Framework Component ................................................ 4 Lab 3.1: Creating a .NET Framework Component ............................................ 11 Creating a Simple Console Client...................................................................... 13 Lab 3.2: Creating a Simple Console-Based Client............................................. 18 Demonstration: Creating a Windows Forms Client ........................................... 21 Creating an ASP.NET Client ............................................................................. 25 Multimedia: ASP.NET Execution Model .......................................................... 26 Lab 3.3: Calling a Component Through an ASP.NET Page.............................. 34 Review ............................................................................................................... 38

Module 4: Deployment and Versioning


Overview.............................................................................................................. 1 Introduction to Application Deployment ............................................................. 2 Application Deployment Scenarios ..................................................................... 7 Related Topics and Tools................................................................................... 32 Lab 4: Packaging and Deployment .................................................................... 38 Review ............................................................................................................... 43

Module 5: Common Type System


Overview.............................................................................................................. 1 An Introduction to the Common Type System .................................................... 2 Elements of the Common Type System............................................................... 8 Object-Oriented Characteristics......................................................................... 26 Lab 5: Building Simple Types ........................................................................... 40 Review ............................................................................................................... 45

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Programming the Microsoft .NET Framework with C# (Prerelease)

Module 6: Working with Types


Overview.............................................................................................................. 1 System.Object Class Functionality ...................................................................... 2 Specialized Constructors.................................................................................... 12 Type Operations................................................................................................. 17 Interfaces............................................................................................................ 27 Managing External Types .................................................................................. 34 Lab 6: Working with Types ............................................................................... 37 Review ............................................................................................................... 42

Module 7: Strings, Arrays, and Collections


Overview.............................................................................................................. 1 Strings .................................................................................................................. 2 Terminology Collections................................................................................. 20 .NET Framework Arrays.................................................................................... 21 .NET Framework Collections ............................................................................ 39 Lab 7: Working with Strings, Enumerators, and Collections............................. 57 Review ............................................................................................................... 63

Module 8: Delegates and Events


Overview.............................................................................................................. 1 Delegates.............................................................................................................. 2 Demonstration: Using Delegates.......................................................................... 8 Multicast Delegates............................................................................................ 12 Demonstration: Multicast Delegates .................................................................. 19 Events................................................................................................................. 22 When to Use Delegates, Events, and Interfaces................................................. 30 Lab 8: Creating a Simple Chat Server................................................................ 31 Review ............................................................................................................... 40

Module 9: Memory and Resource Management


Overview.............................................................................................................. 1 Memory Management Basics............................................................................... 2 Multimedia: Simple Garbage Collection ........................................................... 10 Non-Memory Resource Management ................................................................ 12 Implicit Resource Management ......................................................................... 13 Multimedia: Garbage Collection........................................................................ 19 Explicit Resource Management ......................................................................... 26 Optimizing Garbage Collection ......................................................................... 36 Lab 9: Memory and Resource Management ...................................................... 49 Review ............................................................................................................... 55

Module 10: Data Streams and Files


Overview.............................................................................................................. 1 Streams................................................................................................................. 2 Readers and Writers............................................................................................. 4 Basic File I/O ....................................................................................................... 7 Lab 10: Files ...................................................................................................... 20 Review ............................................................................................................... 25

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Programming the Microsoft .NET Framework with C# (Prerelease)

Module 11: Internet Access


Overview.............................................................................................................. 1 Internet Application Scenarios............................................................................. 2 The WebRequest and WebResponse Model........................................................ 3 Application Protocols......................................................................................... 16 Handling Errors.................................................................................................. 25 Security .............................................................................................................. 28 Lab 11: Creating a DateTime Client/Server Application................................... 36 Review ............................................................................................................... 40

Module 12: Serialization


Overview.............................................................................................................. 1 Serialization Scenarios......................................................................................... 2 Serialization Attributes ........................................................................................ 4 Object Graph........................................................................................................ 5 Serialization Process ............................................................................................ 7 Serialization Example .......................................................................................... 9 Deserialization Example .................................................................................... 10 Custom Serialization.......................................................................................... 12 Custom Serialization Example........................................................................... 14 Security Issues ................................................................................................... 17 Lab 12: Serialization .......................................................................................... 18 Review ............................................................................................................... 27

Module 13: Remoting and Web Services


Overview.............................................................................................................. 1 Remoting.............................................................................................................. 2 Remoting Configuration Files............................................................................ 18 Lab 13.1: Building an Order-Processing Application by Using Remoted Servers...................................................................................... 27 Web Services ..................................................................................................... 35 Lab 13.2: Using a Web Service ......................................................................... 47 Review ............................................................................................................... 52

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Programming the Microsoft .NET Framework with C# (Prerelease)

vii

About This Course


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

Description
The goal of this course is to help application developers understand the Microsoft .NET Framework. In addition to offering an overview of the .NET Framework and an introduction to key concepts and terminology, the course provides a series of labs, which introduce and explain .NET Framework features that are used to code, debug, tune, and deploy applications.

Audience
This course is intended for experienced, professional software developers who work in independent software vendors or software companies or work on corporate enterprise development teams. Most students will be Microsoft Visual C++ (or C++) and Java developers.

Student Prerequisites
This course requires that students meet the following prerequisites:
!"

Students should be proficient in the C++ or Java programming languages and have been exposed to the C# language. Students can meet these prerequisites by taking Course 2124, Introduction to C# Programming for the Microsoft .NET Platform.

!"

Course Objectives
After completing this course, the student will be able to:
!"

List the major elements of the .NET Framework and explain how they fit into the .NET platform. Explain the main concepts behind the common language runtime and use the features of the .NET Framework to create a simple application. Create and use components in Windows Forms-based and ASP.NET-based applications. Use the deployment and versioning features of the .NET runtime to deploy multiple versions of a component. Create, use, and extend types by understanding the Common Type System architecture. Create classes and interfaces that are functionally efficient and appropriate for given programming scenarios. Use the .Net Framework class library to efficiently create and manage strings, arrays, collections, and enumerators. Use delegates and events to have an event sender object signal the occurrence of an action to an event receiver object. Describe and control how memory and other resources are managed in the .NET Framework.

!"

!"

!"

!"

!"

!"

!"

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

viii

Programming the Microsoft .NET Framework with C# (Prerelease)


!" !"

Read from and write to data streams and files. Use the basic request/response model to send and receive data over the Internet. Serialize and deserialize an object graph. Create distributed applications via Web Services and Object Remoting.

!" !"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Programming the Microsoft .NET Framework with C# (Prerelease)

ix

Course Timing
The following schedule is an estimate of the course timing. Your timing may vary.

Day 1
Start 9:00 9:30 10:00 10:15 11:00 11:15 11:45 12:00 1:00 1:15 1:30 2:00 2:30 2:45 End 9:30 10:00 10:15 11:00 11:15 11:45 12:00 1:00 1:15 1:30 2:00 2:30 2:45 4:15 Module Introduction Module 1: Overview of the Microsoft .NET Framework Break Module 2: Introduction to a Managed Execution Environment Lab 2: Building a Simple .NET Application Module 3: Working with Components Lab 3.1: Creating a .NET Framework Component Lunch Module 3: Working with Components (continued) Lab 3.2: Creating a Simple Console-Based Client Module 3: Working with Components (continued) Lab 3.3: Calling a Component Through an ASP .NET Page Break Module 4: Deployment and Versioning

Day 2
Start 9:00 9:50 10:00 11:30 12:30 1:15 2:30 2:45 3:30 End 9:50 10:00 11:30 12:30 1:15 2:30 2:45 3:30 4:00 Module Lab 4: Packaging and Deployment Break Module 5: Common Type System Lunch Lab 5: Building Simple Types Module 6: Working with Types Break Lab 6: Creating Classes Module 7: Strings, Arrays, and Collections

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Programming the Microsoft .NET Framework with C# (Prerelease)

Day 3
Start 9:00 10:30 10:45 11:45 12:45 2:00 2:15 3:25 End 10:30 10:45 11:45 12:45 2:00 2:15 3:25 4:00 Module Module 7: Strings, Arrays, and Collections (continued) Break Lab 7: Working with Strings, Enumerators, and Collections Lunch Module 8: Delegates and Events Break Lab 8: Creating a Simple Chat Server Module 9: Memory and Resource Management

Day 4
Start 9:00 10:30 10:45 11:45 12:45 1:30 2:15 2:30 3:30 End 10:30 10:45 11:45 12:45 1:30 2:15 2:30 3:30 4:15 Module Module 9: Memory and Resource Management (continued) Break Lab 9: Memory and Resource Management Lunch Module 10: Data Streams and Files Lab 10: Files Break Module 11: Internet Access Lab 11: Creating a DateTime Client/Server Application

Day 5
Start 9:00 9:30 10:15 10:30 11:30 12:30 1:20 2:20 2:35 End 9:30 10:15 10:30 11:30 12:30 1:20 2:20 2:35 3:25 Module Module 12: Serialization Lab 12: Serialization Break Module 13: Remoting and Web Services Lunch Lab 13.1: Building an Order-Processing Application by Using Remoted Servers Module 13: Remoting and Web Services (continued) Break Lab 13.2: Using a Web Service

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Programming the Microsoft .NET Framework with C# (Prerelease)

xi

Trainer Materials Compact Disc Contents


The Trainer Materials compact disc contains the following files and folders:
!"

Autorun.exe. When the CD is inserted into the CD-ROM drive, or when you double-click the autorun.exe file, this file opens the CD and allows you to browse the Student Materials or Trainer Materials CD, or install Internet Explorer. Default.htm. This file opens the Trainer Materials Web page. Readme.txt. This file contains a description of the compact disc contents and setup instructions in ASCII format (non-Microsoft Word document). 2349A_MS.doc. This file is the Classroom Setup Guide. It contains a description of classroom requirements, classroom configuration, and classroom setup instructions. StudentCD. This folder contains the Web page that provides students with links to resources pertaining to this course, including additional reading, review and lab answers, lab files, multimedia presentations, and courserelated Web sites. Errorlog. This folder contains a template that is used to record any errors and corrections that you find in the course. Fonts. This folder contains fonts that are required to view the Microsoft PowerPoint presentation and Web-based materials. Mplayer. This folder contains files that are required to install Microsoft Windows Media Player. Powerpnt. This folder contains the PowerPoint slides that are used in this course. Pptview. This folder contains the PowerPoint Viewer, which is used to display the PowerPoint slides. Webfiles. This folder contains the files that are required to view the course Web page. To open the Web page, open Windows Explorer, and in the root directory of the compact disc, double-click Default.htm or Autorun.exe.

!" !"

!"

!"

!"

!"

!"

!"

!"

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

xii

Programming the Microsoft .NET Framework with C# (Prerelease)

Student Materials Compact Disc Contents


The Student Materials compact disc contains the following files and folders:
!"

Autorun.exe. When the CD is inserted into the CD-ROM drive, or when you double-click the autorun.exe file, this file opens the CD and allows you to browse the Student Materials CD or install Internet Explorer. Default.htm. This file opens the Student Materials Web page. It provides you with resources pertaining to this course, including additional reading, review and lab answers, lab files, multimedia presentations, and courserelated Web sites. Readme.txt. This file contains a description of the compact disc contents and setup instructions in ASCII format (non-Microsoft Word document). 2349A_MS.doc. This file is the Classroom Setup Guide. It contains a description of classroom requirements, classroom setup instructions, and the classroom configuration. AddRead. This folder contains additional reading pertaining to this course. If there are no additional reading files, this folder does not appear. Appendix. This folder contains appendix files for this course. If there are no appendix files, this folder does not appear. Democode. This folder contains demonstration code. If there is no demonstration code, the Democode folder does not appear. Fonts. This folder contains fonts that are required to view the Microsoft PowerPoint presentation and Web-based materials. Labs. This folder contains files that are used in the hands-on labs. These files may be used to prepare the student computers for the hands-on labs. Media. This folder contains files that are used in multimedia presentations for this course. If this course does not include any multimedia presentations, this folder does not appear. Menu. This folder contains elements for autorun.exe. Mplayer. This folder contains files that are required to install Microsoft Windows Media Player. Practices. This folder contains files that are used in the hands-on practices. If there are no practices, the Practices folder does not appear. Sampapps. This folder contains the sample applications associated with this course. If there are no associated sample applications, the Sampapps folder does not appear. Sampcode. This folder contains sample code that is accessible through the Web pages on the Student Materials CD. If there is no sample code, the Sampcode folder does not appear. Sampsite. This folder contains files that create the sample site associated with this course. If there is no sample site, the Sampsite folder does not appear.

!"

!"

!"

!"

!"

!"

!"

!"

!"

!" !"

!"

!"

!"

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Programming the Microsoft .NET Framework with C# (Prerelease)


!"

xiii

Setup. This folder contains additional files that may be required for lab setup. If no additional files are required, the Setup folder does not appear. Webfiles. This folder contains the files that are required to view the course Web page. To open the Web page, open Windows Explorer, and in the root directory of the compact disc, double-click Default.htm or Autorun.exe. Wordview. This folder contains the Word Viewer that is used to view any Word document (.doc) files that are included on the compact disc. If no Word documents are included, this folder does not appear.

!"

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

xiv

Programming the Microsoft .NET Framework with C# (Prerelease)

Document Conventions
The following conventions are used in course materials to distinguish elements of the text.
Convention
#

Use Indicates an introductory page. This symbol appears next to a topic heading when additional information on the topic is covered on the page or pages that follow it. Represents commands, command options, and syntax that must be typed exactly as shown. It also indicates commands on menus and buttons, dialog box titles and options, and icon and menu names. In syntax statements or descriptive text, indicates argument names or placeholders for variable information. Italic is also used for introducing new terms, for book and course titles, and for emphasis in the text. Indicate domain names, user names, computer names, directory names, and folder and file names, except when specifically referring to case-sensitive names. Unless otherwise indicated, you can use lowercase letters when you type a directory name or file name in a dialog box or at a command prompt. Indicate the names of keys, key sequences, and key combinations for example, ALT+SPACEBAR. Represents code samples or examples of screen text. In syntax statements, enclose optional items. For example, [filename] in command syntax indicates that you can choose to type a file name with the command. Type only the information within the brackets, not the brackets themselves. In syntax statements, enclose required items. Type only the information within the braces, not the braces themselves. In syntax statements, separates an either/or choice. Indicates a procedure with sequential steps. In syntax statements, specifies that the preceding item may be repeated. Represents an omitted portion of a code sample.

bold

italic

Title Capitals

ALL CAPITALS monospace

[]

{}

!
... . . .

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

Contents Introduction Course Materials Prerequisites Course Outline Microsoft Certified Professional Program Facilities 1 2 3 4 8 10

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

iii

Instructor Notes
Presentation: 30 Minutes The Introduction module provides students with an overview of the course content, materials, and logistics for course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

Course Materials and Preparation


Required Materials
To teach this course, you need the following materials:
!" !"

Delivery Guide Trainer Materials compact disc

Preparation Tasks
To prepare for this course, you must: Complete the Course Preparation Checklist that is included with the trainer course materials.

Module Strategy
Use the following strategy to present this module:
!"

Course 2349A: Programming the Microsoft .NET Framework with C# (Prerelease) Show the slide that displays the course number and course title. Introduction Welcome students to the course and introduce yourself. Provide a brief overview of your background to establish credibility. Have students introduce themselves and provide their background, product experience, and expectations of the course. Record student expectations on a white board or flip chart that you can reference later in class.

!"

!"

Course Materials Explain the purpose of all materials used in this course. Prerequisites Provide the students with the list of prerequisites that they should have met before taking this course. This is an opportunity for you to identify students who may not have the appropriate background or experience to attend this course.

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Introduction
!"

Course Outline Provide an overview of each module and what students will learn. Explain how this course will meet students expectations by relating the information covered in individual modules to their expectations.

!"

Setup Provide the students with any necessary setup information for the course. Microsoft Official Curriculum Present an overview of the Microsoft Official Curriculum program and refer students to the Microsoft Official Curriculum Web page at http://www.microsoft.com/trainingandservices/

!"

!"

Microsoft Certified Professional Program Inform students about the Microsoft Certified Professional (MCP) program and the various certification options.

!"

Facilities Explain the facility information for the training site.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

Introduction
Topic Objective
To introduce yourself, establish credibility, meet students, and set student expectations for the course.
! ! ! ! ! ! !

Name Company Affiliation Title/Function Job Responsibility Programming Experience .NET Framework Experience Expectations for the Course

Lead-in
Good morning. Welcome to Course 2349A: Programming the Microsoft .NET Framework with C# (Prerelease). My name is...

Introduce yourself. Provide a brief overview of your background to establish credibility as a .NET Framework instructor. Ask students to introduce themselves, addressing the bulleted items on the slide.

Delivery Tip
As students introduce themselves, use a white board or flip chart to record their expectations of the course.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

Course Materials
Topic Objective
To identify and describe the course materials.
! ! ! !

Lead-in
We have provided everything you need for this course. You will find the following materials at your desk...

Name Card Student Workbook Student Materials Compact Disc Course Evaluation

Describe the contents of the student workbook and the Student Materials compact disc. Have students write their names on both sides of the name card. Tell students where they can send comments with feedback on the course.

The following materials are included with your kit:


!" !"

Name card. Write your name on both sides of the name card. Student workbook. The student workbook contains the material covered in class, in addition to the hands-on lab exercises. Student Materials compact disc. The Student Materials compact disc contains the Web page that provides you with links to resources pertaining to this course, including additional readings, review and lab answers, lab files, multimedia presentations, and course-related Web sites. Note To open the Web page, insert the Student Materials compact disc into the CD-ROM drive, and then in the root directory of the compact disc, double-click Autorun.exe or Default.htm.

!"

Delivery Tip
Demonstrate how to open the Web page provided on the Student Materials compact disc. On the Trainer Materials compact disc, double-click Autorun.exe or Default.htm in the StudentCD folder.

!"

Course evaluation. To provide feedback on the instructor, course, and software product, send e-mail to mstrain@microsoft.com. Be sure to type Course 2349A in the subject line. Your comments will help us improve future courses. To provide additional comments or inquire about the Microsoft Certified Professional program, send e-mail to mcp@msprograms.com.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

Prerequisites
Topic Objective
To present and describe the prerequisites for this course.
! !

Lead-in
The following prerequisite knowledge is needed for this course.

Proficiency in the C++ or Java Programming Languages Some Exposure to the C# Language

This course requires that you meet the following prerequisites:


!" !"

Proficiency in the C++ or Java programming languages Some exposure to the C# language Students can meet the prerequisites by taking Course 2124A, Introduction to C# Programming for the Microsoft .NET Platform.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

Course Outline
Topic Objective
To provide an overview of each module and what students will learn.
! !

Module 1: Overview of the Microsoft .NET Framework Module 2: Introduction to a Managed Execution Environment Module 3: Working with Components Module 4: Deployment and Versioning Module 5: Common Type System Module 6: Working with Types

Lead-in
In this course, we will cover...

! ! ! !

Briefly describe each module. As you describe each module, acknowledge any information that will meet the student expectations that you recorded earlier.

Module 1, Overview of the Microsoft .NET Framework, defines terminology specific to the Microsoft .NET Framework and describes its key features and benefits. This module also discusses the namespaces taught in this course. There will be minimal lecture and no lab. After completing this module, you will be able to list the major elements of the .NET Framework. Module 2, Introduction to a Managed Execution Environment, introduces the concept of managed execution and shows developers how to quickly build applications that take advantage of the new .NET Framework common language runtime environment. After completing this module, you will be able to explain the main concepts behind the common language runtime and use the features of the .NET Framework to create a simple application. Module 3, Working with Components, discusses how to create a small, componentized application where modules can easily be written in either C# or Microsoft Visual Basic. The steps necessary to construct, compile, and run each program are covered in detail. This module also explains how to build the client application by using the Windows Forms library and ASP.NET Web Forms. After completing this module, you will be able to create and use components in Windows Forms-based and ASP.NET-based applications. Module 4, Deployment and Versioning, explains how to use deployment and versioning features of the .NET Framework common language runtime to build and deploy applications that are fully managed and protected. After completing this module, you will be able to use the deployment and versioning features of the .NET Framework common language runtime to deploy multiple versions of a component.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

Module 5, Common Type System introduces the Common Type System. The module discusses how to differentiate between value types and reference types and examines how classes, interfaces, properties, methods, events, and values are represented in the .NET Framework. After completing this module, you will be able to create, use, and extend types by understanding the Common Type System architecture. Module 6, Working with Types, discusses the use of attributes to control visibility and inheritance on types and explains how to work with various type operations, such as boxing and unboxing, and type operators. In addition, this module discusses how to build an interface that supports methods and properties and how to make interface designs more efficient. Finally, this module highlights features that are designed to help you work with unmanaged types, such as COM types. After completing this module, you will be able to create classes and interfaces that are functionally efficient and appropriate for given programming scenarios.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

Course Outline (continued)


! ! ! ! ! ! !

Module 7: Strings, Arrays, and Collections Module 8: Delegates and Events Module 9: Memory and Resource Management Module 10: Data Streams and Files Module 11: Internet Access Module 12: Serialization Module 13: Remoting and Web Services

Module 7, Strings, Arrays, and Collections, describes some of the key classes in the .NET Framework class library. This module explains how to work with strings, arrays, collections, and enumerators. After completing this module, you will be able to use the .NET framework class library to efficiently create and manage strings, arrays, collections, and enumerators. Module 8, Delegates and Events, explains how the .NET Framework uses delegates in callback and event-handling scenarios. After completing this module, you will be able to use delegates and events to have an event sender object signal the occurrence of an action to an event receiver object. Module 9, Memory and Resource Management, discusses how the .NET Framework automatically handles the allocation and release of an objects memory resources through garbage collection. After completing this module, you will be able to describe and control how memory and other resources are managed in the .NET Framework. Module 10, Data Streams and Files, introduces the System.IO namespace and discusses the types that it contains that allow synchronous and asynchronous reading from and writing to data streams and files. This module discusses synchronous operations only, as asynchronous operations are beyond the scope of this course. After completing this module, you will be able to read from and write to data streams and files. Module 11, Internet Access, discusses the use of the System.Net classes to communicate with other applications by using common protocols, such as HTTP, Transmission Control Protocol (TCP), User Datagram Protocol (UDP), and Socket Internet protocols. After completing this module, you will be able to use the basic request/response model to send and receive data over the Internet.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

Module 12, Serialization, explains how to use serialization to convert a graph of objects into a linear sequence of bytes, which can then be sent to a remote computer and deserialized, thereby making a clone in the remote memory of the original graph of objects. After completing this module, you will be able to serialize and deserialize an object graph. Module 13, Remoting and Web Services, explains how .NET Remoting supports communication between objects in different application domains, in different processes, and on different computers. The module describes how the common language runtime remoting infrastructure provides a rich set of classes that enable you to ignore most of the complexities of deploying and managing remote objects. After completing this module, you will be able to create distributed applications by means of Web Services and Object Remoting.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

Microsoft Certified Professional Program


Topic Objective
To provide students with information about the Microsoft Certified Professional Program.

Lead-in
The Microsoft Certified Professional Program includes these certifications

http://www.microsoft.com/trainingandservices/

The Microsoft Certified Professional program includes the following certifications:


!" !" !" !" !" !"

Microsoft Certified Systems Engineer (MCSE) Microsoft Certified Database Administrator (MCDBA) Microsoft Certified Solution Developer (MCSD) Microsoft Certified Professional + Site Building (MCP + Site Building) Microsoft Certified Professional (MCP) Microsoft Certified Trainer (MCT)

For More Information See the Certification section of the Web page provided on the compact disc or the Microsoft Training and Certification Web site at http://www.microsoft.com/trainingandservices/ You can also send e-mail to mcp@msprograms.com if you have specific certification questions.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Introduction

Exam Preparation Guides


To help prepare for the MCP exams, you can use the preparation guides that are available for each exam. Each Exam Preparation Guide contains exam-specific information, such as a list of the topics on which you will be tested. These guides are available on the Microsoft Certified Professional Web site at http://www.microsoft.com/trainingandservices/ Important MSDN Training curriculum helps you to prepare for Microsoft Certified Professional (MCP) exams. However, no one-to-one correlation exists between MSDN Training courses and MCP exams. Passing MCP exams requires real-world experience with the productsMSDN Training courses help get you started.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Introduction

Facilities
Topic Objective
To inform students of class logistics and rules for the training site.
Class Hours

Lead-in
Before we start, lets go over the class logistics.

Building Hours

Phones

Parking

Messages

Rest Rooms

Smoking

Meals

Recycling

Explain the class hours, extended building hours for labs, parking, rest room location, meals, phones, message posting, and where smoking is or isnt allowed. Let students know if your facility has Internet access that is available for them to use during class breaks. Also make sure that the students are aware of the recycling program if one is available.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework


Contents Overview Overview of the Microsoft .NET Framework Overview of Namespaces Review 1 2 12 15

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

iii

Instructor Notes Module 1


Presentation: 30 Minutes Lab: 00 Minutes This module provides students with an overview of the Microsoft .NET Framework. It defines some of the terminology that is specific to the .NET Framework and describes the .NET Frameworks key features and benefits. The module starts with an overview of the .NET Framework, and then introduces the namespaces in the .NET Framework. It explains which modules teach which namespaces, and which namespaces are not covered in this course. Do not spend too much time on this module. This module is designed to provide only an overview, so do not go into too much detail. This module contains no labs. After completing this module, students will be able to:
!" !"

Describe the .NET Framework and its components. Explain the relationship between the .NET Framework Class Library and namespaces.

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_01.ppt

Preparation Tasks
To prepare for this module, you should: Read all of the materials for this module.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 1: Overview of the Microsoft .NET Framework

Module Strategy
Use the following strategy to present this module:
!"

The .NET Framework Explain each part of the .NET Framework. One important goal of this slide is to explain what this course covers. This course primarily teaches the common language runtime and the .NET Framework class library. This course uses C# to teach the .NET Framework. Only minimal coverage of Web Services, user interfaces, ADO.NET, and ASP.NET is provided. Other courses will cover these technologies in more detail.

!"

Common Language Runtime This is a build slide. Explain each of the following topics as they appear. Definitions of these topics are found in the content. Class Loader Microsoft Intermediate Language (MSIL) to Native compilers, Code Manager, and Garbage Collection Security Engine, Debugger, Type Checker, Exception Manager, Thread Support, and COM Marshaler .NET Framework Class Library Support

!"

The .NET Framework Class Library Explain the benefits of the .NET Framework class library. Explain that the common type system is covered in more detail in Module 5, Common Type System, and Module 6, Working with Types, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease). Specific classes are covered in Module 7, Strings, Arrays, and Collections, and other modules as appropriate.

!"

ADO.NET: Data and XML This is a build slide. Explain the following topics as they appear. System.Data Explain how this namespace works primarily with data, such as data from databases. System.XML Explain how this namespace works primarily with XML and Extensible Stylesheet Language (XSL).

!"

What Is a Web Service? This slide is the key slide for explaining Web Services. Be sure that everyone understands the role of Web Services Description Language (WSDL), Universal Description, Discovery, and Integration (UDDI), SOAP, XML, and HTTP. Also explain that the .NET Software Developers Kit (SDK) and Microsoft Visual Studio .NET provide tools to simplify the creation of Web Services. Note that Web Services are appropriate for internal applications as well as external applications. An enterprise is likely to run multiple platforms; Web Services are a good way of working across platforms because they rely on XML and SOAP. Any platform that supports XML and SOAP can use or expose Web Services.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework


!"

Web Forms and Services Explain how ASP.NET classes make it easier to work with user data on Web pages.

!"

Namespaces Briefly explain the purpose of each namespace. The key point to explain is that there are a lot of data types and functionality in the .NET Framework. Namespaces arrange the types in a hierarchy that make it easier to work with the types.

!"

Namespaces Used in this Course Briefly explain which modules teach which namespaces. Explain that not all of the namespaces are taught in their entirety. For example, the System.Reflection namespace is mentioned in Module 4, Deployment and Versioning, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease), only in terms of versioning. Most of the System.Reflection namespace is not covered. Also explain that the ADO.NET namespaces and security namespaces are not taught in this course.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! !

Overview of the Microsoft .NET Framework Overview of Namespaces

Lead-in
In this module, you will be introduced to the .NET Framework. You will then learn about the namespaces and which modules teach certain namespaces.

The Microsoft .NET Framework provides tools and technologies that you need to build distributed Web applications. In this module, you will learn the architecture of the .NET Framework. You will also learn how the .NET Framework class library is divided into namespaces, and which namespaces are taught in this course. After completing this module, you will be able to:
!" !"

Describe the .NET Framework and its components. Explain the relationship between the .NET Framework class library and namespaces.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

# Overview of the Microsoft .NET Framework


Topic Objective
To provide an overview of the .NET Framework topics.
! ! ! ! ! !

Lead-in
In this section, you will learn about the Microsoft .NET Framework.

The .NET Framework Common Language Runtime The .NET Framework Class Library ADO.NET: Data and XML What is a Web Service? Web Forms and Services

In this section, you will learn about the .NET Framework. The .NET Framework is a set of technologies that form an integral part of the Microsoft .NET platform. It provides the basic building blocks for developing Web applications and Web Services. This section includes the following topics:
!" !" !" !" !" !"

The .NET Framework Common Language Runtime The .NET Framework Class Library ADO.NET: Data and XML What is a Web Service? Web Forms and Services

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

The .NET Framework


Topic Objective
To understand the architecture of the .NET Framework.
VB C++ C# Perl Python

Lead-in
The .NET Framework is an architecture consisting of a runtime, the class library, and language support.

Web Services ASP.NET

User Interface

ADO.NET: Data and XML .NET Framework Class Library Common Language Runtime
Message Queuing COM+ (Transactions, Partitions, Object Pooling) IIS WMI

Win32

The .NET Framework


The .NET Framework provides the necessary compile time and runtime foundation to build and run .NET applications. The .NET Framework is the primary focus of this course.

Platform Substrate
The .NET Framework must run on an operating system. Currently, the .NET Framework is built to work on the Microsoft Win32 operating systems. In the future, the .NET Framework will be extended to run on other platforms, such as Microsoft Windows CE.

Application Services
When running on Windows 2000, application services, such as COM+, Message Queuing, Windows Internet Information Server (IIS), and Windows Management Instrumentation (WMI), are available to the developer. The .NET Framework exposes application services through classes in the .NET Framework class library.

Common Language Runtime


The common language runtime simplifies application development, provides a robust and secure execution environment, supports multiple languages, and simplifies application deployment and management. The common language runtime environment is also referred to as a managed environment, in which common services, such as garbage collection and security, are automatically provided.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

The .NET Framework Class Library


The .NET Framework class library exposes features of the runtime and provides other high-level services that every developer needs. The classes simplify development of .NET applications. Developers can extend them by creating their own libraries of classes.

ADO.NET
ADO.NET is the next generation of ActiveX Data Object (ADO) technology. ADO.NET provides improved support for the disconnected programming model. It also provides rich XML support.

ASP.NET
Microsoft ASP.NET is a programming framework that is built on the common language runtime. ASP.NET can be used on a server to build powerful Web applications. ASP.NET Web Forms provide an easy and powerful way to build dynamic Web user interfaces (UI).

Web Services
The .NET Framework provides tools and classes for building, testing, and distributing Web Services.

User Interfaces
The .NET Framework supports three types of user interfaces:
!" !" !"

Web Forms, which work through ASP.NET Windows Forms, which run on Win32 clients Console applications, which for simplicity, are used for most of the labs in this course

Languages
Any language that conforms to the common language specification (CLS) can run on the common language runtime. In the .NET Framework, Microsoft provides Microsoft Visual Basic, Microsoft Visual C++, Microsoft Visual C#, and Microsoft JScript support. Third parties can provide additional languages.

Building Components in the .NET Framework


In the .NET Framework, components are built on a common foundation. You no longer need to write the code to allow objects to interact directly with each other. In addition, you no longer need to write component wrappers in the .NET environment, because components do not use wrappers. The .NET Framework can interpret the constructs that developers are accustomed to using in objectoriented languages. The .NET Framework fully supports class, inheritance, methods, properties, events, polymorphism, constructors, and other objectoriented constructs.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

Common Language Runtime


Topic Objective
To highlight some of the key components in the common language runtime.

.NET Framework Class Library Support Thread Support Type Checker Security Engine MSIL to Native Compilers Code Manager Class Loader COM Marshaler Exception Manager Debugger Garbage Collection

Lead-in
This topic will give you an overview of the components of the common language runtime. I will briefly describe each component. As a C# developer, you will never see these discrete pieces, but this discussion will give you a better understanding of the richness of the runtime.

The common language runtime simplifies application development, provides a robust and secure execution environment, supports multiple languages, and simplifies application deployment and management. The common language runtime environment is also referred to as a managed environment, one in which common services, such as garbage collection and security, are automatically provided. The common language runtime features are described in the following table.
Component Class loader Microsoft Intermediate Language (MSIL) to native compiler Code manager Garbage collection Security engine Debugger Type checker Exception manager Thread support COM marshaler .NET Framework class library support Description Manages metadata, and the loading and layout of classes. Converts MSIL to native code on a just-in-time basis.

Manages code execution. Provides automatic lifetime management of all of objects in the .NET Framework, garbage collection is a multiprocessor, scalable garbage collector. Provides evidence-based security, based on user identity and the origin of the code. Enables the developer to debug an application and trace the execution of code. Does not allow unsafe casts or uninitialized variables. MSIL can be verified to guarantee type safety. Provides structured exception handling, which is integrated with Windows Structured Exception Handling (SEH). Error reporting has been improved. Provides classes and interfaces that enable multithreaded programming. Provides marshaling to and from COM. Integrates code with the runtime that supports the .NET Framework class library.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

The .NET Framework Class Library


Topic Objective
To provide an overview of the .NET Framework class library and the most common namespace: System.
!

Spans All Programming Languages


$ $

Enables cross-language inheritance and debugging Integrates well with tools Enhances developer productivity by reducing the number of APIs to learn

Lead-in
In this topic, you will learn how .NET Framework class library exposes features of the runtime and provides other high-level services.

Is Object-Oriented and Consistent


$

! !

Has a Built-In Common Type System Is Extensible


$

Makes it easy to add or modify framework features Allows creation of secure applications

Is Secure
$

The .NET Framework class library exposes features of the runtime and provides other high-level services that every developer needs. Because there are hundreds of classes in the .NET Framework class library, classes are grouped into namespaces. The first part of the full name, which is located before the rightmost dot, is the namespace name. The last part of the name, which is located after the dot, is the type name. For example, System.Collections.ArrayList represents the ArrayList class, which belongs to the System.Collections namespace. The types in System.Collections namespace can be used to manipulate collections of objects.

Spans All Programming Languages


The .NET Framework class library is language-independent so it enables crosslanguage inheritance and debugging. The .NET Framework class library also integrates fully with Microsoft Visual Studio .NET, making it easy to develop applications with the library.

Is Object-Oriented and Consistent


Unlike flat APIs that are numerous and unorganized, the .NET Framework class library is organized into namespaces and classes. This object-oriented approach groups related functionality and data together and enables the developer to work with the library in a more natural way.

Has a Built-In Common Type System


The .NET Framework class library is type-safe. Type safety is ensured through the common type system, which is part of the common language runtime.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

Is Extensible
You can extend the library by creating your own classes and compiling them into libraries. If designed properly, your class libraries will also be objectoriented and language-independent.

Is Secure
The .NET Framework class library provides rich security for your applications. You can use code access security and role-based security, and configure your own security policies. Furthermore, there are numerous security tools to assist in certificate creation, permission viewing, and so on.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

ADO.NET: Data and XML


Topic Objective
To explain the data and XML support in the runtime.

Lead-in
The .NET Framework provides a new set of ADO.NET classes to handle data.

ADO.NET: Data and XML


System.Data OleDb Common SqlClient SQLTypes XSL XPath System.Xml

Serialization

ADO.NET, the next generation of ADO technology provides improved support for disconnected programming. It also provides rich XML support in the System.Xml namespace.

System.Data Namespace
The System.Data namespace consists of classes that constitute the ADO.NET object model. At a high level, the ADO.NET object model is divided into two layers: the connected layer and the disconnected layer. The System.Data namespace includes the DataSet class, which represents multiple tables and their relations. These data sets are completely self-contained data structures that can be populated from a variety of data sources. One data source could be XML; another data source could be an OLE DB; and a third data source could be the direct adapter for Microsoft SQL Server.

System.Xml Namespace
The System.Xml namespace provides support for XML. It includes an XML parser and a writer, which are W3C-compliant. The Extensible Stylesheet Language for Transformation (XSLT) is provided by the System.Xml.Xsl namespace. The implementation of XPath, a comprehensive language for document addressing, enables data graph navigation in XML. The System.Xml.Serialization namespace provides the entire core infrastructure for Web Services, including such features as moving back and forth from objects to an XML representation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

What Is a Web Service?


Topic Objective
To define a Web Service.

Lead-in
Web Services are the fundamental building blocks of the .NET platform.
!

Open Internet Protocols

Web Service
A programmable application component accessible via standard Web protocols
Universal Description, Discovery, and Integration

Provide a Directory of Services on the Internet Web Services are defined in terms of the formats and ordering of messages Web Services consumers can send and receive messages using XML Built using open Internet protocols

UDDI

Web Services Description Language

WSDL

SOAP XML & HTTP

Web Services are an integral part of the .NET platform. They are the fundamental mechanism for exposing and consuming data and functionality across Web applications, both inside organizations and across organizations. Web Services are units of application logic that provide data and services to other applications. Applications access Web Services by means of industry standard Web protocols and data formats, such as HTTP, XML, and Simple Object Access Protocol (SOAP), regardless of how each Web Service is implemented.

XML and HTTP


Web Services are built by using XML and HTTP. Because they are built with XML and HTTP, Web Services operate without firewall restrictions. Also, because XML and HTTP are industry standards, any platform supporting XML and HTTP can work with Web Services.

SOAP
SOAP defines how messages are formatted, sent, and received when working with Web Services. SOAP is also an industry standard that is built on XML and HTTP. Any platform that supports the SOAP standard can support Web Services.

Web Services Description Language


The Web Services Description Language (WSDL) is an XML format for describing the network services that are offered by the server. You use WSDL to create a file that identifies the services that are provided by the server and the set of operations within each service that the server supports. For each of the operations, the WSDL file also describes the format that the client must follow when requesting an operation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 1: Overview of the Microsoft .NET Framework

Universal Description, Discovery, and Integration


Universal Description, Discovery, and Integration (UDDI) is an industry standard for registering and searching for Web Services. By using UDDI, developers can discover and use Web Services that are available publicly over the Internet. For more information on UDDI, see Web Service Discovery in Module 13, Remoting and Web Services, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease), and the UDDI Web site at http://www.uddi.org.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

11

Web Forms and Services


Topic Objective
To explain Web Forms and Web Services.

Lead-in
The Internet is quickly evolving from todays Web sites that simply deliver UI pages to browsers to a next generation of programmable Web sites that link organizations, applications, services, and devices directly.
Services Description Discovery Protocols Caching Configuration

ASP.NET
System.Web
UI HtmlControls WebControls

Security SessionState

ASP.NET is a programming framework built on the common language runtime that can be used on a server to build powerful Web applications. ASP.NET Web Forms provide an easy and powerful way to build dynamic Web UI pages. ASP.NET Web Services provide the building blocks for constructing distributed Web-based applications. Web Services are based on open Internet standards, such as HTTP and XML. The common language runtime provides built-in support for creating and exposing Web Services by using a programming abstraction that is consistent and familiar to both ASP Web Forms and Visual Basic developers. The resulting model is both scalable and extensible. This model is based on open Internet standards, such as HTTP, XML, SOAP, and WSDL, so it can be accessed and interpreted by any client or Internet-enabled device. Some of the more common ASP.NET classes are described in this topic as follows:

System.Web
In the System.Web namespace, there are lower-level services, such as caching, security, and configuration, which are shared between Web Services and Web UIs.

System.Web.Services
The System.Web.Services namespace has classes that handle Web Services, such as protocols and discovery.

Controls
There are two types of controls: HTML controls and Web controls. The System.Web.UI.HtmlControls namespace gives you direct mapping of HTML tags, such as input. The System.Web.UI.WebControls namespace enables you to structure controls with templates, such as grid controls.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 1: Overview of the Microsoft .NET Framework

# Overview of Namespaces
Topic Objective
To provide an overview of the namespaces in the .NET Framework.
! !

Namespaces Namespaces Used in this Course

Lead-in
In this section, you will learn about the namespaces in the .NET Framework.

In this section, you will learn about the namespaces in the Microsoft .NET Framework. You will also learn about which namespaces are taught in this course. This section includes the following topics:
!" !"

Namespaces Namespaces Used in this Course

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

13

Namespaces
Topic Objective
To understand how namespaces provide an easy-to-use hierarchy of types and functionality.

Lead-in
The .NET Framework includes a large set of class library assemblies, which contain hundreds of types. These assemblies provide access to system functionality in your development process.
Collections Configuration Diagnostics Globalization IO Net Reflection Resources

System
Security ServiceProcess Text Threading Runtime .InteropServices .Remoting .Serialization

The .NET Framework includes a large set of class library assemblies, which contain hundreds of types. These assemblies provide access to system functionality in your development process.

The Purpose of Namespaces


Because the .NET Framework class library includes definitions for so many types, the library is organized in a hierarchical namespace structure. Namespaces use a dot-syntax naming scheme to group logically related classes together so that they can be easily searched and referenced. For example, the System.Data namespace contains the classes that constitute the ADO.NET architecture. The System.Xml namespace is the overall namespace for the XML classes that provide standards-based support for processing XML.

The System Namespace


The System namespace is the root namespace for types in the .NET Framework. The System namespace contains the base type Object, from which all other types are derived. The System namespace also contains types for exception handling, garbage collection, console I/O, various tool types, format data types, random number generators, and math functions.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 1: Overview of the Microsoft .NET Framework

Namespaces Used in this Course


Topic Objective
To explain which namespaces are taught in this course, and which namespaces are not taught. Module 2
$

Module 10
$

System.Console System.Windows.Forms System.Drawing System.Reflection System.Text System.Collections

System.IO System.Net System.Net.Sockets System.Runtime.Serialization System.Runtime.Remoting.Channels System.Web.Services

Module 3
$ $

Module 11
$ $

Lead-in
This course covers many of the System namespaces. Some namespaces not covered are the System.Data and System.Security namespaces.

Module 4
$

Module 12
$

Module 7
$ $

Module 13
$ $

This course covers many of the namespaces in the Microsoft .NET Framework. Module 2 teaches the System.Console namespace for printing output to the console. Module 3 teaches the System.Windows.Forms and System.Drawing namespaces for building a form with buttons that interacts with the user. Module 4 teaches the System.Reflection namespace for storing version and key file information in an assembly. Module 7 teaches the System.Text namespace for advanced string management, and System.Collections for maintaining collections of data. Module 10 teaches the System.IO namespace for reading and writing to files. Module 11 teaches the System.Net and System.Net.Sockets namespaces for transmitting data over the network. Module 12 teaches the System.Runtime.Serialization namespace for persisting objects to storage. Module 13 teaches the System.Runtime.Remoting.Channels and System.Web.Services namespaces for invoking remote objects, and building XML Web Services.

Namespaces Not Covered


This course does not teach the System.Data namespace for ADO.NET. This namespace and related data namespaces are taught in Course 2389A, Developing Applications Using ADO.NET. Also the System.Security namespace is not taught in this course. System.Security and related security namespaces are taught in Course 2350A, Securing and Deploying Microsoft .NET Assemblies (Prerelease).

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 1: Overview of the Microsoft .NET Framework

15

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! !

Overview of the Microsoft .NET Framework Overview of Namespaces

Lead-in
The review questions cover some of the key concepts taught in the module.

1. List the components of the .NET Framework. The common language runtime, .NET Framework class library, data and XML, Web Services and Web Forms, and Windows Forms.

2. What is the purpose of the common language runtime? It provides an environment in which you can execute code.

3. What is the purpose of the common language specification? It defines a set of features that all .NET languages should support.

4. What is a Web Service? Web Services are programmable Web components that can be shared among applications on the Internet or an intranet.

5. What is a managed environment? A managed environment is an environment that provides services, such as garbage collection, security, and other related features.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

THIS PAGE INTENTIONALLY LEFT BLANK

Module 2: Introduction to a Managed Execution Environment


Contents Overview Writing a .NET Application Compiling and Running a .NET Application Multimedia: Application Loading and Single-File Assembly Execution Lab 2: Building a Simple .NET Application Review 1 2 10 26 28 31

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

iii

Instructor Notes Module 2


Presentation: 45 Minutes Lab: 15 Minutes After completing this module, students will be able to:
!" !"

Create simple console applications in C#. Explain how code is compiled and executed in a managed execution environment. Explain the concept of garbage collection.

!"

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials:
!" !"

Microsoft PowerPoint file 2349A_02.ppt Sample managed module HelloDemoCS.exe

Preparation Tasks
To prepare for this module, you should:
!" !" !" !"

Read all of the materials for this module. Practice the demonstrations. Review the animation. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 2: Introduction to a Managed Execution Environment

Demonstrations
This section provides demonstration procedures that will not fit in the margin notes or are not appropriate for the student notes.

Hello, World
This demonstration shows how to build a simple application in C#. In the following procedures, use Notepad to create the simple Hello, World application, and build and run the HelloDemoCS.exe application from the command line.

!" create the source code in C# To


1. Open Notepad and type the following code:
// Allow easy reference to System namespace classes using System; // Create class to hold program entry point class MainApp { public static void Main() { // Write text to the console Console.WriteLine(Hello World using C#!); } }

2. Save the file as HelloDemoCS.cs.

!" compile the source code and build an executable program To


From a command prompt window, type the following syntax:
csc HelloDemoCS.cs

Running the resulting executable file will generate the following output:
Hello World using C#!

Viewing Assembly Metadata by Using the MSIL Disassembler


This demonstration shows how to use the Microsoft Intermediate Language (MSIL) Disassembler (Ildasm.exe) to view an assemblys metadata. The code for this demonstration is contained in one project and is located in <install folder>\Democode\Mod02. To demonstrate how to use the MSIL Disassembler to view the contents of the HelloDemoCS.exe assembly, follow the directions in Demonstration: Using the MSIL Disassembler in Module 2, Introduction to a Managed Execution Environment in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

Module Strategy
Use the following strategy to present this module:
!"

Writing a .NET Application Stress the importance of understanding the process of compiling and running Microsoft .NET Framework applications, by using the simple Hello, World application. Focus primarily on the compilation and execution processes.

!"

Compiling and Running a .NET Application This section introduces basic concepts of a managed execution environment and presents new terminology. Many of these concepts are covered in greater detail in subsequent modules in this course, in subsequent courses, and in the NET Framework Software Developers Kit (SDK) documentation. Emphasize that you are primarily introducing new concepts and terminology. Be prepared to postpone answering questions that pertain to information that is covered in later modules. Encourage students to start reading the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! !

Writing a .NET Application Compiling and Running a .NET Application

Lead-in
This module introduces the concept of managed execution and shows you how to quickly build applications that use the Microsoft .NET Framework common language runtime environment.

This module introduces the concept of managed execution and shows you how to quickly build applications that use the Microsoft .NET Framework common language runtime environment. A simple Hello, World version of a console application illustrates most of the concepts that are introduced in this module. Because this course is an introduction to programming in the .NET Framework, you should spend some time reading the .NET Framework Software Developers Kit (SDK) documentation. In fact, the labs, demonstrations, and material for this module and other modules in this course are based on several tutorials in the .NET Framework SDK. After completing this module, you will be able to:
!" !"

Create simple console applications in C#. Explain how code is compiled and executed in a managed execution environment. Explain the concept of garbage collection.

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

# Writing a .NET Application


Topic Objective
To introduce the topics in the section.
! ! ! ! ! !

Lead-in
Because all supported languages use the Common Type System and the .NET Framework class library, and run in the common language runtime, programs in the supported languages are similar.

Demonstration: Hello World Using a Namespace Defining a Namespace and a Class Entry Points, Scope, and Declarations Console Input and Output Case Sensitivity

Because all supported languages use the Common Type System and the .NET Framework base class library, and run in the common language runtime, programs in the supported languages are similar. The most significant difference in programming with the supported languages is syntax. Delivery Tip
Stress the importance of understanding the process of compiling and running the .NET applications. Using Visual Studio .NET at this time may obscure the underlying processes.

Note In this module, and in Modules 3 and 4, Notepad is used as the source code editor, instead of the Microsoft Visual Studio .NET development environment. The examples in these modules are simple enough to be compiled and built directly from a command prompt window. Working in Notepad will allow you to focus on the compilation and execution processes.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

Demonstration: Hello World


Topic Objective
To demonstrate how to build a simple application in C#.

Lead-in
In this demonstration, you will learn how to build a simple application in C#.

In this demonstration, you will learn how to build a simple application in C#. Delivery Tip
As this is a short, simple demonstration, you may want to let students try it themselves.

!" create the source code in C# To


1. Open Notepad and type the following code:
// Allow easy reference to System namespace classes using System; // Create class to hold program entry point class MainApp { public static void Main() { // Write text to the console Console.WriteLine(Hello World using C#!); } }

2. Save the file as HelloDemoCS.cs

!" compile the source code and build an executable program To


From a command prompt window, type the following syntax:
csc HelloDemoCS.cs

Running the resulting executable will generate the following output:


Hello World using C#!

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

Using a Namespace
Topic Objective
To describe how to use namespaces in the .NET Framework.
!

Classes Can Be Fully Referenced


// declares a FileStream object // declares a FileStream object System.IO.FileStream aFileStream; System.IO.FileStream aFileStream;

Lead-in
You can fully reference classes in which an instance of System.IO.FileStream is declared by using C#:

Or the Namespace of a Class Can Be Referenced


$

No need to fully qualify contained class names

using System.IO; using System.IO; ... ... FileStream aFileStream; FileStream aFileStream;

You can fully reference classes, as in the following example, in which an instance of System.IO.FileStream is declared by using C#:
System.IO.Filestream aFileStream;

However, it is more convenient to reference the required namespaces in your program. Using the namespace obviates the need to qualify all class library references, as in the following example:
using System.IO; ... FileStream aFileStream;

For example, in order to have convenient access to System objects, you must use the System namespace.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

Defining a Namespace and a Class


Topic Objective
To describe how to define namespaces and classes in C#.
!

C# Supports Creation of Custom Namespaces and Classes Within Those Namespaces

Lead-in
C# supports the creation of custom namespaces and classes within those namespaces.

namespace CompCS { namespace CompCS { public class StringComponent { public class StringComponent { ... ... } } } }

C# supports the creation of custom namespaces and classes within those namespaces. Tip The following is the general rule for naming namespaces: CompanyName.TechnologyName For example: Microsoft.Office This is merely a guideline. Third-party companies can choose other names.

Namespaces in C#
In C#, you use the namespace statement to define a new namespace, which encapsulates the classes that you create, as in the following example:
namespace CompCS { public class StringComponent { ... } }

Note that a namespace may be nested in other namespaces, and a single namespace may be defined in multiple files. A single source code file may also define multiple namespaces.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

Entry Points, Scope, and Declarations


Topic Objective
To describe how to create program entry points in C#.
!

In C#, the External Entry Point for a Program Is in a Class


class MainApp class MainApp { public static void Main() { public static void Main() {. . .} {. . .} } }

Lead-in
Every executable program must contain an external entry point, where the application begins its execution.

C# Supports the Use of a Period As a Scope Resolution Operator


Console.WriteLine ("First String"); Console.WriteLine ("First String");

In C#, Objects Must Be Declared Before They Can Be Used and Are Instantiated Using the New Keyword
Lib.Comp myComp = new Lib.Comp(); Lib.Comp myComp = new Lib.Comp();

Every executable program must contain an external entry point, where the application begins its execution. In C#, all code must be contained in methods of a class.

Entry Points in C#
To accommodate the entry point code in C#, you must first specify the class, as in the following example:
class MainApp {...}

Next, you specify the entry point for your program. The compiler requires this entry point to be a public static method called Main, as in the following example:
public static void Main () {...}

Scope
C# uses the period as a scope resolution operator. For example, you use the syntax Console.WriteLine when referencing the WriteLine method of the Console object.

Declaring and Instantiating Variables


In C#, you must declare a variable before it can be used. To instantiate the object, use the new keyword. The following example in C# shows how to declare an object of type Comp, in namespace Lib, with the name myComp:
Lib.Comp myComp = new Lib.Comp();

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

Console Input and Output


Topic Objective
To describe how to use Console class methods in C#.
!

Console Class Methods


$

Lead-in
You can use the runtime Console class of the System namespace for input and output to the console of any string or numeric value by using the Read, ReadLine, Write, and WriteLine methods.

Read, ReadLine, Write, and WriteLine

Console.WriteLine("Hello World using C#!"); Console.WriteLine("Hello World using C#!");

You can use the common language runtimes Console class of the System namespace for input and output to the console of any string or numeric value by using the Read, ReadLine, Write, and WriteLine methods. The following example shows a C# program that outputs a string to the console:
using System; class MainApp { public static void Main() { // Write text to the console Console.WriteLine(Hello World using C#!); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

Case Sensitivity
Topic Objective
To describe case sensitivity issues in programming languages.
!

Do Not Use Names That Require Case Sensitivity


$

Lead-in
C++ and C# are casesensitive, but Visual Basic is not case-sensitive.

Components should be fully usable from both casesensitive and case-insensitive languages Case should not be used to distinguish between identifiers within a single name scope

Avoid the Following


class class class class customer customer Customer Customer {...} {...} {...} {...}

void foo(int X, int x) void foo(int X, int x)

C++ and C# are case-sensitive, but Microsoft Visual Basic is not casesensitive. To ensure that a program is compliant with the Common Language Specification (CLS), however, you must take special care with public names. You cannot use case to distinguish between identifiers within a single name scope, such as types within assemblies and members within types. The following examples show situations to avoid:
!"

Do not have two classes or namespaces whose names differ only by case.
class customer { ... } class Customer { ... }

!"

Do not have a function with two parameters whose names differ only by case.
void foo(int X, int x)

This constraint enables Visual Basic (and potentially other case-insensitive languages) to produce and use components that have been created in other casesensitive languages. This constraint does not apply to your definitions of private classes, private methods on public classes, or local variables.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

Note To fully interact with other objects regardless of the language they were implemented in, objects must expose to callers only those features that are common to all the languages they must interoperate with. For this reason, a set of language features has been defined, called the Common Language Specification (CLS), which includes basic language features that are needed by many applications. The CLS rules define a subset of the common type system; that is, all the rules that apply to the common type system apply to the CLS, except where stricter rules are defined in the CLS. If your component uses only CLS features in the API that it exposes to other code (including derived classes), the component is guaranteed to be accessible from any programming language that supports the CLS. Components that adhere to the CLS rules and use only the features included in the CLS are said to be CLS-compliant components.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 2: Introduction to a Managed Execution Environment

# Compiling and Running a .NET Application


Topic Objective
To introduce the topics in the section.
! ! ! ! ! ! ! ! ! !

Compiler Options The Process of Managed Execution Metadata Microsoft Intermediate Language Assemblies Common Language Runtime Tools Demonstration: Using the MSIL Dissembler Just-In-Time Compilation Application Domains Garbage Collection

Lead-in
Most aspects of programming in the .NET Framework are the same for all compatible languages; each supported language compiler produces selfdescribing, managed Microsoft intermediate language (MSIL) code.

Most aspects of programming in the .NET Framework are the same for all compatible languages; each supported language compiler produces selfdescribing, managed Microsoft intermediate language (MSIL) code. All managed code runs using the common language runtime, which provides crosslanguage integration, automatic memory management, cross-language exception handling, enhanced security, and a consistent and simplified programming model. Delivery Tip
Emphasize that you are primarily introducing new concepts and terminology. Be prepared to postpone answering questions that pertain to later modules. Encourage students to start reading the .NET Framework SDK documentation.

This section introduces basic concepts of a managed execution environment and presents new terminology. Many of these concepts are covered in greater detail in subsequent modules in this course, in subsequent courses, and in the NET Framework SDK Documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

11

Compiler Options
Topic Objective
To introduce compiler options in C#.
!

Lead-in
The .NET Framework includes a command line compiler for C#.

Compile Directly from a Command Prompt Window


>csc HelloCS.cs >csc HelloCS.cs

Use /t to indicate target


>csc /t:exe HelloCS.cs >csc /t:exe HelloCS.cs

Use /reference to reference assemblies

>csc /t:exe /reference:assemb1.dll HelloCS.cs >csc /t:exe /reference:assemb1.dll HelloCS.cs

The .NET Framework includes a command line compiler for C#. The filename of the compiler is Csc.exe.

Compiling in C#
To compile the source code for the Hello, World application presented in the Hello, World demonstration at the beginning of this module, type the following:
csc HelloCS.cs

This syntax invokes the C# compiler. In this example, you only need to specify the name of the file to be compiled. The compiler generates the program executable, HelloCS.exe.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 2: Introduction to a Managed Execution Environment

Command Line Options


In C#, you can obtain the complete list of command line options by using the /? switch as follows:
csc /?

Common options include the /out switch, which specifies the name of the output file, and the /target switch, which specifies the target type. By default, the name of the output file is the name of the input file with an .exe extension. The default for the target type is an executable program. The following example shows the use of both the /out and /t switches in C#:
csc /out:HelloCS.exe /t:exe HelloCS.cs

The /t switch is equivalent to the /target switch. For more information about compiler options, see the .NET Framework SDK documentation.

Using the /reference Compilation Option


When referring to other assemblies, you must use the /reference compilation switch. The /reference compilation option allows the compiler to make information in the specified libraries available to the source that is currently being compiled. The following example shows how to build an executable program from the command line by using the /reference compilation option.
csc /r:assemb1.dll,assemb2.dll /out:output.exe input.cs

The /r switch is equivalent to the /reference compilation switch.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

13

The Process of Managed Execution


Topic Objective
To introduce fundamental concepts of compiling and executing code in a managed execution environment.
EXE/DLL EXE/DLL (MSIL and (MSIL and metadata) metadata) Class Class Libraries Libraries (MSIL and (MSIL and metadata) metadata)

Compiler Compiler

Source Source Code Code

Class Loader Class Loader JIT Compiler JIT Compiler with optional with optional verification verification Trusted, pre-JITed code only
Managed Native Code

Lead-in
In the .NET Framework, the common language runtime provides the infrastructure for a managed execution environment.

Call to an uncompiled method

Execution Execution Security Checks Security Checks

Runtime Engine

In the .NET Framework, the common language runtime provides the infrastructure for a managed execution environment. This topic introduces fundamental concepts of compiling and executing code in a managed execution environment and identifies new terminology.

Compiling Source Code


When you develop an application in the .NET Framework, you can write the source code in any programming language as long as the compiler that you use to compile the code targets the common language runtime. Compilation of the source code produces a managed module. The managed module is contained within a physical file also known as a portable executable (PE) file. The file may contain the following items:
!"

Microsoft Intermediate Language (MSIL) The compiler translates the source code into MSIL, a CPU-independent set of instructions that can be efficiently converted to native code.

!"

Type Metadata This information fully describes types, members, and other references, and is used by the common language runtime at run time.

!"

A Set of Resources For example, .bmp or .jpg files.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 2: Introduction to a Managed Execution Environment

If the C# compilers target option is either exe or library, then the compiler produces a managed module that is an assembly. Assemblies are a fundamental part of programming with the .NET Framework. Assemblies are the common language runtimes fundamental unit of sharing, deployment, security, and versioning. The .NET common language runtime only executes MSIL code that is contained in an assembly. If the C# compilers target option is module, then the compiler produces a managed module that is not an assembly, it does not contain a manifest and cannot be executed by the common language runtime. A managed module can be added to an assembly by the C# compiler, or by using the .NETs Assembly Generation Tool, Al.exe. Subsequent topics in this module cover MSIL, metadata, and assemblies in more detail.

Executing Code
When a user executes a managed application, the operating system loader loads the common language runtime, which then begins executing the modules managed MSIL code. Because current host CPUs cannot execute the MSIL instructions directly, the common language runtime must first convert the MSIL instructions into native code. The common language runtime does not convert all of the modules MSIL code into CPU instructions at load time. Instead, it converts the instructions when functions are called. The MSIL is compiled only when needed. The component of the common language runtime that performs this function is called the justin-time (JIT) compiler. JIT compilation conserves memory and saves time during application initialization. For more information about the JIT compiler, see Just-In-Time Compilation in this module.

Application Domain
Operating systems and runtime environments typically provide some form of isolation between applications. This isolation is necessary to ensure that code running in one application cannot adversely affect other, unrelated applications. Application domains provide a secure and versatile unit of processing that the common language runtime can use to provide isolation between applications. Application domains are typically created by runtime hosts, which are responsible for bootstrapping the common language runtime before an application is run.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

15

Metadata
Topic Objective
To explain how metadata is used in the common language runtime.
! ! !

Declarative Information Emitted at Compile Time Included with All .NET Framework Files and Assemblies Metadata Allows the Runtime to:
$ $ $ $

Lead-in
Every compiler that targets the common language runtime is required to emit full metadata into every managed module.

Load and locate code Enforce code security Generate native code at runtime Provide reflection

Every compiler that targets the common language runtime is required to emit full metadata into every managed module. This topic explains how the common language runtime uses metadata.

Definition of Metadata
Metadata is a set of data tables, which fully describe every element that is defined in a module. This information can include data types and members with their declarations and implementations, and references to other types and members. Metadata provides the common language runtime with all the information that is required for software component interaction. It replaces older technologies, such as Interface Definition Language (IDL) files, type libraries, and external registration. Metadata is always embedded in the .exe or .dll file containing the MSIL code. Therefore, it is impossible to separate metadata from the MSIL code.

Uses for Metadata


Metadata has many uses, but the following uses are most important:
!"

Locating and loading classes Because metadata and MSIL are included in the same file, all type information in that file is available to the common language runtime at compile time. There is no need for header files because all types in a particular assembly are described by the assemblys manifest.

!"

Enforcing security The metadata may or may not contain the permissions required for the code to run. The security system uses permissions to prevent code from accessing resources that it does not have authority to access.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 2: Introduction to a Managed Execution Environment

Other uses for metadata include:


!" !" !"

Resolving method calls. Setting up runtime context boundaries. Providing reflection capability.

For more information about metadata, see Metadata and Self-Describing Components in the .NET Framework SDK documentation. For more information about verification of type safety, see Module 4, Deployment and Versioning, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

17

Microsoft Intermediate Language


Topic Objective
To introduce MSIL and JIT compilation.
! !

Lead-in
Microsoft intermediate language, sometimes called managed code, is the set of instructions that the compiler produces as it compiles source code.

Produced by Each Supported Language Compiler Converted to Native Language by the Common Language Runtime's JIT Compilers

Microsoft intermediate language (MSIL), sometimes called managed code, is the set of instructions that the compiler produces as it compiles source code. This topic explains MSIL and the general process for converting MSIL to native code.

Compiled MSIL
Regardless of their logical arrangement, most assemblies contain code in the form of MSIL. MSIL is a CPU-independent machine language created by Microsoft in consultation with third-party compiler vendors. However, MSIL is a much higher-level language than most CPU machine languages. MSIL contains instructions for many common operations, including instructions for creating and initializing objects, and for calling methods on objects. In addition, it includes instructions for arithmetic and logical operations, control flow, direct memory access, and exception handling.

Conversion to Native Code


Before MSIL code can be executed, it must be converted to CPU-specific or native code by a JIT compiler. The common language runtime provides an architecture-specific JIT compiler for each CPU architecture. These architecture-specific JIT compilers allow you to write managed code that can be JIT compiled and executed on any supported architecture. Note Any managed code that calls platform-specific native APIs or libraries can only run on a specific operating system. For more information about MSIL, see the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 2: Introduction to a Managed Execution Environment

Assemblies
Topic Objective
This topic introduces the concept of an assembly and the role of the assembly manifest.
Managed Module Managed Module (MSIL and Metadata) (MSIL and Metadata) Managed Module Managed Module (MSIL and Metadata) (MSIL and Metadata)

Assembly Assembly

Lead-in
The common language runtime uses an assembly as the functional unit of sharing and reuse.
.html .gif Multiple Managed Modules and Resource Files Are Compiled to Produce an Assembly
Manifest Manifest

Resource Files

The common language runtime uses an assembly as the functional unit of sharing and reuse.

Definition of an Assembly
An assembly is a unit of class deployment, analogous to a logical .dll. Each assembly consists of all the physical files that make up the functional unit: any managed modules, and resource or data files. Conceptually, assemblies provide a way to consider a group of files as a single entity. You must use assemblies to build an application, but you can choose how to package those assemblies for deployment. An assembly provides the common language runtime with the information that it needs to understand types and their implementations. As such, an assembly is used to locate and bind to referenced types at run time.

The Assembly Manifest


An assembly contains a block of data known as a manifest, which is a table in which each entry is the name of a file that is part of the assembly. The manifest includes the metadata that is needed to specify the version requirements, security identity, and the information that is used to define the scope of the assembly and resolve references to resources and classes. Because the metadata makes an assembly self-describing, the common language runtime has the information it requires for each assembly to execute.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

19

All applications that are executed by the common language runtime must be composed of an assembly or assemblies. All files that make up an assembly must be listed in the assemblys manifest. The manifest can be stored in singlefile assemblies or multi-file assemblies:
!"

Single-file assemblies When an assembly has only one associated file, the manifest is integrated into a single PE file.

!"

Multi-file assemblies When an assembly has more than one associated file, the manifest can be a standalone file, or it can be incorporated into one of the PE files in the assembly.

For more information about assemblies, see Assemblies in the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 2: Introduction to a Managed Execution Environment

Common Language Runtime Tools


Topic Objective
This topic describes how the MSIL Assembler and MSIL Disassembler work.
!

Runtime Utilities for Working with MSIL


$

Lead-in
The common language runtime provides two tools that you can use together to test and debug MSIL code.

MSIL Assembler (ilasm.exe) produces a final executable binary MSIL Disassembler (ildasm.exe) inspects metadata and code of a managed binary

The common language runtime provides two tools that you can use to test and debug MSIL code.
!"

The MSIL Assembler The MSIL Assembler (Ilasm.exe) takes MSIL as text input and generates a PE file, which contains the binary representation of the MSIL code and required metadata. The basic syntax is as follows: ilasm [options] filename [options]

!"

The MSIL Disassembler You can use the MSIL Disassembler (Ildasm.exe) to examine the metadata and disassembled code of any managed module. You will use this tool to examine MSIL code in Lab 2, Building a Simple .NET Application.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

21

Demonstration: Using the MSIL Disassembler


Topic Objective
To demonstrate how the MSIL Disassembler works.

Lead-in
This demonstration shows how to use the MSIL Disassembler to view an assemblys metadata.

This demonstration shows how to use the MSIL Disassembler to view an assemblys metadata.

Viewing Assembly Metadata by Using the MSIL Disassembler


In the following procedures, you will see how to use the MSIL Disassembler (Ildasm.exe) to view the contents of the HelloDemoCs.exe assembly.

!" run the MSIL Disassembler on the HelloDemoCS.exe assembly To


At the command prompt, change the directory to <install folder>\Democode\Mod02 where the sample file HelloDemoCS.exe has been copied, and type the following command:
ildasm HelloDemoCS.exe

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 2: Introduction to a Managed Execution Environment

After you expand the MainApp icon, the MSIL Disassembler graphical user interface (GUI) displays information about the file HelloDemoCS.exe, as shown in the following illustration:

!" display the contents of the manifest To


1. Double-click MANIFEST. The MANIFEST window appears, as follows:

2. Close the Manifest window, and then close ILDASM.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

23

Just-In-Time Compilation
Topic Objective
To describe JIT compilation and introduce JIT compiler options.
!

Process for Code Execution


$ $ $

Lead-in
MSIL code must be converted into native code before it can execute. Because an intermediate step is involved, the common language runtime optimizes the compilation process for efficiency.

MSIL converted to native code as needed Resulting native code stored for subsequent calls JIT compiler supplies the CPU-specific conversion

As previously stated in this module, MSIL code must be converted into native code before it can execute. Because an intermediate step is involved, the common language runtime optimizes the compilation process for efficiency.

The Code Execution Process


The common language runtime compiles MSIL as needed. This just-in-time, or JIT, compiling saves time and memory. The basic process is as follows: 1. When the common language runtime loads a class type, it attaches stub code to each method. 2. For subsequent method calls, the stub directs program execution to the common language runtime component that is responsible for compiling a methods MSIL into native code. This component of the common language runtime is frequently referred to as the JIT compiler. 3. The JIT compiler compiles the MSIL and the methods stub is substituted with the address of the compiled code. Future calls to that method will not involve the JIT compiler because the compiled native code will simply execute.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 2: Introduction to a Managed Execution Environment

Application Domains
Topic Objective
To describe how application domains provide application isolation.
!

Lead-in
Historically, process boundaries have been used to isolate applications running on the same computer.
!

Historically, Process Boundaries Used to Isolate Applications In the Common Language Runtime, Application Domains Provide Isolation Between Applications
$

The ability to verify code as type-safe enables isolation at a much lower performance cost Several application domains can run in a single process

Faults in One Application Cannot Affect Other Applications

Historically, process boundaries have been used to isolate applications running on the same computer. Each application is loaded into a separate process, which isolates the application from other applications running on the same computer. The applications are isolated because memory addresses are process-relative; a memory pointer passed from one process to another cannot be used in any meaningful way in the target process. In addition, you cannot make direct calls between two processes. Instead, you must use proxies, which provide a level of indirection. Managed code must be passed through a verification process before it can be run (unless the administrator has granted permission to skip the verification). The verification process determines whether the code can attempt to access invalid memory addresses or perform some other action that could cause the process in which it is running to fail to operate properly. Code that passes the verification test is said to be type-safe. The ability to verify code as type-safe enables the common language runtime to provide as great a level of isolation as the process boundary, at a much lower performance cost. Application domains provide a secure and versatile unit of processing that the common language runtime can use to provide isolation between applications. You can run several application domains in a single process with the same level of isolation that would exist in separate processes, but without incurring the additional overhead of making cross-process calls or switching between processes. The ability to run multiple applications within a single process dramatically increases server scalability. Isolating applications is also important for application security. For example, you can run controls from several Web applications in a single browser process in such a way that the controls cannot access each other's data and resources.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

25

The isolation provided by application domains has the following benefits:


!"

Faults in one application cannot affect other applications. Because type-safe code cannot cause memory faults, using application domains ensures that code running in one domain cannot affect other applications in the process. Individual applications can be stopped without stopping the entire process. Using application domains enables you to unload the code running in a single application.

!"

Note You cannot unload individual assemblies or types. Only a complete domain can be unloaded. Code running in one application cannot directly access code or resources from another application. The common language runtime enforces this isolation by preventing direct calls between objects in different application domains. Objects that pass between domains are either copied or accessed by proxy. If the object is copied, the call to the object is local. That is, both the caller and the object being referenced are in the same application domain. If the object is accessed through a proxy, the call to the object is remote. In this case, the caller and the object being referenced are in different application domains. Crossdomain calls use the same remote call infrastructure as calls between two processes or between two computers.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 2: Introduction to a Managed Execution Environment

Multimedia: Application Loading and Single-File Assembly Execution


Topic Objective
To describe how assembly code is executed.

Lead-in
In this demonstration, you will see how a single-file private assembly is loaded and executed.

Delivery Tip
To launch the animation, click the button in the lower left corner of the slide. The animation plays automatically. To pause or rewind the animation, click the controls in the lower left of the screen.

Applications that are implemented by using MSIL code require the common language runtime to be installed on the users computer in order to run. The common language runtime manages the execution of code. For example, when an application that is implemented as a single-file private assembly is run, the following tasks are performed:
!"

The Microsoft Windows loader loads the PE file. The PE file contains a call to a function found in the file MSCorEE.dll. Windows loads the file MSCorEE.dll and transfers control to it to initialize the common language runtime. The common language runtime parses the metadata of the application assembly, and then the JIT compiler compiles the code. The common language runtime then locates the PE files managed entrypoint (the main method in the case of a C# program), and transfers control to this entry point.

!"

!"

!"

If the application calls a private assembly:


!"

The common language runtime uses probing to locate the referenced assembly, beginning in the applications root directory and then traversing the subfolders until the assembly is located. If the assembly is not found, a TypeLoadException error occurs. If the assembly is found, it is loaded by the common language runtime.

The common language runtime loader parses the manifest in the referenced assembly. The JIT compiler then compiles the required code in the assembly and passes control to the called function.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

27

Garbage Collection
Topic Objective
To introduce memory and resource management in the .NET Framework.
!

Lead-in
Every program uses resources, such as files, screen space, network connections, and database resources.
!

Garbage Collection Provides Automatic Object Memory Management in the .NET Framework You No Longer Need to Track and Free Object Memory

This topic introduces memory management in the .NET Framework. For more information about memory and resource management, see Module 9, Memory and Resource Management, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

Current Memory Management Model


When you create an object programmatically, you generally follow these steps: 1. Allocate memory for the object 2. Initialize the memory 3. Use the object 4. Perform cleanup on the object 5. Free the objects memory If you forget to free memory when it is no longer required or try to use memory after it has been freed, you can generate programming errors. The tracking and correction of such errors are complicated tasks because the consequences of the errors are unpredictable.

Memory Management in the .NET Framework


The common language runtime uses a heap called the managed heap to allocate memory for all objects. This managed heap is similar to a C-Runtime heap, however you never free objects from the managed heap. In the common language runtime, garbage collection is used to manage memory deallocation. The garbage collection process frees objects when they are no longer needed by the application For more information about garbage collection, see Module 9, Memory and Resource Management, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

28

Module 2: Introduction to a Managed Execution Environment

Lab 2: Building a Simple .NET Application


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will learn how to write, compile, and run a simple application in C# and Visual Basic, and how to use the MSIL Disassembler to examine an assembly.

Objectives
After completing this lab, you will be able to:
!" !"

Write, compile, and run a simple application in C#. Use the MSIL Disassembler to examine an assembly.

Lab Setup
Only solution files are associated with this lab. The solution files for this lab are in the folder <install folder>\Labs\Lab02\Solution.

Estimated time to complete this lab: 15 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

29

Exercise 1 Creating the Program in C#


In this exercise, you will create the source code for a small console application that takes user input and writes a string to the console by using C#. The lab uses the classic Hello, World application to allow you to focus on basic concepts in a managed execution environment. To help you concentrate on the syntactical aspects of this lab, you will use Notepad to create and edit the source files. From a command window prompt, you will then compile the application and test the resulting executable program.

!" write the source code To


1. Open Notepad and create a class in C# called MainApp. 2. Import the System namespace. 3. Define the program entry point. The entry point takes no arguments and does not return a value. 4. Create methods that accomplish the following: a. Print the following text to the console: Type your name and press Enter. b. Read in the resulting user input. c. Print the text Hello and append to the text the value that was read in. 5. Save the file as HelloLabCS.cs in the <install folder>\Labs\Lab02 folder.

!" build and test the program To


1. From a command prompt window, type the syntax to build an executable program from HelloLabCS.cs. 2. Run the resulting executable program. Your C# program should generate the following output:
Type your name and press Enter.

When you press ENTER, the program outputs the text Hello and whatever text you typed as input.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

30

Module 2: Introduction to a Managed Execution Environment

Exercise 2 Using the MSIL Disassembler


In this exercise, you will use the MSIL Disassembler to open a single assembly and familiarize yourself with the assembly manifest. In subsequent labs, you will explore assemblies in greater detail.

!" examine the metadata for the Hello, World applications To


1. From a command prompt window, type:
>ildasm /source

2. Open HelloLabCS.exe and double-click the Manifest icon. 3. Note the following: a. The externally referenced library named mscorlib b. The assembly name HelloLabCS c. Version information (for the HelloLabCS assembly and mscorlib) 4. Close the Manifest window, double-click the MainApp icon, double-click the Main icon, and view the MSIL and source code.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 2: Introduction to a Managed Execution Environment

31

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! !

Writing a .NET Application Compiling and Running a .NET Application

Lead-in
The review questions cover some of the key concepts taught in the module.

1. Name the root namespace for types in the .NET Framework. The System namespace is the root namespace for types in the .NET Framework.

2. What class and methods can your application use to input and output to the console? You can use the common language runtimes Console class of the System namespace for input and output to the console of any string or numeric value by using the Read, ReadLine, Write, and WriteLine methods.

3. When compiling code that makes references to classes in assemblies other than mscorlib.dll what must you do? You must use the /reference compilation switch. The /reference compilation option allows the compiler to make information in the specified libraries available to the source that is currently being compiled. The /r switch is equivalent to /reference.

4. What is the code produced by a .NET compiler called? Microsoft intermediate language (MSIL), sometimes called managed code.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

32

Module 2: Introduction to a Managed Execution Environment

5. What .NET component compiles MSIL into CPU specific native code? The just-in-time (JIT) compiler.

6. What feature of .NET ensures that object memory is freed? The garbage collection process.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components


Contents Overview An Introduction to Key .NET Framework Development Technologies Creating a Simple .NET Framework Component Lab 3.1: Creating a .NET Framework Component Creating a Simple Console Client Lab 3.2: Creating a Simple Console-Based Client Demonstration: Creating a Windows Forms Client Creating an ASP.NET Client Multimedia: ASP.NET Execution Model Lab 3.3: Calling a Component Through an ASP.NET Page Review 1 2 4 11 13 18 21 25 26 34 38

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

iii

Instructor Notes Module 3


Presentation: 75 Minutes Lab: 60 Minutes After completing this module, students will be able to:
!" !" !"

Create a simple Microsoft .NET Framework component in C#. Implement structured exception handling. Create a simple .NET Framework console application that calls a component. Create a .NET Framework client application by using the Windows Forms library. Create an ASP.NET page that uses the previously developed .NET Framework component to create an ASP.NET application.

!"

!"

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_03.ppt

Preparation Tasks
To prepare for this module, you should:
!" !" !" !"

Read all of the materials for this module. Practice the demonstration. Review the animation. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 3: Working with Components

Demonstration
This section provides demonstration procedures that will not fit in the margin notes or are not appropriate for the student notes.

Creating a Windows Forms Client


This demonstration shows how to build a simple Windows Forms client in Visual Studio .NET. If time permits, you can show the demonstration by using Visual Basic. The solution code for this demonstration is located in <install folder>\DemoCode\Mod03\C# and <install folder>\DemoCode\Mod03\VB. In this demonstration, point out how the windows form is created in the Main method. Also point out how the Windows Forms Designer adds code to create and initialize the controls. Consider stepping through the code to explain the code to students.

!" create a Windows Form To


1. Open Visual Studio .NET and create a Visual C# project from the Windows Application template. Name the project WinForm_Client. 2. Add two buttons and a listbox to the form. Set the following properties. a. Set the button1 Text property to &Execute. b. Set the button2 Text property to &Close. c. Set the Form1 Text property to Client.

!" add references To


1. Select Add Reference from the Project menu. 2. In the Add Reference dialog box, click the Browse button. 3. Select the CompCS.dll and CompVB.dll assemblies as references. These assemblies are located in <install folder>\DemoCode\Mod03\C#. Then click the Open button. 4. Click OK. 5. Add references to the assemblies in the form code. Use aliases to avoid name conflicts.
using CSStringComp = CompCS.StringComponent; using VBStringComp = CompVB.StringComponent;

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

!" add button event handlers To


1. In the form, double-click the Execute button to create a button-click event handler. 2. Add the following code to the event handler to create an instance of the C# component and Visual Basic component, and add their strings to the listbox.
//Local Variables CSStringComp myCompCS = new CSStringComp(); VBStringComp myCompVB = new VBStringComp(); int stringCount=0; //Display results from C# Component for (stringCount=0; stringCount<myCompCS.Count;! stringCount++) { listBox1.Items.Add(myCompCS.GetString(stringCount)); } //Display results from Visual Basic Component for (stringCount=0; stringCount<myCompVB.Count;! stringCount++) { listBox1.Items.Add(myCompVB.GetString(stringCount)); }

3. In the form, double-click the Close button to create a button-click event handler. 4. In the Close button event handler, call the Close method to close the form. 5. Compile and run the application. When you click the Execute button, the listbox should be filled with four C# strings and four Visual Basic strings.

Testing the ASP.NET Client


To test the ASP.NET page, the following software must be installed on the test computer:
!" !" !" !"

Microsoft Internet Information Services (IIS) The .NET Framework common language runtime The .aspx file that contains the client code All compiled components that are required by the client application

You must configure a virtual directory that points to the directory that contains the .aspx file. You can use the New Directory Wizard in the IIS snap-in to do this.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

vi

Module 3: Working with Components

!" configure a virtual directory To


1. Click the Start menu, point to Programs, point to Administrative Tools, and then click Internet Services Manager. 2. Expand the computer icon, and then expand and select Default Web Site. 3. Click the Action menu, point to New, and then click Virtual Directory. The Virtual Directory Creation Wizard is launched. 4. Click Next to continue. 5. In the Alias text box, type Test, and click Next. 6. Browse to the StudentCD\Labs\Lab03.3\SOLUTION\ASP.NET_Client folder that contains the file ClientASP.NET.aspx, and then click Next. 7. On the Access Permissions page, accept the default selections, click Next, and then click Finish. The Test folder is added to the Default Web Site. Ensure that the compiled component DLLs, CompCS.dll and CompVB.dll, are in a \Bin subdirectory under the starting point for the application virtual directory.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

vii

!" test the ASP.NET Client To


Open Microsoft Internet Explorer, and type the following text in the Address bar: http://localhost/Test/ClientASP.NET.aspx When you press ENTER, the following display, or one similar to it, appears.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

viii

Module 3: Working with Components

Module Strategy
Use the following strategy to present this module:
!"

An Introduction to Key .NET Framework Technologies Briefly introduce Windows Forms, Web Forms, and Web Services. Explain that you will show an example of a Windows Form in this module. Tell students that they will learn about Web Services in Module 13, Remoting and Web Services, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

!"

Creating a Simple .NET Framework Component Show the basic approach to creating reusable classes by using C# and Visual Basic. Spend some time on the new structured exception handling techniques. Use the command line to compile the component. Break the lecture at this point and instruct students to do Lab 3.1, Creating a .NET Framework Component.

!"

Creating a Simple Console Client Show how to write a simple console application that calls the .NET Framework runtime-compatible component that was created in Creating a Simple .NET Framework Component. Be sure to fully explain how to use a namespace alias to remove ambiguity to type references. Instruct students to do Lab 3.2, Creating a Simple Console-Based Client.

!"

Creating an ASP.NET Client Emphasize the .NET Frameworks capability to execute the component code that was created in Creating a Simple .NET Framework Component in a variety of environments. Contrast the use of the component by the standalone client applications with that of a IIS ASP.NET page. Be sure to present the ASP.NET Execution Model animation to help students understand how ASP.NET pages are processed on the server. Instructions for running the animation are included in the Instructor Notes in the margins. The main objective of this section is to show students how to use an ASP.NET page to obtain the string data from the .NET Framework component, to format that data in HTML, and to return this HTML to a Web browser for display. Be sure to demonstrate how to test the ASP.NET page that was created in Creating an ASP.NET Client in this module. Students must understand how to configure a virtual directory that points to the directory that contains the .aspx file. Instruct students to do Lab 3.3, Calling a Component Through an ASP.NET Page.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

Overview
Topic Objective
To provide an overview of the module topics and objectives.
!

Lead-in
In this module, you will learn how to create a small client/server application.
! ! !

An Introduction to Key .NET Framework Development Technologies Creating a Simple .NET Framework Component Creating a Simple Console Client Creating an ASP.NET Client

For Your Information


Tell students that the code examples used in this module are from the tutorial, Introduction to Developing with the .NET Framework.

In this module, you will learn how to create a small client/server application in C#. The steps necessary to construct, compile, and run each program are covered in detail. You will also learn how to build the client application by using the Windows Forms library and an ASP.NET page. As in Module 2, Introduction to a Managed Execution Environment in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease), the content of this module is based on the Introduction to Developing with the .NET Framework tutorial in the .NET Framework Software Developers Kit (SDK). After completing this module, you will be able to:
!" !" !"

Create a simple Microsoft .NET Framework component in C#. Implement structured exception handling. Create a simple .NET Framework console application that calls a component. Create a .NET Framework client application by using the Windows Forms library. Create an ASP.NET page that uses the previously developed .NET Framework component to create an ASP.NET application.

!"

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

An Introduction to Key .NET Framework Development Technologies


Topic Objective
To introduce the technologies that are used to develop .NET Framework applications.
! ! !

Windows Forms Web Forms XML Web Services

Lead-in
To develop applications in the .NET Framework, you should be familiar with Windows Forms, ASP.NET Web Forms, and Web Services.

To develop applications in the .NET Framework, you should be familiar with the following technologies: Windows Forms, ASP.NET Web Forms, and Web Services. Your choice of technology, or technologies, depends on the type of software solution that you wish to implement. This topic briefly introduces the technologies and provides references to additional information.

Windows Forms
Windows Forms are used to develop applications in which the client computer handles most of the application processing. Classic Microsoft Win32 desktop applications, such as drawing and graphics applications, data-entry systems, point-of-sale systems, and games, are well suited to Window Forms. All of these applications rely on the power of the desktop computer for processing and for high-performance content display. The System.Windows.Forms namespace contains the classes used to create Windows Forms.

Web Forms
ASP.NET Web Forms are used to create applications in which the primary user interface is a browser. Obviously, you can use Web Forms to create applications that are available on the World Wide Web, such as e-commerce applications, but you will also find them helpful for creating other types of applications, such as intranet applications, which users can run by using only their browser, which is already installed on their computers. Because Web Forms applications are platform-independent, users can interact with your application regardless of the type of browser or computer that they are using. You can also optimize Web Forms applications to use features that are built into the most recent browsers, such as Dynamic Hypertext Markup Language (DHTML) and HTML 4.0, which enhance performance and responsiveness.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

The System.Web namespace contains the classes used to create Web Forms. For more information about Windows Forms and ASP.NET Web Forms, see Windows Forms and Web Forms Recommendations in the .NET Framework SDK documentation.

XML Web Services


An XML Web Service is a programmable entity that resides on a Web server and is exposed through standard Internet protocols. In many respects, the programming model for creating and using Web Services is similar to the programming model for creating and using COM-based components. However, unlike COM, the Web Services programming model is based on simple, open standards that are broadly supported. Instead of using binary communication methods between applications, Web Services use communication based on the SOAP protocol to transport XML messages between applications. In an environment of integrated, programmable Web Services, XML is the universal language for communication of raw data and information that can be understood and acted upon. For more information about Web Services, see Module 13, Remoting and Web Services in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

# Creating a Simple .NET Framework Component


Topic Objective
To provide an overview of the section topics.
! ! ! ! !

Lead-in
In this section, you will learn how to use C# to create a simple component.

Using Namespaces and Declaring the Class Creating the Class Implementation Implementing Structured Exception Handling Creating a Property Compiling the Component

In this section, you will learn how to create a simple component using C#. The component provides a wrapper for an array of strings and includes a GetString method that takes an integer and returns a string. The component includes a read-only Count property that contains the number of elements in the string array, which is used to iterate over all of the array members. The GetString method also demonstrates the use of structured exception handling. Delivery Tip
If you prefer, you can use Notepad to demonstrate the code in this section, instead of discussing the content of each slide.

In subsequent sections of this module, you will learn how clients use the GetString method and the Count property to determine and display the output from the components string array. The simple string component that is described in this section shows the basic approach to creating reusable classes in C#.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

Using Namespaces and Declaring the Class


Topic Objective
To explain how to create a new namespace that encapsulates classes.
!

Create a New Namespace


using System; using System; namespace CompCS {...} namespace CompCS {...}

Lead-in
To create a new namespace that encapsulates the classes that you will be creating, you use the namespace statement.

Declare the Class


public class StringComponent {...} public class StringComponent {...}

To create a new namespace that encapsulates the classes that you will be creating, you use the namespace statement, as in the following example:
using System; namespace CompCS {...}

The following statement denotes that instances of the StringComponent class will now be created by the runtime and managed in the garbage-collected heap.
public class StringComponent {...}

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

Creating the Class Implementation


Topic Objective
To explain how to create the class implementation.
!

Declare a Private Field of Type Array of String Elements


private string[] stringSet; private string[] stringSet;

Lead-in
The component provides a wrapper for an array of strings.
!

Create a Public Default Constructor


public StringComponent() {...} public StringComponent() {...}

Assign the stringSet Field to an Array of Strings


stringSet = new string[] { stringSet = new string[] { "C# String 0", "C# String 0", "C# String 1", "C# String 1", ... ... }; };

The component provides a wrapper for an array of strings. You can declare a private field of type array of string elements, as in the following example:
private string[] stringSet;

The following example shows how to create a public default constructor, which executes each time a new instance of the class is created, and how to assign the stringSet field to an array of strings:
public StringComponent() { stringSet = new string[] { "C# String 0", "C# String 1", "C# String 2", "C# String 3" }; }

In the preceding example, you can see that the constructor has the same name as the class and does not have a return type.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

Implementing Structured Exception Handling


Topic Objective
To explain how to implement structured exception handling.
!

Implement the GetString Method

public string GetString(int index) {...} public string GetString(int index) {...}
!

Lead-in
The component uses the GetString method to return the strings in the stringSet array.

Create and Throw a New Object of Type IndexOutOfRangeException

if((index < 0) || (index >= stringSet.Length)) { if((index < 0) || (index >= stringSet.Length)) { throw new IndexOutOfRangeException(); throw new IndexOutOfRangeException(); } } return stringSet[index]; return stringSet[index]; ! Exceptions May Be Caught by the Caller in try, catch, finally block
!

Structured Exception Handling Replaces HRESULT-Based Error Handling in COM

Programs must be able to uniformly handle errors and exceptions that occur during execution. The common language runtime helps you design errortolerant software by providing a platform for notifying programs of errors in a uniform manner. All .NET Framework methods indicate failure by throwing exceptions. Traditionally, a languages error-handling model relied on either the languages unique way of detecting errors and locating handlers for them, or on the errorhandling mechanism that is provided by the operating system. The runtime implements exception handling with the following features:
!"

It handles exceptions without regard for the language that generates the exception or the language that will be called upon to handles the exception. It does not require any particular language syntax for handling exceptions, but allows each language to define its own syntax. It allows exceptions to be thrown across process boundaries and machine boundaries.

!"

!"

Exceptions offer several advantages over other methods of error notification. Failures do not go unnoticed. Invalid values do not continue to propagate through the system. You do not have to check return codes. Exception-handling code can be easily added to increase program reliability. Finally, the runtimes exception handling is faster than Windows-based C++ error handling.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

The component uses the GetString method to return the strings in the stringSet array. You can use a throw statement to implement structured exception handling within the GetString method, as in the following example:
public string GetString(int index) { if ((index < 0) || (index >= stringSet.Length)) { throw new IndexOutOfRangeException(); } return stringSet[index]; }

In the preceding example, the program evaluates whether the integer that is passed as an argument to GetString is a valid index for the stringSet array. If the index is invalid, the following statement creates and throws a new object of type IndexOutOfRangeException:
throw new IndexOutOfRangeException();

If the index is valid, the program returns the string element of the stringSet array at that particular index. Exceptions may be caught by the caller by using a try/catch/finally block. Place the sections of code that might throw exceptions in a try block and place code that handles exceptions in a catch block. You can also write a finally block that always runs regardless of how the try block runs. The finally block is useful for cleaning up resources after a try block. For example, in C#:
try { // code that might } catch(Exception e) // place code that } finally { // place code that } throw exceptions { handles exceptions

runs after try or catch runs

In general, it is good programming practice to catch a specific type of exception rather than using the general catch statement above that catches any exception. Structured exception handling replaces the HRESULT-based error-handling system that is used in COM. All .NET Framework exception-handling classes, such as IndexOutOfRangeException() and user-defined exceptions, must derive from System.Exception. For more information about exception handling, see Handling and Throwing Exceptions in the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

Creating a Property
Topic Objective
To explain how to create a property.
!

Create a Read-Only Count Property to Get the Number of String Elements in the stringSet Array
public int Count { public int Count { get { return stringSet.Length; } get { return stringSet.Length; } } }

Lead-in
To provide the number of string elements in the stringSet array in C#, you create a read-only property called Count.

To provide the number of string elements in the stringSet array, you create a read-only property called Count, as in the following example:
public int Count { get { return stringSet.Length; } }

For Your Information


Point out that the GetString method and Count property may be used by a client to iterate over the components string elements. This information will help students when they create the clients in subsequent labs.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 3: Working with Components

Compiling the Component


Topic Objective
To explain how to compile the source code for a component.
!

Use the /target:library Switch to Create a DLL


$

Lead-in
To compile the source code, first you must save the source file.

Otherwise, an executable with a .dll file extension is created instead of a DLL library

csc /out:CompCS.dll /target:library CompCS.cs csc /out:CompCS.dll /target:library CompCS.cs

To compile the source code for the C# component, first you must save the source file, and then enter the following command from a command prompt window:
csc /out:CompCS.dll /target:library CompCS.cs

This command directs the compiler to produce the file CompCS.dll. The /target:library switch is required to actually create a DLL library, instead of an executable.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

11

Lab 3.1: Creating a .NET Framework Component


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will learn how to create a simple .NET Framework component in C#.

For Your Information


In this introductory module, the lab problems have intentionally been made very similar to the problems presented in the module. This approach is designed to allow the student to experience a wide range of .NET software approaches within a very limited amount of time.

Objective
After completing this lab, you will be able to create a simple .NET Framework component in C#.

Lab Setup
Only solution files are associated with this lab. The solution files for this lab are in the folder <install folder>\Labs\Lab03.1\Solution.

Scenario
This lab is based on a small client server application scenario in which you write both the client application and server component using C#. This lab focuses on building the server component. Lab 3.2, Creating a Simple Console-Based Client, focuses on building a client program that calls the server component.

Estimated time to complete this lab: 15 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 3: Working with Components

Exercise 1 Creating a Component in C#


In this exercise, you will use C# to create a component that provides a wrapper for a private array of strings. The wrapper includes a read-only Count property, which returns the number of strings in the array, and a public GetString method, which takes an integer argument and returns the string in the private array at that index. The GetString method will also implement structured exception handling to ensure that the argument of the index is within range of the array.

!" specify namespace information and class declarations To


1. Open Notepad and reference the System namespace. 2. Create a new namespace named CompCS. CompCS will contain the class for your component.

!" create the class implementation To


1. Create a public class named StringComponent. 2. Declare a private field named StringSet of type array of string elements. 3. Create a public default constructor. The default constructor takes no arguments. 4. Assign to the field StringSet an array of strings initialized with the following four strings:
"C# "C# "C# "C# String String String String 0", 1", 2", 3"

5. Create the public GetString method, which takes an integer as an argument. That integer must be a valid index for the StringSet array. a. If the integer is an invalid index, throw an index out of range exception. b. If the integer is a valid index, return the StringSet string at that index. 6. Create a read-only Count property that gets the number of string elements in the StringSet array. 7. Save the file as CompCS.cs in the <install folder>\Labs\Lab03.1 folder.

!" compile the source code To


From a command prompt window, enter the command to build a library named CompCS.dll from the CompCS.cs. source. You must specify that the target is a library.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

13

# Creating a Simple Console Client


Topic Objective
To provide an overview of the section topics.
! ! ! !

Lead-in
In this section, you will learn how to write a simple console application that calls a .NET Framework runtime-compatible component.

Using the Libraries Instantiating the Component Calling the Component Building the Client

In this section, you will learn how to write a simple console application that calls the .NET Framework runtime-compatible component that was created in the previous section.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 3: Working with Components

Using the Libraries


Topic Objective
To explain how to import libraries and to use namespace aliasing to remove ambiguity.
!

Reference Types Without Having to Fully Qualify the Type Name


using CompCS; using CompCS; using CompVB; using CompVB;

Lead-in
By using the namespaces in the program, you can reference types in the library without fully qualifying the type name.

If Multiple Namespaces Contain the Same Type Name, Create a Namespace Alias to Remove Ambiguity

using CSStringComp = CompCS.StringComponent; using CSStringComp = CompCS.StringComponent; using VBStringComp = CompVB.StringComponent; using VBStringComp = CompVB.StringComponent;

This topic explains how to reference types in your applications by using namespaces and how to use a namespace alias if you need to remove ambiguity to type references.

Using the Namespaces


By using the namespaces in the program, you can reference types in the library without fully qualifying the type name. To use the component namespaces in C#, you must enter a using statement followed by the name of the component namespaces:
using CompCS; using CompVB;

Using an Alias
Consider a scenario where similar C# and Microsoft Visual Basic components use the same type name (StringComponent). You must still fully qualify the type name to remove any ambiguity when referring to the GetString method and the Count property. In C#, you can create and use aliases to solve this problem. The following C# example shows how to alias the component namespaces so that you do not have to fully qualify the type names:
using CSStringComp = CompCS.StringComponent; using VBStringComp = CompVB.StringComponent;

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

15

Instantiating the Component


Topic Objective
To describe how to instantiate the component in C#.
! !

Declare a Local Variable of Type StringComponent Create a New Instance of the StringComponent Class

Lead-in
To instantiate the StringComponent class, you declare a local variable of type StringComponent and create a new instance of StringComponent.

CompCS.StringComponent myCSStringComp = new CompCS.StringComponent myCSStringComp = new CompCS.StringComponent(); CompCS.StringComponent();

To instantiate the StringComponent class, you declare a local variable of type StringComponent and create a new instance of StringComponent, as in the following example:
using CompCS; class MainApp { public static void Main() { CompCS.StringComponent myCSStringComp = new CompCS.StringComponent(); ... } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 3: Working with Components

Calling the Component


Topic Objective
To describe how to call a component after it has been instantiated.
!

Iterate over All the Members of StringComponent and Output the Strings to the Console

Lead-in
After instantiating the StringComponent class, the client can iterate over the string array in the C# or Visual Basic component and return the appropriate output.

for (int index = 0; for (int index = 0; index < myCSStringComp.Count; index++) { index < myCSStringComp.Count; index++) { Console.WriteLine Console.WriteLine (myCSStringComp.GetString(index)); (myCSStringComp.GetString(index)); } }

After instantiating the StringComponent class, the client can iterate over the string array in the component and return the appropriate output, as in the following example:
using System; using CompCS; class MainApp { public static void Main() { StringComponent myCSStringComp = new StringComponent(); // Display result strings from CS component Console.WriteLine("Strings from CS StringComponent"); for (int index = 0; index < myCSStringComp.Count; index++) { Console.WriteLine(myCSStringComp.GetString(index)); } } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

17

Building the Client


Topic Objective
To show how to build the client in C#.
!

Lead-in
To build the client, you can compile the source code from a command prompt window.

Use the /reference Switch to Reference the Assemblies That Contain the StringComponent Class
csc /reference:CompCS.dll,CompVB.dll! csc /reference:CompCS.dll,CompVB.dll! /out:ClientCS.exe ClientCS.cs /out:ClientCS.exe ClientCS.cs

To build the client, you can compile the source code from a command prompt window. You must use the /reference option to reference all of the assemblies that contain the StringComponent class, as in the following example:
csc /reference:CompCS.dll,CompVB.dll! /out:ClientCS.exe ClientCS.cs

Running a client program that first iterates over the C# components strings and then iterates over the Visual Basic components strings will produce the following output:
Strings from C# StringComponent C# String 0 C# String 1 C# String 2 C# String 3 Strings from VB StringComponent VB String 0 VB String 1 VB String 2 VB String 3

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 3: Working with Components

Lab 3.2: Creating a Simple Console-Based Client


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will learn how to create a simple console-based client application that calls a component.

Objectives
After completing this lab, you will be able to create a simple console-based client application that calls a component.

Lab Setup
To complete this lab you will need the solution files from Lab 3.1 and a Visual Basic component provided for you in the <install folder>\Labs\Lab03.2\Starter\VB\Component folder. The solution files for this lab are located in <install folder>\Labs\Lab03.2\Solution.

Scenario
This lab is based on a small client/server application scenario in which both the client application and server component are written by using C#. This lab focuses on building a simple console-based client application that calls the component that was created in Lab 3.1, Creating a .NET Framework Component. Also, another version of the component written in Visual Basic is provided. The client will use both the C# and Visual Basic component versions to show cross-language compatibility.

Estimated time to complete this lab: 15 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

19

Exercise 1 Creating a Client Application in C#


In this exercise, you will create a simple console application to call the C# component that you created in Lab 3.1, Creating a .NET Framework Component, and a Visual Basic component that is already provided. The Visual Basic component provides the same StringComponent class as the C# component.

!" specify namespace information To


1. Open Notepad and import the System namespace. 2. Use the namespace of the C# component that you created in Lab 3.1, Creating a .NET Framework Component. 3. Copy the Visual Basic component from <install folder>\Labs\Lab03.2 \Starter\VB\Component to your working folder. 4. Use the namespace of the Visual Basic component. The namespace of the Visual Basic component is CompVB. Because you are importing two libraries that contain the same type name but have different namespaces, use an alias directive to allow for unambiguous references to StringComponent classes. 5. Create a class in C# called MainApp. 6. Specify the program entry point. The entry point takes no arguments and does not return a value.

!" write the code to call the C# and Visual Basic components To
1. Assign to a local variable named myCSStringComp a new instance of the C# version of StringComponent. 2. Write the code to print the following string to the console:
Strings from C# StringComponent

3. Iterate over all of the members of the C# string component and output the strings to the console. 4. Repeat steps 1 through 3 for the Visual Basic version of StringComponent. Name the local variable myVBStringComp. 5. Save the file as ClientCS.cs in the <install folder>\Labs\Lab03.2 folder.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 3: Working with Components

!" compile and run the program To


1. From a command prompt window, enter the command to build the executable program ClientCS.exe from ClientCS.cs. You must reference the assemblies that contain the C# and Visual Basic StringComponent class. You must copy these assemblies into the same directory as ClientCS.cs. The Visual Basic assembly is located in <install folder>\Labs\Lab03.2\Starter\VB\Component 2. Run the resulting executable program. Your C# program should generate the following output:
Strings from C# StringComponent C# String 0 C# String 1 C# String 2 C# String 3 Strings from VB StringComponent VB String 0 VB String 1 VB String 2 VB String 3

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

21

Demonstration: Creating a Windows Forms Client


Topic Objective
To demonstrate how to create a Windows Forms client.

Lead-in
In this demonstration, you will see how to create a Windows Forms client.

In previous sections of this course, all examples have been command-line programs that wrote to the system console. In this demonstration, you will learn how to rewrite the client application so it can use the new .NET Windows Forms library, which is available to all .NET Framework runtime-compatible languages. In this demonstration, the client displays in a listbox on a form the string output that was displayed in the system console in previous examples.
using using using using using using System; System.Drawing; System.Collections; System.ComponentModel; System.Windows.Forms; System.Data;

using CSStringComp = CompCS.StringComponent; using VBStringComp = CompVB.StringComponent; namespace WinForm_Client { /// <summary> /// Summary description for Form1. /// </summary> public class Form1 : System.Windows.Forms.Form { private System.Windows.Forms.Button button1; private System.Windows.Forms.Button button2; private System.Windows.Forms.ListBox listBox1; /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container! components = null;

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 3: Working with Components


public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); // // TODO: Add any constructor code after // InitializeComponent call // } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.button1 = new System.Windows.Forms.Button(); this.button2 = new System.Windows.Forms.Button(); this.listBox1 = new System.Windows.Forms.ListBox(); this.SuspendLayout(); // // button1 // this.button1.Location =! new System.Drawing.Point(24, 232); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(64, 24); this.button1.TabIndex = 0; this.button1.Text = "&Execute"; this.button1.Click +=! new System.EventHandler(this.button1_Click); // // button2 // this.button2.Location =! new System.Drawing.Point(192, 232); this.button2.Name = "button2";
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components


this.button2.Size = new System.Drawing.Size(64, 24); this.button2.TabIndex = 1; this.button2.Text = "&Close"; this.button2.Click +=! new System.EventHandler(this.button2_Click); // // listBox1 // this.listBox1.Location =! new System.Drawing.Point(8, 8); this.listBox1.Name = "listBox1"; this.listBox1.Size =! new System.Drawing.Size(264, 199); this.listBox1.TabIndex = 2; // // Form1 // this.AutoScaleBaseSize =! new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 273); this.Controls.AddRange! (new System.Windows.Forms.Control! { this.listBox1, this.button2, this.button1}); this.Name = "Form1"; this.Text = "Client"; this.ResumeLayout(false); } #endregion /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.Run(new Form1()); } private void button1_Click(object sender,! System.EventArgs e) { //Local Variables CSStringComp myCompCS = new CSStringComp(); VBStringComp myCompVB = new VBStringComp(); int stringCount=0;

23

//Display results from C# Component for (stringCount=0; stringCount<myCompCS.Count;! stringCount++) { listBox1.Items.Add(myCompCS.GetString(stringCount)); }


BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 3: Working with Components


//Display results from Visual Basic Component for (stringCount=0; stringCount<myCompVB.Count;! stringCount++) { listBox1.Items.Add(myCompVB.GetString(stringCount)); } } private void button2_Click(object sender,! System.EventArgs e) { Close(); } } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

25

# Creating an ASP.NET Client


Topic Objective
To provide an overview of the section topics.
! ! !

Lead-in
In this section, you will learn how to use an ASP.NET page to obtain the string data from the .NET Framework component, to format the data in HTML, and to return this HTML to a Web browser for display.

Writing the HTML for the ASP.NET Application Coding the Page_Load Event Handler Generating the HTML Response

In this module, you have learned how to create two standalone versions of a client application that calls the simple string component: a console application, and a form based on the Windows Forms library. Another important feature of the .NET Framework is the capability to execute the component code that was used by such standalone client applications in a Microsoft Internet Information Services (IIS) ASP.NET page. In this section, you will learn how to use an ASP.NET page to obtain the string data from the .NET Framework component, to format that data in HTML, and to return this HTML to a Web browser for display.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 3: Working with Components

Multimedia: ASP.NET Execution Model


Topic Objective
To describe the ASP.NET execution model.

Lead-in
In this animation, you will see how ASP.NET pages are processed on the server.

To launch the animation, click the button in the lower left corner of the slide. To play the animation, click the Start button, and then click the First Request, Second Request, and Output Cache buttons at the top of the screen. There is no audio, but explanatory text appears in the Info column when you click one of the buttons.

The .NET Framework provides the capability to execute code that was used in the preceding standalone client applications in an ASP.NET page. However, there are some differences in the code execution processes. An ASP.NET page generally produces HTML in response to a Hypertext Transfer Protocol (HTTP) request; and the page itself is compiled dynamically, unlike the standalone client applications. Each ASP.NET page is individually parsed, and the syntax is checked. Then, a .NET runtime class is produced, compiled, and invoked. ASP.NET caches the compiled object, so subsequent requests do not perform the parse and compile step and thus execute much faster. In this animation, you will see how ASP.NET pages are processed on the server. To view the animation, open the 2349A_mod3.htm file from the Media folder.

Tell students that they can view the animation again later for themselves by opening the 2349A_mod3.htm file from the Media folder.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

27

Writing the HTML for the ASP.NET Application


Topic Objective
To describe how to write the HTML for an ASP.NET application.
!

Specify Page-Specific Attributes Within a Page Directive

<%@ Page Language="C#" Description="ASP.NET Client" %> <%@ Page Language="C#" Description="ASP.NET Client" %>
!

Lead-in
An ASP.NET file is a text file that contains markup syntax for coding server-side page logic, dynamic output, and literal content.

Import the Namespace and the Physical Assembly


<%@ Import Namespace="CompCS"%> <%@ Import Namespace="CompCS"%> <%@ Import Namespace="CompVB"%> <%@ Import Namespace="CompVB"%>

Specify Code Declaration Blocks


<script language="C#" runat=server> <script language="C#" runat=server> ... //client code ... //client code </script> </script>

An ASP.NET file is a text file that contains markup syntax for coding serverside page logic, dynamic output, and literal content. By default, ASP.NET files have an .aspx extension or .ascx for user controls. However, ASP.NET will parse and compile any file that is mapped to the aspnet_isapi.dll under IIS.

Specifying @ Page Directives


To create the ASP.NET page that calls the string component, you first specify page-specific attributes within a page directive. Page directives specify optional settings that are used by the page compiler when processing ASP.NET files, as shown in the following example:
<%@ Page Language="C#" Description="ASP.NET Client" %>

The following table describes the two @ Page directive attributes that are used in the sample client ASP.NET page.
Attribute Language Description Description Language that is used when compiling all <% %> and <%= %> blocks within a page. Can be Visual Basic, C#, or Microsoft JScript .NET. Provides a text description of the page. Supports any string description.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

28

Module 3: Working with Components

Specifying @ Import Directives


After specifying a @ Page directive, you include an @ Import directive, which explicitly imports a namespace into a page, as in the following example:
<%@ Import Namespace="CompCS"%> <%@ Import Namespace="CompVB"%>

When you use an @ Import directive to import a namespace into a page, all classes and interfaces of the imported namespace are made available to the page. The imported namespace can be part of the .NET Framework class library or a user-defined namespace. In addition, the @ Import directive specifies the name of the assembly that will be used. The assembly must be located in the \Bin subdirectory of the applications starting point.

Specifying Code Declaration Blocks


After specifying @ Page directives and importing the required namespaces, you add code declaration blocks in which you place the code that calls the string component in the ASP.NET page. You define code declaration blocks by using <script> tags that contain a runat attribute, which tells the server to execute the code on the server, instead of sending the code text back to the client as part of the HTML stream. The script element may optionally use a language attribute to specify the language of its inner code, as in the following example:
<html> //... <script language="C#" runat=server> ... //client code </script> //... </html>

If you do not specify a language, ASP.NET defaults to the language that was configured for the base page, which is determined by the @ Page directive. For more information about directives in ASP.NET, see Directive Syntax in the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

29

Coding the Page_Load Event Handler


Topic Objective
To explain how to code the Page_Load event handler. void Page_Load(Object sender, EventArgs EvArgs) void Page_Load(Object sender, EventArgs EvArgs) { { StringBuilder Out = new StringBuilder(""); StringBuilder Out = new StringBuilder(""); int Count = 0; int Count = 0; // Iterate over component's strings and concatenate // Iterate over component's strings and concatenate Out.Append("Strings from C# Component<br>"); Out.Append("Strings from C# Component<br>"); CompCS.StringComponent myCSStringComp = new CompCS.StringComponent myCSStringComp = new CompCS.StringComponent(); CompCS.StringComponent(); for(int index = 0; index < myCSStringComp.Count; for(int index = 0; index < myCSStringComp.Count; index++) index++) { { Out.Append(myCSStringComp.GetString(index)); Out.Append(myCSStringComp.GetString(index)); Out.Append("<br>"); Out.Append("<br>"); } } Message.InnerHtml = Out.ToString(); Message.InnerHtml = Out.ToString(); } }

Lead-in
The Page_Load event contains most of the code for the sample client program.

The Page_Load event contains most of the code for the sample client program.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

30

Module 3: Working with Components

The following example shows the Page_Load event-handling code:


void Page_Load(Object sender, EventArgs EvArgs) { StringBuilder Out = new StringBuilder(""); int Count = 0; // Iterate over component's strings and concatenate Out.Append("Strings from C# Component<br>"); CompCS.StringComponent myCSStringComp = new CompCS.StringComponent(); for(int index = 0; index < myCSStringComp.Count; index++) { Out.Append(myCSStringComp.GetString(index)); Out.Append("<br>"); } Out.Append("<br>"); // Iterate over component's strings and concatenate Out.Append("Strings from VB Component<br>"); CompVB.StringComponent myVBStringComp = new CompVB.StringComponent(); for(int index = 0; index < myVBStringComp.Count; index++) { Out.Append(myVBStringComp.GetString(index)); Out.Append("<br>"); } Message.InnerHtml = Out.ToString(); }

Notice that the client code that calls the string component is very similar to the code for the standalone console and Windows Forms-based applications. After declaring the Page_Load event handler and initializing variables, you create a new instance of the StringComponent class and iterate over the string array. Each of the strings is appended to the variable Out. You then assign Out to a property of an HTML server control, as in the following example:
Message.InnerHTML = Out.ToString();

Instead of assigning Out to a property of an HTML server control, you can use Response.Write to write the stream directly into the HTML stream. Note It is a recommended practice with ASP.NET forms to place the executable code in a separate file from the declarative HTML. However, for the sake of simplicity, the code for the ASP.NET page in this module has not been placed in a separate file.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

31

Generating the HTML Response


Topic Objective
To show how to generate the HTML response by using the Message object.
!

Specify the Body of the HTML Response

Lead-in
The following example shows how to create the HTML response by using the Message object.

<body> <body> <span id="Message" runat=server/> <span id="Message" runat=server/> </body> </body>

The following example shows how to create the HTML response by using the Message object:
<body> <span id="Message" runat=server/> </body>

This code places the string output that was generated by the Page_Load event handler in the HTTP response.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

32

Module 3: Working with Components

The code for the final ASP.NET page is as follows:


<%@ <%@ <%@ <%@ Page Language="C#" Description="ASP.NET Component Test" %> Import Namespace="CompCS"%> Import Namespace="CompVB"%> Import Namespace="System.Text"%>

<html> <script language="C#" runat=server> void Page_Load(Object sender, EventArgs EvArgs) { StringBuilder Out = new StringBuilder(); int Count = 0; // Iterate over component's strings and concatenate Out.Append("Strings from C# Component<br>"); CompCS.StringComponent myCSStringComp = new CompCS.StringComponent(); for (int index = 0; index < myCSStringComp.Count; index++){ Out.Append(myCSStringComp.GetString(index)); Out.Append("<br>"); } Out.Append("<br>"); // Iterate over component's strings and concatenate Out.Append("Strings from VB Component<br>"); CompVB.StringComponent myVBStringComp = new CompVB.StringComponent(); for (int index = 0; index < myVBStringComp.Count; index++){ Out.Append(myVBStringComp.GetString(index)); Out.Append("<br>"); } Message.InnerHtml = Out.ToString(); } </script> <body> <span id="Message" runat=server/> </body> </html>

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

33

Demonstration: Testing the ASP.NET Client


Topic Objective
To demonstrate how to test the ASP.NET page.

Lead-in
In this demonstration, you will see how to test the ASP.NET page.

For Your Information


For instructions on running this demonstration, see the Instructor Notes. This exact procedure is repeated in Lab 3.3, Calling a Component Through an ASP.NET Page.

This demonstration shows how to test the ASP.NET page that was created in Creating an ASP.NET Client in this module. Before testing the page, you must first configure a virtual directory that points to the directory that contains the .aspx file. You can use the New Directory Wizard in the IIS snap-in to do this.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

34

Module 3: Working with Components

Lab 3.3: Calling a Component Through an ASP.NET Page


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will learn how to create an ASP.NET page that uses a previously developed .NET Framework component to create an ASP.NET application.

Objectives
After completing this lab, you will be able to create an ASP.NET page that uses a previously developed .NET Framework component to create an ASP.NET application.

Lab Setup
Starter and solution files are associated with this lab. The starter files are in the folder <install folder>\Labs\Lab03.3\Starter, and the solution files are in the folder <install folder>\Labs\Lab03.3\Solution.

Scenario
The labs associated with Module 3 are based on a small client/server application scenario in which a .NET Framework component may be used in several different client scenarios. The component may be written in any .NET Framework runtime-compatible language, but you will only create a C# component. Lab 3.2, Creating a Simple Console-Based Client, and Lab 3.3, Calling a Component Through an ASP.NET Page, demonstrate how the same component code runs unchanged in different client environments. This lab focuses on using an ASP.NET page to call the component and display the results in a Web browser.

Estimated time to complete this lab: 30 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

35

Exercise 1 Writing the ASP.NET Page


In this exercise, you will create an ASP.NET page that uses the same StringComponent component that was used in the standalone client application that you created in Lab 3.2, Creating a Simple Console-Based Client. You will build a string object that holds the results of processing the string array in the StringComponent class and generates output that can be displayed in a Web browser.

!" create an ASP.NET page To


1. Open Notepad and enter a @ Page directive that specifies the following page attributes: a. Language = C# b. Description = ASP.NET Component Test 2. Import the following namespaces into the page: a. CompCS b. CompVB c. System.Text 3. Create HTML script that specifies C# as the script language and uses the runat=server directive.

!" call the StringComponent class To


1. Create a handler for the Page_Load event and initialize a local variable called Out of type StringBuilder to represent the string array in the StringComponent class.
StringBuilder Out = new StringBuilder("");

2. Declare a local variable called Count of type int to obtain the number of string elements in the string array. 3. Call the Append method on the Out variable with the following string that has as it final characters an HTML line break, "<br>": "Strings from C# Component<br> " 4. Assign to a local variable called myCSStringComp a new instance of the C# version of the StringComponent class. 5. Iterate over all the strings of the C# string component. In each iteration, append the components string to the string variable named Out and then append an HTML line break, "<br>". 6. Append the string "<br>Strings from the VB Component<br>" to the Out string and repeat steps 4 and 5 for the Visual Basic version of the StringComponent class. The local variable name is myVBStringComp. 7. Assign the result of processing the string array to an HTML server control so that the output is dynamically generated on a Web page. Use the ToString method to get the output string from the Out variable. 8. Save the file as ClientASP.NET.aspx in the <install folder>\Labs\Lab03.3\Starter\ASP.NET_Client folder.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

36

Module 3: Working with Components

Exercise 2 Building and Testing the ASP.NET Page


In this exercise, you will configure a virtual directory to point to a directory where the ASP.NET page is located, so that you can test the ASP.NET application that is a client of the previously created string component.

!" configure a virtual directory To


1. Click the Start menu, point to Programs, point to Administrative Tools, and then click Internet Services Manager. 2. Expand the computer icon, and then select and expand Default Web Site. 3. Click the Action menu, point to New, and then click Virtual Directory. The Virtual Directory Creation Wizard is launched. 4. Click Next to continue. 5. In the Alias text box, type Test, and click Next. 6. Browse to the <install folder>\Labs\Lab03.3\Starter\ASP.NET_Client folder that contains the file ClientASP.NET.aspx that you created in Exercise 1, and then click Next. 7. On the Access Permissions page, accept the default selections, click Next, and then click Finish. The Test folder is added to the Default Web Site.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 3: Working with Components

37

!" test the ASP.NET Client To


1. Ensure that the compiled component DLLs, CompCS.dll and CompVB.dll, are in a \Bin subdirectory under the starting point for the application virtual directory. 2. Open Microsoft Internet Explorer, and type the following text in the Address bar: http://localhost/Test/ClientASP.NET.aspx Pressing ENTER should display a dialog box that generates the correct string output, as shown in the following illustration:

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

38

Module 3: Working with Components

Review
Topic Objective
To reinforce module objectives by reviewing key points.
!

Lead-in
The review questions cover some of the key concepts taught in the module.
! ! !

An Introduction to Key .NET Framework Development Technologies Creating a Simple .NET Framework Component Creating a Simple Console Client Creating an ASP.NET Client

1. How do .NET methods indicate failure? All .NET Framework methods indicate failure by throwing exceptions.

2. What namespace contains the classes to create a Windows Form application? The Windows Forms library is located in the System.Windows.Forms namespace.

3. What is the default extension for ASP.NET pages? By default, ASP.NET files have an .aspx extension or .ascx for user controls.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning


Contents Overview Introduction to Application Deployment Application Deployment Scenarios Related Topics and Tools Lab 4: Packaging and Deployment Review 1 2 7 32 38 43

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

iii

Instructor Notes Module 4


Presentation: 90 Minutes Lab: 50 Minutes After completing this module, students will be able to:
!" !" !" !"

Package and deploy simple and componentized applications. Create strong-named assemblies. Install and remove assemblies from the global assembly cache. Configure an application to control its binding to an assembly based on the assemblys location and version data.

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_04.ppt

Preparation Tasks
To prepare for this module, you should:
!" !"

Read all of the materials for this module. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 4: Deployment and Versioning

Module Strategy
Use the following strategy to present this module:
!"

Introduction to Application Deployment Introduce common concepts, such as the Microsoft .NET Frameworks hierarchy of namespaces, the organization of assemblies, and the role of the assembly manifest. Describe simple and componentized applications, and their configuration and distribution scenarios.

!"

Application Deployment Scenarios The examples in this section show how to deploy a simple standalone application, an application that uses a shared assembly, and an application that makes use of assembly versioning. Introduce compapp, a componentized application, which uses multiple assemblies. Contrast compapp with the simple single assembly Hello, World application that was created in Module 2, Introduction to a Managed Execution Environment, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

!"

Related Topics and Tools Briefly introduces additional topics that are related to deployment and versioning but are beyond the scope of this course. This section also provides a list of tools that you can use to work with assemblies. You should simply inform the students of these topics and encourage them to look for more information in the .NET Framework Software Developers Kit (SDK) documentation. In addition, Course 2350A, Securing and Deploying Microsoft .NET Assemblies (Prerelease), covers code access security and role-based security in greater detail.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! ! !

Introduction to Application Deployment Application Deployment Scenarios Related Topics and Tools

Lead-in
In this module, you will learn about packaging and deployment of Microsoft .NET Framework applications and assemblies.

This module introduces the concepts of packaging and deployment of Microsoft .NET Framework applications and assemblies. The .NET Framework provides improved isolation of application assemblies, simplified application deployment, and robust versioning. This module walks you through the packaging and deployment of a simple Hello World application, and a small, componentized application. These applications are written in C#, the new language designed for the .NET Framework. The steps that are necessary to construct, compile, and run C# applications were explained in Module 2, Introduction to a Managed Execution Environment, and Module 3, Working with Components, both in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease). Because this course is an introduction to programming in the .NET Framework, you should spend some time reading the .NET Framework Software Developers Kit (SDK) documentation. In fact, the labs, demonstrations, and material for this module and other modules in this course are based on several tutorials in the .NET Framework SDK. After completing this module, you will be able to:
!" !" !" !"

Package and deploy simple and componentized applications. Create strong-named assemblies. Install and remove assemblies from the global assembly cache. Configure an application to control its binding to an assembly based on the assemblys location and version data.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

# Introduction to Application Deployment


Topic Objective
To introduce issues that arise in application deployment and to introduce the topics in the section.
! ! ! !

Common Concepts Simple Applications Componentized Applications Configuration and Distribution

Lead-in
You can deploy a .NET Framework application in several ways.

You can deploy a .NET Framework application in several ways depending on the following considerations:
!" !" !" !"

The complexity of the application The sharing of assemblies with other applications The applications security and protection requirements The applications method of distribution

An applications deployment is not affected by the .NET Framework common language runtime-compatible language that is used to develop the application: All applications that are written for use with the .NET Framework are compiled to the same self-describing, Microsoft intermediate language (MSIL) code and run against the same .NET Framework runtime. This section introduces common concepts, such as the .NET Frameworks hierarchy of namespaces, the organization of assemblies, and the role of the assembly manifest. It then describes simple and componentized applications, and their configuration and distribution.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

Common Concepts
Topic Objective
To review the organization of the .NET Framework class library and assemblies, and the role of the assembly manifest.
!

Classes and Types Used in .NET Framework Applications Are:


$ $ $

Organized in a hierarchy of namespaces Stored in PE files, such as DLLs and EXEs Fully described by metadata Are made up of one or more PE files Contain a manifest that identifies the assembly and its files Specify exported and imported classes and types Are units of deployment, reuse, and versioning

Lead-in
The .NET Framework provides a common class library that is organized into a hierarchical tree of namespaces.

Assemblies:
$ $ $ $

As you learned in Module 2, Introduction to a Managed Execution Environment, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease), in addition to the common language runtime, the .NET Framework provides common class library that is organized into a hierarchical tree of namespaces. At the root of this hierarchy is the System namespace, which contains objects for many other useful classes that can be used from any .NET-compatible language. These objects include objects that are used for file I/O, messaging, networking, and security. For Your Information
This topic reviews information that was covered in Module 2. Do not spend much time on this topic. Simply present the material as the starting point for a discussion of deployment and versioning.

The Organization of PE Files into Assemblies


The .NET Framework class library that you and others create are also organized into hierarchical namespaces and stored in portable executable (PE) files, most typically DLLs and EXEs. A single PE file can contain several namespaces, including nested namespaces. You also can split a namespace across multiple PE files. One or more PE files, and possibly non-PE files, such as resources, are combined to create an assembly, which is a physical unit that can be deployed, versioned, and reused.

The Role of the Assembly Manifest


In the .NET Framework, each class type is fully described through the types metadata. Each assembly contains a manifest that includes the name of each type that is exported from the assembly, along with information about the file that contains that types metadata. The manifest also includes information about the identity of the assembly, such as name, files that make up the assembly, and version information, and full information about any dependencies on other assemblies. The .NET Framework runtime uses assembly manifests to locate and bind to the referenced types.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

Simple Applications
Topic Objective
To describe how easily a application can be executed in the .NET Framework.
! !

Require .NET Runtime Be Installed on Local Computer Can Be Run Directly from a File Server or Copied Locally Make No Registry Entries Cannot Break Another Application
$

Lead-in
In the simplest case, a .NET Framework application can be executed locally on any computer on which the .NET runtime is already installed.

! !

Eliminate DLL Hell

Can Be Uninstalled by Deleting Locally Copied File(s)

In the simplest case, a .NET Framework application can be executed locally on any computer on which the .NET runtime is already installed. The program can run directly from a file server, or the files can be copied locally. Nothing else is required. No registry entries are made, and no other applications are broken or caused to stop running as a result. The fact that no registry entries are made eliminates DLL versioning issues, commonly referred to as DLL hell. Simply deleting the executable file, if it was copied locally, is sufficient to uninstall the application and leave zero footprint on the computer.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

Componentized Applications
Topic Objective
To describe how assemblies are handled in componentized applications.
!

Assemblies Private to an Application


$

Lead-in
Componentized applications are only slightly more complex than applications.
!

Same as a simple application Deployed into a common subdirectory Require a strong name and version information Deployed into the global assembly cache

Assemblies Private to Related Applications


$

Assemblies Shared with Other Unrelated Applications


$ $

Componentized applications are only slightly more complex than simple applications. The complexity of componentized applications depends on whether their components are:
!" !" !"

Contained in assemblies that are private to the application. Shared with other related applications. Shared with other potentially unknown applications.

If all of the component assemblies are private, the componentized application can be treated in the same manner as the application. The application can run from a file server, or the application files can be copied to a local volume. Deleting all of a componentized applications files is sufficient to uninstall the program. Likewise, if several related applications use the same component assemblies, those assemblies can be located in a common subdirectory. However, if the application uses assemblies that are shared with other unrelated applications, these assemblies can be installed in the global assembly cache and have certain properties, such as a unique strong name that includes version information, that enable the .NET runtime to ensure that the application binds to the appropriate versions.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

Configuration and Distribution


Topic Objective
To introduce options for configuring and deploying applications in the .NET Framework.
!

Configuration
$

Lead-in
As a developer of .NET Framework applications, you should be aware of the different ways in which applications may be configured and packaged for distribution.
!

Maintained in plain-text files Common distribution formats, such as a .CAB file or a .MSI file Common distribution mechanisms, such as Windows 2000 IntelliMirror or Microsoft Systems Management Server

Deployment
$

As a developer of .NET Framework applications, you should be aware of the different ways in which applications may be configured and packaged for distribution. Usually, individual organizations, or an administrator within an organization, decide how an application is packaged for distribution and configured for the organization.

Configuration
In the .NET Framework, you can maintain application configuration in plain text files. This use of plain text XML-based application configuration files allows administrators to tailor an applications behavior on a particular computer without having to involve developers in the process. The following section, Application Deployment Scenarios, presents several common application scenarios. While this module does not cover ASP.NET deployment, most of the concepts that are presented in this module apply to ASP.NET deployment.

Deployment
Many client applications may be further packaged in a common distribution format, such as a .CAB file or .MSI file. Client applications may also be installed by using application distribution mechanisms, such as Microsoft Windows 2000 IntelliMirror or Microsoft Systems Management Server (SMS), which both use the Microsoft Windows Installer technology. The Microsoft Windows Installer is an installation and configuration service that is included in the Windows 2000 operating system. It is provided in a service pack to Microsoft Windows 95, Microsoft Windows 98, and Microsoft Windows NT version 4.0. For more information about the Microsoft Windows Installer, see the Platform SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

# Application Deployment Scenarios


Topic Objective
To introduce the topics in the section.
! ! ! ! ! ! ! ! !

A Simple Application A Componentized Application Specifying a Path for Private Assemblies A Strong-Named Assembly Deploying Shared Components A Versioned Assembly Creating Multiple Versions of a Strong-Named Assembly Binding Policy Deploying Multiple Versions of a Strong-Named Assembly

Lead-in
This section shows how to deploy a variety of applications, from simple applications to applications that make use of assembly versioning.

The examples in this section show how to deploy a simple application, an application that uses a shared assembly, and an application that makes use of assembly versioning.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

A Simple Application
Topic Objective
To explain how a simple application is deployed.
!

Lead-in
In Module 2, you looked at the simplest .NET Framework application, the traditional Hello World application written in C#.
!

Use the Microsoft Intermediate Language Disassembler (Ildasm.exe) to Examine the Assembly Manifest
$ $ $

Version information Imported types Exported types Running the executable file directly from a file server, or Installing it locally by copying the file Uninstall the application by deleting the file

Deploy the Application by:


$ $ $

For Your Information


Point out that while Hello World is simplistic, it is extremely versatile in its ability to easily demonstrate many new concepts of the .NET Framework, including deployment and versioning.

In Module 2, Introduction to a Managed Execution Environment, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease), you looked at the simplest .NET Framework application, the traditional Hello World application written in C#. The C# source code for that program, HelloCS, is as follows:
using System; class MainApp { public static void Main() { Console.WriteLine("Hello World using C#!"); } }

This simple executable file prints a single line to the System.Console, a type that is contained in the .NET Framework class library. It does not reference any other libraries and does not itself produce a library.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

Using Microsoft Intermediate Language Disassembler to Examine Hello World


Compiling this small application generates the HelloCS.exe. If you run the Microsoft intermediate language (MSIL) disassembler (Ildasm.exe) against this executable file, a window appears, similar to the following illustration.

The simple Hello World application highlights a particularly important concept behind programming for the .NET Framework. The application is clearly selfdescribing: All of the information that is needed to understand the application is contained in the metadata. The MSIL disassembler shows the classes or types that are created within the application. In the case of the Hello World application, the only class is MainApp. The MSIL disassembler also shows the methods Main and a default constructor, indicated by .ctor. The program does not have any other members. To save information about the assembly to a file, use the Dump command on the File menu. To see additional information about the application, double-click the Manifest icon. The following window appears:

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 4: Deployment and Versioning

The preceding illustration shows the manifest, which contains information about the assembly, including the version (not yet set), and external libraries, and types within those libraries, that the application uses.

Deployment
Deployment to computers on which the .NET runtime is installed is a simple process. The Hello World application can run directly from a file server. More advanced programs may involve security issues. In the simple Hello World case, no files are placed on the workstation, no entries are made in the system registry, and, in effect, there is no impact on the client workstation. There is also nothing to clean up because there is nothing to uninstall on the client workstation. As you would expect, HelloCS.exe can also be copied to a local volume. In this scenario, you can uninstall the program by simply deleting the file, and as before, nothing would remain on the workstation. Whether you run HelloCS.exe from a file server or copy it to a local volume, running this application will not break another program, and no other application can cause HelloCS.exe to stop functioning.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

11

A Componentized Application
Topic Objective
To introduce compapp, a componentized application, which uses multiple assemblies.
!

Assembly Component to Be Used by Application


$

Assembly Stringer.dll is built from Stringer.cs as follows:

Lead-in
The Hello World application that is discussed in the preceding topic is completely trivial and hardly representative of even the simplest real-world application.

csc /target:library Stringer.cs csc /target:library Stringer.cs


!

Client Needs to Reference Assembly Deployment by File Server or Local Copy

csc /reference:Stringer.dll Client.cs csc /reference:Stringer.dll Client.cs


!

The Hello World application that is discussed in the preceding topic is completely trivial and hardly representative of even the simplest real-world application. This topic covers compapp, a componentized application, which uses multiple assemblies.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 4: Deployment and Versioning

Creating Stringer.dll
The client, Client.exe, calls types that are contained in a component assembly that is named Stringer (Stringer.dll). The source code for the Stringer assembly, is located in Stringer.cs:
using System; namespace org { public class Stringer { private string[] StringSet; public Stringer() { StringSet = new string[] { "C# String 0", "C# String 1", "C# String 2", "C# String 3" }; } public string GetString(int index) { if ((index < 0) || (index >= StringSet.Length)) { throw new IndexOutOfRangeException(); } return StringSet[index]; } public int Count { get { return StringSet.Length; } } } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

13

A client application that uses this component could fully qualify a reference to the Stringer class, for instance, as org.Stringer. Alternatively, a client application could include a using statement to allow easy access to the types in Stringer.dll by specifying the namespace, as shown in the Client.cs source code:
using System; using org; class MainApp { public static void Main() { Stringer myStringComp = new Stringer(); string[] StringsSet = new string[4]; // Iterate over component's strings Console.WriteLine("Strings from StringComponent"); for (int index = 0; index < myStringComp.Count; index++) { StringsSet[index] = myStringComp.GetString(index); Console.WriteLine(StringsSet[index]); } // ... } }

Building the Application


To build this componentized application, you first build the Stringer.dll assembly component. Then, you build Client.exe, importing the Stringer component by using the name of the file that contains the manifest, Stringer.dll, rather than the namespace name, which is org in this case.
csc /target:library Stringer.cs csc /reference:Stringer.dll Client.cs

The MSIL disassembler displays the Stringer.dll and shows all of the members, as in the following illustration.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 4: Deployment and Versioning

Like HelloCS.exe, Client.exe contains manifest information about itself, the System library, and the types that the application uses. However, the manifest now contains information about the Stringer assembly. A MSIL disassembler display of the manifest for Client.exe shows the reference to the Stringer assembly, as in the following illustration.

Deployment
Like the simple application, Client.exe can run directly from a file server on any workstation that has the .NET runtime installed. Client.exe and Stringer.dll can also be copied to a local volume. To uninstall the application, you need only delete the two files.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

15

Specifying a Path for Private Assemblies


Topic Objective
To show how to use a configuration file to specify a path for private assemblies.
!

Specifying a Directory From Which to Load Private Assemblies.


$

Lead-in
The .NET Framework provides a configuration mechanism that allows administrators to specify a directory from which to load private assemblies.

Client.exe.config file specifies a privatePath tag

<configuration> <configuration> <runtime> <runtime> <assemblyBinding <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath=MyStringer"/> <probing privatePath=MyStringer"/> </assemblyBinding> </assemblyBinding> </runtime> </runtime> </configuration> </configuration>

Configuration Files XML Tags Are Case-Sensitive

The preceding Client.exe example has one important weakness: Both Client.exe and Stringer.dll reside in the same directory. In the real world, an administrator may wish to use a directory structure to manage assemblies. The .NET Framework provides a configuration mechanism that allows administrators to specify a directory from which to load private assemblies.

Locating Stringer.dll and Client.exe in Separate Directories


Using the preceding Client example, all of the source code is the same, but for illustration purposes the build process has been modified so that the component applications Stringer.dll is built in its own subdirectory named MyStringer:
cd \compapp csc /target:library /out:MyStringer\Stringer.dll! MyStringer\Stringer.cs csc /reference:MyStringer\Stringer.dll Client.cs

Using a Configuration File to Locate Assemblies at Run Time


Although the /reference: compile option locates an assembly in a directory when compiling the program, a separate XML-based application configuration file is required at run time to support assemblies that are located in other directories. For client executable files like the examples that are covered in this module, the configuration file resides in the same directory as the executable file. The configuration file has the complete name of the executable file with an additional extension of .config.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 4: Deployment and Versioning

The Client.exe configuration file is called Client.exe.config. It specifies a privatePath tag, as shown in the following example:
<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="MyStringer"/> </assemblyBinding> </runtime> </configuration>

Important The configuration files XML tags are case-sensitive. When this configuration file is placed in the same directory as the executable file, at run time, the .NET Framework uses the privatePath tag to determine where to look for componentsin addition to looking in the application directory. Note When loading an assembly, the runtime also searches for a private path that is equal to the name of the assembly. If the Stringer.dll assembly was located in a subdirectory named Stringer, instead of MyStringer, then a configuration file would be unnecessary.

Deployment
Like the simple application, the revised Client.exe can run directly from a file server on any workstation that has the .NET runtime installed. Client.exe, Stringer.dll, and the applications .config file can also be copied to a local volume, using the same relative directory structure. Deleting the files and directory effectively uninstalls the application. While they are not used in the preceding example, it is important to know that in addition to application configuration files, the .NET Framework also supports separate user and Computer Configuration Files for many common configuration settings.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

17

A Strong-Named Assembly
Topic Objective
To discuss the problems that may occur when multiple applications share components, and to introduce the use of strong names.
!

Global Assembly Cache


$

Contains assemblies shared by unrelated applications

Strong Names Are Required for Assemblies in the Cache


$

Lead-in
The client applications discussed in the preceding topics are limited in that they only illustrate the use of assemblies that are private to the Client.exe and do not demonstrate the use of assemblies that are shared by more than one application.

Generate a private key: sn k orgKey.snk sn k orgKey.snk


$

Add code to source file to specify version and key information:

#if STRONG #if STRONG [assembly: System.Reflection.AssemblyVersion("1.0.0.0")] [assembly: System.Reflection.AssemblyVersion("1.0.0.0")] [assembly: System.Reflection.AssemblyKeyFile("orgKey.snk")] [assembly: System.Reflection.AssemblyKeyFile("orgKey.snk")] #endif #endif
$

Compile:

csc /define:STRONG /target:library /out:AReverser.dll! csc /define:STRONG /target:library /out:AReverser.dll! AReverser.cs AReverser.cs

The client applications discussed in the preceding topics show the basics for constructing a complex program, but they are limited in that they only illustrate the use of assemblies that are private to the Client.exe and do not demonstrate the use of assemblies that are shared by more than one application. This topic discusses the problems that may occur when multiple applications share components. It then introduces the use of strong names, the .NET Frameworks solution to these problems.

Issues with Sharing Components


Many applications use assemblies that are shared by more than one application. These shared assemblies, which are typically provided by third-party developers, are installed in a common location on the system, the global assembly cache. By default, the system looks for each applications assemblies in the global assembly cache. In classic COM and COM+ applications, the sharing mechanism depends heavily on the Windows System Registry in which information about each component, including its version and physical file location, is stored. This mechanism allows multiple applications to share a single component, but it also allows a component of a newly installed application to overwrite an existing component and possibly cause other applications to break. Such overwriting of existing components is often difficult to detect because the application that is causing the problem appears to work properly.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 4: Deployment and Versioning

Strong Names
In the .NET Framework, you can solve the problems that are caused by the sharing of components with multiple applications by more strongly associating a distinct build of a component assembly with the client application. A distinct build is indicated by a combination of a version number and a special value that is called the publicKeyToken. When component assemblies are associated with a distinct build, the system can isolate these component assemblies, thus allowing different versions to run at the same time for different client applications. This system of protection is sometimes called side-by-side execution. It differs from backward compatibility because with side-by-side execution, applications can run alongside other versions of the same applications without affecting their respective execution environments. You can facilitate side-by-side execution by assigning strong names to your assemblies. A strong name consists of the assemblys identity, which includes its simple text name, version number, and culture information, if provided, and a public key. To demonstrate these additional build attributes the client and component scenario is extended by adding an assembly named AReverser. This assembly contains a class with a method that is named Invert, which uses the System.Array.Reverse method to reverse an array of strings. Note The code details of AReverser are not relevant to deployment issues and therefore are not shown. This modules lab contains the complete code details.

Building the Assembly Without a Strong Name


You begin by building the new component assembly without specifying any options to make it have a strong name. First, you simply compile the new AReverser assembly, as follows:
csc /target:library /out:AReverser.dll AReverser.cs

After compiling the new AReverser assembly, you can examine the metadata by using the MSIL disassembler. The MSIL disassembler indicates that the assembly lacks an originator and does not have an established version number, as shown in the following code:
.assembly AReverser { ... .hash algorithm 0x00008004 .ver 0:0:0:0 } .module AReverser.dll

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

19

Generating a Public-Private Key Pair


To create an assembly with a strong name, you must compile the assembly by using a private key. Public keys are used for verification. Therefore, before compiling the assembly, you must first generate a public-private key pair. You use the Strong Name tool (Sn.exe) to generate a new key pair and place them in a file, as in the following example:
sn k orgKey.snk

Compiling a Strong-Named Assembly


Now that you have a private key, you are ready to compile the component, specifying the key file and the version number to be assigned. You can do this by specifying AssemblyVersion and AssemblyKeyFile attributes in the AReverser.cs file using the STRONG conditional compilation symbol:
#if STRONG [assembly: System.Reflection.AssemblyVersion("1.0.0.0")] [assembly: System.Reflection.AssemblyKeyFile("orgKey.snk")] #endif

You must then define STRONG in the compile process:


csc /define:STRONG /target:library /out:AReverser.dll! AReverser.cs

If you run the MSIL disassembler again on AReverser.dll, you can verify that the assembly is now strong-named from the presence of a publickey property and a non-default version, which is specified by the .ver property of 1:0:0:0. The following example shows the disassembled code:
.assembly AReverser { ... .publickey = (00 ... 71 8A 7D 6A D7 ) .hash algorithm 0x00008004 .ver 1:0:0:0 } .module AReverser.dll

For more information about the Strong Name tool, see Packaging and Deployment Tools in this module.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 4: Deployment and Versioning

Deploying Shared Components


Topic Objective
To explain the commands that are used to install, examine, and remove assemblies from the global assembly cache.
!

Installing the Strong-Named Component in the Global Assembly Cache

Lead-in
While components can easily be shared by related applications simply by putting them in a common subdirectory, shared assemblies that are used by many applications on the system are often stored in the systems global assembly cache.

gacutil /i AReverser.dll gacutil /i AReverser.dll


!

Examining the Global Assembly Cache

gacutil /l gacutil /l
!

Removing a Shared Component File

gacutil /u AReverser gacutil /u AReverser

Deployment with strong-named assemblies is usually more complicated than deployment with assemblies that are not strong-named. While components can easily be shared by related applications simply by putting them in a common subdirectory, shared assemblies that are used by many applications on the system are often stored in the systems global assembly cache. As with the previous examples of and componentized applications, this revised Client.exe can run directly from a file server on any workstation on which the .NET runtime is installed. The Client.exe and Stringer.dll files can also be copied to a local volume.

Installing a Strong-Named Assembly into the Global Assembly Cache


Installing the strong-named component into the global assembly cache requires the following additional command on the computer that will be running the corresponding Client.exe program:
gacutil /i AReverser.dll

Note You must have Administrator privileges on a computer to install assemblies into the global assembly cache. Assemblies that are installed in the global assembly cache must have a strong name. After installing the AReverser assembly, you can then examine the system assembly cache by entering:
gacutil /l

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

21

The output of this command:


... AReverser, Version=1.0.0.0, Culture=neutral, PublicKeyToken=! 0588613cb04b772e, Custom=null ...

You can also examine the system assembly cache by navigating to the \WindowsDirectory\Assembly directory and by using the cache shell extension.

Uninstalling a Strong-Named Assembly from the System Cache


Cleaning up applications that use strong-named assemblies requires more work than cleaning up the simple applications or componentized applications that are described in the preceding topics. In addition to deleting the executable files, you should remove the shared component file from the global assembly cache, which unlike the download cache, is not automatically scavenged. To remove a shared component file, an administrator can use the cache shell extension, select the appropriate components, and delete them. Developers and administrators who want to automate the process, however, should use the command-line interface to the assembly cache manager as follows:
gacutil /u AReverser

To confirm the removal, you can view the contents of the global assembly cache by using the following command:
gacutil /l

For more information about installing and uninstalling shared assemblies to the global assembly cache, see Packaging and Deployment Tools in this module.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 4: Deployment and Versioning

A Versioned Assembly
Topic Objective
To discuss the physical representation and logical mapping of the compatibility version number.
!

Applications Need to Bind to a Suitable Version of a Shared Assembly The Version Number Is Represented by a 4-Part Number Applications Get the Versions of Assemblies with Which They Were Built and Tested
$

Lead-in
The final packaging and deployment example in this module involves updating the shared assembly to a new version.

<major version>.<minor version>.<revision>.<build number> <major version>.<minor version>.<revision>.<build number>


!

Unless overridden by explicit policy rules

The final packaging and deployment example in this module involves updating the shared assembly to a new version. In Creating Multiple Versions of a Strong-Named Assembly in this module, the shared assembly is updated to deliberately break compatibility with the client and to demonstrate how the .NET Framework allows you to configure the client application to bind to the desired version of the shared assembly.

Versioning
Each assembly has a specific compatibility version number as part of its identity. As such, two assemblies that differ by compatibility version are completely different assemblies as far as the .NET runtime class loader is concerned. This compatibility version number is physically represented as a four-part number with the following format:
<major version>.<minor version>.<revision>.<build number>

Each segment of this number has a specific meaning to the .NET runtime as it decides which version of an assembly to load. Logically, the compatibility version number has three parts, with the following meanings: 1. Incompatible A change has been made to the assembly that is known to be incompatible with previous versions. Example: Major new release of the product 2. Maybe Compatible A change has been made to the assembly that is thought to be compatible and carries less risk than an incompatible change. However, backward compatibility is not guaranteed. Example: Service Pack or release of a new daily build
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

23

3. Quick Fix Engineering (QFE) An engineering fix that customers may want to upgrade to. Example: An emergency security fix These three logical parts correspond to the physical four-part version number as follows:

For example, an assembly with compatibility version number 2.0.0.0 is considered incompatible with an assembly whose compatibility number is 1.0.0.0. Compatibility number 2.0.2.11 is considered a QFE to compatibility number 2.0.2.1.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 4: Deployment and Versioning

Creating Multiple Versions of a Strong-Named Assembly


Topic Objective
To explain how to create multiple versions of a shared component by using strong-named assemblies.
!

Building Two New Versions of AReverser with a New Key Pair


$

Specify version 2.0.0.0 for one and 2.0.1.0 for the other For AReverser_v2.0.0.0\AReverser.cs:

Lead-in
In the .NET Framework, you can solve the problems that are inherent in working with multiple versions of a shared component by using strong-named assemblies.

#if STRONG #if STRONG [assembly: System.Reflection.AssemblyVersion("2.0.0.0")] [assembly: System.Reflection.AssemblyVersion("2.0.0.0")] [assembly: System.Reflection.AssemblyKeyFile("orgVerKey.snk")] [assembly: System.Reflection.AssemblyKeyFile("orgVerKey.snk")] #endif #endif
!

Build

csc /define:STRONG /target:library! csc /define:STRONG /target:library! /out:AReverser_v2.0.0.0\AReverser.dll! /out:AReverser_v2.0.0.0\AReverser.dll! AReverser_v2.0.0.0\AReverser.cs AReverser_v2.0.0.0\AReverser.cs
!

Use Ildasm.exe to Examine Different Versions


$

.assembly AReverser .assembly AReverser { ... { ... .publickey = (00 24 ... 82 B1 F2 A0 ) .publickey = (00 24 ... 82 B1 F2 A0 ) .hash algorithm 0x00008004 .hash algorithm 0x00008004 .ver 2:0:1:0 .ver 2:0:1:0

Note the publickey and version numbers

In the .NET Framework, you can solve the problems that are inherent in working with multiple versions of a shared component by using strong-named assemblies. This topic examines how multiple versions of an assembly are created. Building on the code in the preceding strong-named AReverser assembly, two separate versions of the strong-named component are created, and additional application configuration options are used to show how an application can be made to run. A method in version 2.0.1.0 of AReverser.dll is deliberately made incompatible with the same method in version 2.0.0.0 so that a client that successfully calls the method that is using version 2.0.0.0 will fail with the later revision. Versioning keys can change from one version of an assembly to the next. To illustrate this, you generate a new key pair using the Strong Name (Sn.exe) tool and place that new key pair in a file, as follows:
sn k orgVerKey.snk

After creating a new private key, you add the following to the AReverser.cs file in the AReverser_v2.0.0.0 subdirectory:
#if STRONG [assembly: System.Reflection.AssemblyVersion("2.0.0.0")] [assembly: System.Reflection.AssemblyKeyFile("orgVerKey.snk")] #endif

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

25

You add the following to the AReverser.cs file in the AReverser_v2.0.1.0 subdirectory:
#if STRONG [assembly: System.Reflection.AssemblyVersion("2.0.1.0")] [assembly: System.Reflection.AssemblyKeyFile("orgVerKey.snk")] #endif

You compile both of these versions by using the commands:


csc /define:STRONG /target:library! /out:AReverser_v2.0.0.0\AReverser.dll! AReverser_v2.0.0.0\AReverser.cs csc /define:STRONG /target:library! /out:AReverser_v2.0.1.0\AReverser.dll! AReverser_v2.0.1.0\AReverser.cs

If you run the MSIL disassembler on these two updated files, you can verify that the assemblies are strong-named as indicated by the version number, 2.0.0.0 or 2.0.1.0, depending on which one you inspect with the MSIL disassembler. Notice that these two assemblies have the same publickey property, but the value of this property is different from the previous version 1.0.0.0 AReverser.dll. This property is different because a different key pair was used, orgVerKey.snk, instead of orgKey.snk. The following example shows the MSIL disassembler output for version 2.0.1.0 of the AReverser.dll:
.assembly AReverser { ... .publickey = (00 24 ... 82 B1 F2 A0 ) .hash algorithm 0x00008004 .ver 2:0:1:0 }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 4: Deployment and Versioning

Binding Policy
Topic Objective
To discuss binding policy.
!

Policy Resolution
$

Lead-in
Whenever the .NET Framework is asked to bind to a specific version of a shared assembly, the version of the assembly reference may be altered at several policy-resolution stages before the .NET Framework finally decides to which version to bind.
!

Allows an assembly reference, specified at compile time, to be modified after the application has been deployed without recompiling Application-policy resolution Publisher-policy resolution Administrator-policy resolution Note: XML is case-sensitive

Happens in the Following Stages: 1. 2. 3.

In Each Stage, an XML Configuration File Is Read


$

! !

Version Numbers of Assemblies That Are Not Strong-Named Are Not Checked Configuration File Tag Examples $ privatePath $ bindingRedirect

When the .NET Framework is asked to bind to a specific version of a shared assembly, the version of the assembly reference may be altered at several policy-resolution stages before the .NET Framework finally decides which version to bind to. This policy-resolution process allows an assembly reference, which is specified at compile time, to be modified after the application has been deployed, without recompiling the assemblies involved. Policy resolution happens in the following three stages: 1. Application-policy resolution 2. Publisher-policy resolution 3. Administrator-policy resolution In each stage, an XML configuration file that describes the policy is read. The privatePath tag in the application-configuration file illustrates the simplest form of application-policy resolution. In addition, the bindingRedirect tag can be used to redirect the reference to a different version of a shared assembly. Note The version numbers of assemblies that are not strong-named are not checked. Publisher-policy resolution allows shared-component vendors to make compatibility statements among different revisions of their software. These perassembly configuration files are distributed as strong-named assemblies and are installed into the global assembly cache (GAC) as part of a service pack-style update. Any binding redirects that are specified by the publisher-policy file are then applied to the reference, which is then subject to administrator-policy resolution. Because publisher-policy assemblies affect all applications on the system, it is important that these assemblies are installed separately from the application.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

27

Administrator-policy resolution is the finaland the strongeststage in the binding policy-resolution process. The administrator-policy file is located in the WindowsDirectory\Microsoft.NET\Framework\v1.0.FinalBuildNumber \CONFIG directory and is called Machine.config. This file has the same XMLbased schema as the policy files that are used in the two previous stages of policy resolution. Administrator policy affects all assembly bindings that occur on the system and can never be bypassed.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

28

Module 4: Deployment and Versioning

Deploying Multiple Versions of a Strong-Named Assembly


Topic Objective
To explain how to deploy multiple versions of a shared assembly.
!

Install Both Versions of AReverser.dll into the Global Assembly Cache


gacutil /i AReverser_v2.0.0.0\AReverser.dll gacutil /i AReverser_v2.0.0.0\AReverser.dll gacutil /i AReverser_v2.0.1.0\AReverser.dll gacutil /i AReverser_v2.0.1.0\AReverser.dll

Lead-in
After you have configured both versions of the AReverser assembly to use strong names, you can deploy those versions.
!

Compile the VerClient Executable and Specify Version 2.0.0.0 of the AReverser Component

csc /reference:MyStringer\Stringer.dll! csc /reference:MyStringer\Stringer.dll! /reference:AReverser_v2.0.0.0\AReverser.dll VerClient.cs /reference:AReverser_v2.0.0.0\AReverser.dll VerClient.cs


!

Use Version Policies to Control Assembly Binding at Run Time

After you have configured both versions of the AReverser assembly to use strong names, you can deploy those versions. To configure client applications to use strong-named assemblies of a specific version, you must first install both 2.0 versions of AReverser.dll into the global assembly cache as follows:
gacutil /i AReverser_v2.0.0.0\AReverser.dll gacutil /i AReverser_v2.0.1.0\AReverser.dll

After installing these AReverser assemblies, you can then examine the global assembly cache by using:
gacutil /l

You can also examine the system assembly cache by navigating to the \WindowsDirectory\Assembly directory, and using the cache shell extension. You now compile the VerClient executable file, for which you specify the version 2.0.0.0 of the AReverser component, as shown in the following example:
csc /reference:MyStringer\Stringer.dll! /reference:AReverser_v2.0.0.0\AReverser.dll VerClient.cs

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

29

Version Policies
All versioning of assemblies that use the common language runtime takes place at the assembly level. The specific version of an assembly and the versions of dependent assemblies are recorded in the assemblys manifest. The rules that specify the acceptable versions of an assembly are called version policies. Version policies are expressed in configuration files.

Using Configuration Files to Overwrite Version Policy


According to the default version policy for the runtime, applications run only with the versions that they were built and tested with unless these versions were overridden by explicit version policy in configuration files. These configuration files, which include the application configuration file, a publisher policy file, and the machines administrator configuration file, provide the means for overriding the version policy that is recorded in the assembly manifest.

Binding to a Specific Assembly Version


In a configuration file, you can specify a version policy that instructs the runtime to bind to a specific version of an assembly that you want the application to use. This specific version policy allows you to bind to a different version of an assembly than the version that is recorded in the assembly manifest of the calling assembly. In particular, the bindingRedirect tag can be used to redirect the reference to a different version of a shared assembly, by overriding the version in the original reference with this newer version. The following option says that for any assembly reference from version 2.0.0.0 through 2.0.0.9, the version that should instead be used at run time is 2.0.1.0:
<bindingRedirect oldVersion="2.0.0.0-2.0.0.9" newVersion="2.0.1.0" />

This option allows an administrator to reconfigure an application without having to have it recompiled.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

30

Module 4: Deployment and Versioning

The following sample VerClient.exe.config file instructs the runtime to look in subdirectory MyStringer for assembly references and to bind to version 2.0.0.0 of AReverser:
<configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="MyStringer"/> <publisherPolicy apply="no"/> <dependentAssembly> <assemblyIdentity name="AReverser" publicKeyToken="52398B7804D8A95C" culture=""/> <publisherPolicy apply="no"/> <bindingRedirect oldVersion="2.0.0.0" newVersion="2.0.0.0"/> </dependentAssembly> </assemblyBinding> </runtime> </configuration>

Note The publicKeyToken tags value can be obtained using the Sn.exe tool or by examining the global assembly cache by using gacutil /l or the cache shell extension. Important The Sn.exe switches to obtain the publicKeyToken do not work correctly in some of the earlier .NET Framework versions, such as build 9188. Key Points
Reinforce the fact that the configuration files XML tags are case-sensitive.

Because a method of a type in version 2.0.1.0 of AReverser.dll was deliberately made incompatible with the same method in version 2.0.0.0, a version 2.0.0.0compatible client that attempted to call this later revision would fail. If VerClient.exe.config changed the line:
newVersion="2.0.0.0"/>

to:
newVersion="2.0.1.0"/>

The resulting error message would be similar to:


Unhandled Exception: System.MissingMethodException:! Method not found: at MainApp.Main()

More typically, the configuration file mechanism allows an administrator to repair an application so that it will continue to run even if it is broken by a subsequent install of another application that used a different version of the same shared component.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

31

Finally, when you need to clean up the application, remove the shared component files from the global assembly cache, as shown in the following example:
gacutil /u AReverser

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

32

Module 4: Deployment and Versioning

# Related Topics and Tools


Topic Objective
To introduce the topics in the section.
! !

Lead-in
This section briefly introduces additional topics that are related to deployment and versioning.

Related Topics Packaging and Deployment Tools

This section briefly introduces additional topics that are related to deployment and versioning but are beyond the scope of this course. This section also provides a list of tools that you can use to work with assemblies.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

33

Related Topics
Topic Objective
To briefly introduce several related topics and provide references for students to follow up on.
! ! ! !

ASP.NET Assemblies Security Localization

Lead-in
This module introduces the concepts of packaging and deployment of .NET Framework applications and assemblies. Several related topics are worth mentioning, and, when appropriate, references to additional information are provided.

This module introduces the concepts of packaging and deployment of .NET Framework applications and assemblies. Several related topics are worth mentioning, and, when appropriate, references to additional information are provided. For Your Information
Do not spend much time on this topic. The subject matter is mostly beyond the scope of the course. You should simply inform the students of these topics and encourage them to look for more information in the provided references.

ASP.NET
This module focuses on packaging and deploying traditional client applications. For more information about deploying ASP.NET applications to a Web server, see the .NET Framework SDK documentation.

Assemblies
For more information about how the .NET Framework locates assemblies when they are referenced at run time, see How the Runtime Locates Assemblies in the .NET Framework SDK documentation. This topic covers the Assembly Resolver, strong-named assemblies, application and administrator version policies, codebase locations, and QFE updates.

Security
The.NET Framework offers code access security and role-based security to address mobile code security concerns and to provide support that enables components to determine what users are authorized to do. These security mechanisms use a simple, consistent model so that developers who are familiar with code access security can easily use role-based security and developers who are familiar with role-based security can easily use code access security. Code access security and role-based security are implemented by using a common infrastructure that is supplied by the common language runtime.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

34

Module 4: Deployment and Versioning

Code Access Security and Role-based Security


Code access security uses permissions to control the access that code has to protected resources and operations. It helps to protect computer systems from malicious mobile code and provides a way to allow mobile code to run safely. Role-based security provides information that is needed to make decisions about what a user is allowed to do. These decisions can be based on the users identity, role membership, or both. A more detailed discussion of security is outside the scope of this course. For more information about security, see Securing Your Application in the .NET Framework SDK documentation. Additionally, Course 2350A, Securing and Deploying Microsoft .NET Assemblies (Prerelease) covers code access security and role-based security in greater detail.

Localization
To localize an application, you typically perform the following steps: 1. Separate your default resources from the code, and specify the localized text in a text file. 2. Compile the text file into a .resources file. 3. Package your default resources in the main assembly by using the C# compiler. 4. Create satellite resource assemblies, including satellites for .NET Framework cultures, by using the Alink tool. 5. Deploy the satellites to a directory structure underneath the main application. 6. Write the code to access the resources at run time. For more information about localization, see the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

35

Packaging and Deployment Tools


Topic Objective
To provide a brief overview of packaging and deployment tools that are included in the .NET Framework SDK.
! ! ! ! ! ! ! !

Assembly Linker (Al.exe) Global Assembly Cache tool (Gacutil.exe) MSIL Disassembler (Ildasm.exe) Strong Name (Sn.exe) Native Image Generator (Ngen.exe) Assembly Binding Log Viewer (Fuslogvw.exe) .NET Framework Configuration Tool (Mscorcfg.msc) Code Access Security Policy Tool (Caspol.exe)

Lead-in
The .NET Framework SDK includes several useful tools for examining assemblies and working with the global assembly cache.

The .NET Framework SDK includes several useful tools for examining assemblies and working with the global assembly cache. For more information about the tools that are introduced in this topic, see .NET Framework Tools and Debugger in the .NET Framework SDK documentation.

Assembly Linker (Al.exe)


The Assembly Linker is most useful to developers who need to create a single assembly from multiple components files, such as those that may be produced with mixed-language development.

Global Assembly Cache Tool (Gacutil.exe)


The global assembly cache tool (Gacutil.exe) allows you to view and manipulate the contents of the global assembly cache. This tool provides much of the same cache-viewing functionality as the Windows Shell Extension (Shfusion.dll), but the global assembly cache tool is more usable from build scripts, makefiles, and batch files. Specifically, Gacutil.exe allows you to install assemblies into the cache, remove them from the cache, and list the contents of the cache. You must have Administrator privileges on a computer to install assemblies into the global assembly cache. To avoid removing more than one assembly from the global assembly cache, you can use a command with the name of your specific assembly, as follows:
gacutil /u! hello,ver=1.0.0.1,Culture=en,PublicKeyToken=874e23ab874e23ab

The preceding command removes only the hello assembly that matches the fully specified version number, culture, and public key.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

36

Module 4: Deployment and Versioning

The following command lists the contents of the global assembly cache:
gacutil /l

MSIL Disassembler (Ildasm.exe)


You can also explore the namespaces in files that come with the runtime or in files that you or others create by using the command-line MSIL disassembler. To open a window that displays information about System.Data.dll, enter the following command:
>ildasm System.Data.dll

Each of the namespace nodes represents a separate namespace, which can be expanded to explore the class objects and their methods and properties. The MSIL disassembler also features a number of command-line options, which are particularly useful when you want to redirect output to the console or to a text file for subsequent analysis. Tip Place a shortcut to Ildasm.exe in your SendTo folder.

Strong Name Tool (Sn.exe)


When working with shared components, you can use the Strong Name (Sn.exe) command-line tool for several purposes. For example, you can use the tool to generate a new public-private key pair and write that pair to an output file, as follows:
-k <outfile>

Native Image Generator (Ngen.exe)


The Native Image Generator creates a native image from a managed assembly and installs it into the native image cache on the local computer. Running Ngen.exe on an assembly allows the assembly to load faster, because it restores code and data structures from the native image cache rather than generating them dynamically. Pre-compiling assemblies with Ngen.exe can improve the startup time for applications, because much of the work required to execute code has been done in advance. Therefore, it is more appropriate to use Ngen.exe for client-side applications where you have determined that the CPU cycles consumed by justin-time (JIT) compilation cause slower performance. Because there are many factors that affect the startup time of an application, you should carefully determine which applications would benefit from the use of Ngen.exe. Experiment by running both a JIT-compiled and a pre-compiled version of a candidate assembly in the environment in which it will be used. This will allow you to compare the startup times for the same assembly executing under different compilation schemes.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

37

Assembly Binding Log Viewer (Fuslogvw.exe)


For Your Information
The Assembly Binding Log Viewer tool is used in the lab.

The Assembly Binding Log Viewer displays details for failed assembly binds. This information helps you diagnose why the .NET Framework cannot locate an assembly at run time. These failures are usually the result of an assembly deployed to the wrong location or a mismatch in version numbers or cultures.

.NET Framework Configuration Tool (Mscorcfg.msc)


The .NET Framework Configuration Tool provides a graphical interface for managing .NET Framework security policy and applications that use remoting services. This tool also allows you to manage and configure assemblies in the global assembly cache. The .NET Framework Configuration Tool is a Microsoft Management Console (MMC) snap-in.

Code Access Security Policy Tool (Caspol.exe)


The Code Access Security Policy Tool allows you to examine and modify machine, user, and enterprise-level code access security policies.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

38

Module 4: Deployment and Versioning

Lab 4: Packaging and Deployment


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will build an application that is named client, which retrieves an array of strings from an instance of the Stringer class and reverses the order of these strings by using an instance of the AReverser class. These classes are packaged in two separate assembly libraries that are named Stringer.dll and AReverser.dll.

Objectives
After completing this lab, you will be able to:
!" !"

Create an application by using private assemblies in multiple directories. Install and remove a strong-named assembly from the global assembly cache. Configure an application to control its binding to an assembly based on the assemblys location and version data.

!"

Lab Setup
Starter and solution files are associated with this lab. The starter files are in the folder <install folder>\Labs\Lab04\Starter. The solution files are in the folder <install folder>\Labs\Lab04\Solution.

Scenario
You will build an application that is named client, which retrieves an array of strings from an instance of the Stringer class and reverses the order of these strings by using an instance of the AReverser class. These classes are packaged in two separate assembly libraries that are named Stringer.dll and AReverser.dll.

Estimated time to complete this lab: 50 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

39

Exercise 1 Locating Private Assemblies in Multiple Directories


In this exercise, you will build the client application by using private assemblies that are located in multiple directories.

!" examine the application To


Open Notepad and examine the source code for the files that are listed in the following table.
Filename Client.cs Stringer.cs AReverser.cs Directory location <install folder>\Labs\Lab04\Starter\Compapp <install folder>\Labs\Lab04\Starter\Compapp\MyStringer <install folder>\Labs\Lab04\Starter\Compapp\AReverser

!" compile and build the application in a command window To


1. Go to the MyStringer directory and build the private assembly library named Stringer.dll in that directory. 2. Go to the AReverser directory and make the private assembly named AReverser.dll in that directory. 3. Go to the Compapp directory and build the client application, referencing the private assemblies from steps 1 and 2. Reference the DLLs in their own directories. Do not copy them to the Compapp directory.

!" Execute the application


1. Execute the Client.exe application and note the exception in the space that is provided.

2. Run the Assembly Binding Log Viewer by executing Fuslogvw.exe. Then select the Client.exe application, and view the log entry.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

40

Module 4: Deployment and Versioning

3. Create a configuration file in the Client directory to specify the appropriate privatePath so that the application can successfully bind and load the necessary classes. The Client.exe application should generate the following output:
Strings from StringComponent C# String 0 C# String 1 C# String 2 C# String 3 Reversed Array Strings C# String 3 C# String 2 C# String 1 C# String 0

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

41

Exercise 2 Using Strong-Named Assemblies and Versioning


In this exercise, you will build the client application by using strong-named assemblies that are located in the global assembly cache. You will then configure an application to control its binding to an assembly based on the assemblys location and version data.

!" build a compatible strong-named version of AReverser To


1. From a command prompt window, navigate to the <install folder>\Labs\Lab04\Starter\Compapp directory, and use the Strong Name tool to create a public-private key pair file that is named OrgVerKey.snk. 2. Open Notepad. On the File menu, click Open, browse to <install folder>\Labs\Lab04\Starter\ Compapp\AReverser_v2.0.0.0, and open AReverser.cs. 3. Examine the source code and note that it is the same code that was used in the preceding exercise. In particular, note that the signature of the Invert method is:
public string[] Invert(string[] myString)

4. Modify the source code to specify the key pair file from step 1 and to specify a version number of 2.0.0.0. 5. From a command prompt window, navigate to the <install folder>\Labs\Lab04\Starter\Compapp directory and build the 2.0.0.0 strong-named version of AReverser.cs. The AReverser.dll should be output into the AReverser_v2.0.0.0 subdirectory. 6. Use the global assembly cache tool (Gacutil.exe) to install this assembly in the global assembly cache. 7. Examine the global assembly cache by using Gacutil.exe or Windows Explorer, and note the presence of AReverser and its properties.

!" build an incompatible strong-named version of AReverser To


1. In Notepad, on the File menu, click Open, browse to <install folder>\Labs\Lab04\Starter\Compapp\AReverser_v2.0.1.0, and open AReverser.cs. 2. Examine the source code and note that it is different from the code that was used in the preceding exercise. In particular, note that the signature of the Invert method is:
public string[] Invert(string[] myString, int myCount)

3. Modify the source code to specify the key pair file OrgVerKey.snk and to specify a version number of 2.0.1.0. 4. From a command prompt window, navigate to the <install folder>\Labs\Lab04\Starter\Compapp directory and build the 2.0.1.0 strong-named version of AReverser.cs. The AReverser.dll should be output into the AReverser_v2.0.1.0 subdirectory.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

42

Module 4: Deployment and Versioning

5. Install this assembly in the global assembly cache. 6. Examine the global assembly cache by using Gacutil.exe or Windows Explorer, and note the presence of AReverser and its properties.

!" compile, build, and execute the application To


1. From a command prompt window, navigate to the Client directory and build the client application. Reference the private assembly MyStringer\Stringer.dll and the strong-named assembly AReverser_v2.0.0.0\AReverser.dll. 2. Execute the Client.exe application, which should generate the following output:
Strings from StringComponent C# String 0 C# String 1 C# String 2 C# String 3 Reversed Array Strings C# String 3 C# String 2 C# String 1 C# String 0

!" Configure to bind to the latest version of AReverser


Tip You can obtain the publicKeyToken tags value by examining the global assembly cache using gacutil /l or the cache shell extension. 1. Modify the configuration file to bind to the incompatible later version 2.0.1.0 of AReverser. 2. Execute Client.exe and note the exception. 3. Use the global assembly cache tool to remove the two strong-named versions of AReverser. 4. Confirm the removal of the two strong-named versions of AReverser by viewing the global assembly cache with Gacutil.exe and Windows Explorer.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 4: Deployment and Versioning

43

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! ! !

Introduction to Application Deployment Application Deployment Scenarios Related Topics and Tools

Lead-in
The review questions cover some of the key concepts taught in the module.

1. What part of the assembly identifies its imported and exported types and its version information? The manifest.

2. What software does a computer require to run a .NET application locally? The .NET Framework common language runtime.

3. Name two simple ways to run a .NET Framework application. Copy the executable file and referenced assemblies to the local computer, or access them on a file server.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

44

Module 4: Deployment and Versioning

4. Describe how an application can use an assembly that is located in an applications subdirectory. Create a configuration file in the applications directory that specifies a PrivatePath as follows: <configuration> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="MyStringer"/> </assemblyBinding> </runtime> </configuration>

5. What kind of assembly can be placed in the global assembly cache and be versioned? A strong-named assembly.

6. What command is used to generate public-private key pairs? The Strong Name (Sn.exe) tool is used to generate a new key pair and place them in a file: sn k orgKey.snk

7. What command is used to install a strong-named assembly into the global assembly cache? > gacutil -i <filename>

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System


Contents Overview An Introduction to the Common Type System Elements of the Common Type System Object-Oriented Characteristics Lab 5: Building Simple Types Review 1 2 8 27 41 46

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

iii

Instructor Notes Module 5


Presentation: 90 Minutes Lab: 45 Minutes After completing this module, students will be able to:
!" !"

Describe the difference between value types and reference types. Explain the purpose of each element in the type system, including values, objects, and interfaces. Explain how object-oriented programming concepts, such as abstraction, encapsulation, inheritance, and polymorphism, are implemented in the Common Type System.

!"

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_05.ppt

Preparation Tasks
To prepare for this module, you should:
!" !"

Read all of the materials for this module. Complete the lab.

Module Strategy
Use the following strategy to present this module:
!"

An Introduction to the Common Type System Cover the basic architecture of the Common Type System. Introduce System.Object as the root type for all types in the Microsoft .NET Framework common language runtime. Explain how all types in the Common Type System are either reference types or value types.

!"

Elements of the Common Type System In this section, cover the primitive types, objects, properties, and other elements of the Common Type System. The information will not be new to students with a C++ object-oriented background, so you can cover these topics quickly or omit most of the material in this section. This decision will depend on the students experience.

!"

Object-Oriented Characteristics Discuss how the object-oriented characteristics of the .NET Framework common language runtime are supported. If the class is already experienced in object-oriented techniques, you can omit this section.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! ! !

An Introduction to the Common Type System Elements of the Common Type System Object-Oriented Characteristics

Lead-in
In this module, you will learn about the Common Type System and object-oriented programming.

In this module, you will learn about the Common Type System. Specifically, you will learn to differentiate between value types and reference types. You will also examine how classes, interfaces, properties, methods, events, and values are represented in the Microsoft .NET Framework. After completing this module, you will be able to:
!" !"

Describe the difference between value types and reference types. Explain the purpose of each element in the type system, including values, objects, and interfaces. Explain how object-oriented programming concepts, such as abstraction, encapsulation, inheritance, and polymorphism, are implemented in the Common Type System.

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

# An Introduction to the Common Type System


Topic Objective
To provide an overview of the section topics.
! !

Common Type System Architecture Value Types vs. Reference Types

Lead-in
In this section, you will learn about the architecture of the Common Type System.

In this section, you will learn about the Common Type System architecture. Specifically, you will learn how types are specified and represented in the .NET Framework common language runtime, and you will learn the difference between value types and reference types.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

Common Type System Architecture


Topic Objective
To describe the basic architecture of the Common Type System.
CLR Type System

Lead-in
A type defines characteristics for a set of values.

Value Types (System.ValueType)

Fields Methods Properties

Reference Types (System.Object)

Primitive Types Built-in Types Interface Types Contract specifying method and property signature

Built-in Types Delegates

User-defined Value and Reference Types

A type defines characteristics for a set of values. For example, the set of whole numbers between negative 32768 and positive 32767 is called the short type in C#, or System.Int16 in the .NET Framework class library. The short type has a physical representation, which, in this case, is a 16-bit value. The short type also defines operations allowed on the type, such as addition and subtraction.

System.Object
System.Object is the root type for all types in the .NET Framework common language runtime. For this reason, any type you use will have System.Object as its base class. System.Object has the following methods.
Methods Public Equals Public GetHashCode Description Determines whether the specified object is the same instance as the current object Serves as a hash function for a particular type; suitable for use in hashing algorithms and data structures, such as a hash table Gets the type of the object Returns a string that represents the current object Allows an object to attempt to free resources and perform other cleanup operations before the object is reclaimed by garbage collection Creates a shallow copy of the current object

Public GetType Public ToString Protected Finalize

Protected MemberwiseClone

For more information about the methods of System.Object, see Module 6, Working with Types, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

Value Types
Value types are any type that inherits from System.ValueType. Value types are typically simple types, such as integer values or long values. Value types are special because they are allocated on the stack. New value types are defined by using the struct or enum keywords. You cannot create value types by using the class keyword. System.ValueType inherits from System.Object, which means that all value types can behave like System.Object. The type system defines primitive types, which are Byte, Int16, Int32, Int64, Single, Double, Boolean, Char, Decimal, IntPtr, and String. There are also built-in types such as System.Array available.

Reference Types
Reference types are any type that inherits from System.Object and not System.ValueType. Reference types are analogous to pointers in C++, but there are subtle differences in the way reference types and pointers work. Reference types are allocated on the heap. Reference types also must be garbage collected. One example of a reference type is the System.IO file class, which represents a file in the system.

Fields, Methods, and Properties


The Common Type System defines fields, methods, and properties that are available to all value types and reference types. A field is a data value stored in a class. For example, Name and Age could be fields describing an employee stored in an Employee structure. A method is an operation that can be performed on a class. For example, a Tenure method could calculate how long an employee has been employed. Properties are a convenient way to expose data values to external objects and code. For example, the Name and Age fields could be exposed as properties, which would allow the Employee structure to control how the name and age are stored and retrieved.

Interfaces
Interfaces are the only types that do not inherit from System.Object. Interfaces have no implementation; they merely provide a description of methods, properties, and events. Any class that inherits from an interface must implement all of the methods, properties, and events in that interface. Interfaces provide a mechanism for specifying contractual relationships between classes. Interfaces also provide a means of implementing multiple inheritance. For more information about inheritance, see Module 6, Working with Types, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

Value Types vs. Reference Types


Topic Objective
To explain the difference between value types and reference types.
!

Value Types Are Primitive or User-Defined Structures


$ $ $

Allocated on stack Assigned as copies Default behavior is pass by value Allocated on heap using the new keyword Assigned as references Passed by reference

Lead-in
With the exception of interfaces, all types in the Common Type System are divided into two categories: value types and reference types.

Reference Types Are Objects That Are:


$ $ $

With the exception of interfaces, all types in the Common Type System are divided into two categories: value types and reference types.

Value Types
Value types represent primitive or user-defined structures. Value types are allocated on the stack and are removed from the stack when the method call in which they were declared returns. When a value type is passed as an argument to a method, it is passed by value, unless the ref keyword is used. All value types must inherit from System.ValueType.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

An integer is an example of a value type. The following example shows an integer value type and its effect on method calls and assignment operations.
using System; public class MainClass { public static void Main() { // Create a new integer with value 5 int a = 5; // Create a new uninitialized integer int b; // Initialize b by copying the value 5 into b b = a; //Increase the value of b by 5 b += 5; Console.WriteLine("{0}, {1}", a, b); Add5(b); Console.WriteLine("{0}, {1}", a, b); } public static void Add5(int num) { num += 5; } }

This code generates the following output:


5, 10 5, 10

In the preceding example, the variables a and b represent two separate instances of the integer type. The Assignment operator (=) copies the value from one variable to another. When the Add5 method is called, the = operator updates a copy of the integer, not the original integer, because a copy of the value is pushed onto the stack when passing value types.

Reference Types
Reference types are a reference to a value. Reference types are allocated on the heap and will remain on the heap until they are garbage collected. Reference types must be allocated by using the new keyword. When you pass reference types as parameters, the reference is pushed onto the stack, and the method call works with the actual value, not with a copy of the value. All reference types inherit from System.Object.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

The following example shows the effect of assignments and method calls when you use the StringBuilder class, which is a reference type:
using System; using System.Text; public class MainClass { public static void Main() { //Create a new StringBuild instance //with the string "Bob" StringBuilder name1 = new StringBuilder("Bob"); StringBuilder name2; //Make name2 reference the same StringBuilder instance name2 = name1; name2.Append("by"); Console.WriteLine("Values are {0}, {1}", name1, name2); Possessive(name2); Console.WriteLine("Values are {0}, {1}", name1, name2); } public static void Possessive(StringBuilder name) { name.Append("'s"); } }

This code generates the following output:


Values are Bobby, Bobby Values are Bobbys, Bobbys

In this example, name1 and name2 always refer to the same StringBuilder instance on the heap. Thus, whenever a change is made to the underlying instance, both variables are affected. Also, name2 is passed by reference to the Possessive method, so that when the Possessive method makes a change to the instance, both name2 and name1 are affected.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

# Elements of the Common Type System


Topic Objective
To provide an overview of the section topics and objectives.
! ! ! ! ! ! !

Primitive Types Objects Constructors Properties Custom Types Enumerations Interfaces

Lead-in
In this section, you will learn about primitive types, objects, properties, and other elements of the Common Type System.

In this section, you will learn about primitive types, objects, properties, and other elements of the Common Type System.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

Primitive Types
Topic Objective
To explain how primitive types are used in the common language runtime.
! ! ! !

Simple Small Types Common in Most Languages Naming Differences C# Support Conversions

Lead-in
Primitive types in the .NET Framework common language runtime are simple value types, commonly found in most programming languages.

Primitive types in the .NET Framework common language runtime are simple value types, which are commonly found in most programming languages. Primitive types are simple small types, such as Boolean types or character types. The following table identifies all of the primitive types available in the .NET Framework common language runtime. The table lists the Microsoft intermediate language (MSIL) assembler name of the type, which you can see when you view the disassembly of managed code in the MSIL Disassembler, the name of the type in C#, the name of the type in the .NET Framework class library, and the description of the type.
Name in MSIL Assembler bool char float32 float64 int8 int16 int32 int64 unsigned int8 unsigned int16 unsigned int32 unsigned int64 Name in C# bool char float double sbyte short int long byte ushort uint ulong Name in class library System.Boolean System.Char System.Single System.Double System.SByte System.Int16 System.Int32 System.Int64 System.Byte System.UInt16 System.UInt32 System.UInt64 Description True/false value Unicode 16-bit char IEEE 32-bit float IEEE 64-bit float Signed 8-bit integer Signed 16-bit integer Signed 32-bit integer Signed 64-bit integer Unsigned 8-bit integer Unsigned 16-bit integer Unsigned 32-bit integer Unsigned 64-bit integer

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 5: Common Type System

The following example shows how to create and initialize the primitive System.UInt16 type in C# to store an employees age:
System.UInt16 age = new System.UInt16(); age = 5;

Primitive types are inherently supported in C#, allowing you to use simpler syntax, as in the following example:
ushort age = 5;

You can convert primitive types by using the Convert class. The Convert class defines static methods to convert from one primitive type to another. The following example shows how to convert a long type to an unsigned short type:
long longAge = 32; ushort ushortAge; ushortAge = Convert.ToUInt16(longAge);

C# provides a more convenient conversion mechanism: casting. The following example shows how to explicitly cast a long type to an unsigned short type:
long longAge = 32; ushort ushortAge; ushortAge = (ushort) longAge;

Casting in C# will automatically compile to conversion methods, such as ToUInt16. Also, you can use casting to avoid memorizing the class library names for primitive types.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

11

Objects
Topic Objective
To explain the role of object types in the Common Type System.
! ! ! !

Every Class Inherits from System.Object Objects Specify Data and Behavior Fields Define the Data Methods Define the Behavior

Lead-in
Everything in the Common Type System is an object and inherits from System.Object.

class Accumulator class Accumulator { { public float Result; public float Result; public void Add(float amount) public void Add(float amount) { { Result += amount; Result += amount; } } } }

Everything in the Common Type System is an object and inherits from System.Object. An object type declaration specifies data and behavior. The Common Type System defines data in terms of fields and defines behavior in terms of methods. Each field or method in an object is called a member of that object. An object is an instance of a class. The class specifies the types that are contained in a class and the classs operations; an object is an instance containing a set of data values. In C#, you can use the class keyword to declare an object type that is a reference type. The following example shows how to declare a class called Accumulator.
class Accumulator { // Fields and methods defined here }

Fields
Fields describe the data in an object. In the preceding example of the Accumulator class, a field is needed to store the current result that has been accumulated.
class Accumulator { public float Result; }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 5: Common Type System

Methods
Methods describe the operations in an object. A method can have arguments and can also have a return type. Because the Common Type System requires strong typing, you must define a specific type for every parameter and return value. The following example shows how to specify an Add method for the Accumulator class that takes an amount of type float and adds it to the Result field.
class Accumulator { public float Result; public void Add(float amount) { Result += amount; } }

The following code is an example of client code:


Accumulator calc = new Accumulator(); calc.Result = 0; calc.Add(5); Console.WriteLine(calc.Result);

This code generates the following output:


5

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

13

Constructors
Topic Objective
To explain how to use constructors to initialize classes.
! !

Constructors Are Used to Initialize Classes Constructors Can Have Zero or More Parameters

Lead-in
If you design a class that requires special initialization code, you can use a constructor to initialize the class properly when objects are created.

class Rectangle class Rectangle { { private int x1,y1,x2,y2; private int x1,y1,x2,y2; public Rectangle(int x1, int y1, int x2,int y2) public Rectangle(int x1, int y1, int x2,int y2) { { this.x1 = x1; this.x1 = x1; this.x2 = x2; this.x2 = x2; this.y1 = y1; this.y1 = y1; this.y2 = y2; this.y2 = y2; } } } }

If you design a class that requires special initialization code, you can use a constructor to initialize the class properly when objects are created. A constructor is a method with the same name as the class. The constructor runs when a new instance of the class is created.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 5: Common Type System

The following example shows how a constructor is used to initialize a class:


public class Rectangle { //Rectangle coordinates private int x1,y1,x2,y2; //Initialize coordinates in constructor public Rectangle() { x1 = 0; x2 = 0; y1 = 0; y2 = 0; } } public class MainClass { public static void Main() { //Creating a new Rectangle //will call constructor Rectangle r = new Rectangle(); } }

Default Constructor
If you do not specify a constructor, the C# compiler will automatically provide a default constructor. The default constructor takes no parameters and calls the base class constructor.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

15

Parameterized Constructor
You can also create a constructor with parameters as follows:
class Rectangle { //Rectangle coordinates private int x1,y1,x2,y2; //Initialize coordinates in constructor public Rectangle(int x1, int y1, int x2,int y2) { this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2; } } public class MainClass { public static void Main() { //Must specify parameters //for this constructor Rectangle r = new Rectangle(2,2,10,10); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 5: Common Type System

Properties
Topic Objective
To describe how to use properties.
! !

Properties Are Similar to Fields Properties Use get and set Accessor Methods for Managing Data Values
public float Start public float Start { { get get { { return start; return start; } } set set { { if (start >= 0) start = value; if (start >= 0) start = value; } } } }

Lead-in
Properties are values that can be stored or retrieved on a class.

Properties are values that can be stored or retrieved on a class. Like fields and methods, properties are also considered members of an object. Properties are different from fields because access to properties is controlled through get and set accessor methods. Also, properties are not necessarily stored in a single variable. They may be calculated on the fly or stored in multiple variables.

get and set Accessors


Property storage and property retrieval are defined by the get and set accessor methods. You write code in the get accessor method to determine how to retrieve a property value. You write code in the set accessor method to determine how to store a property value. By omitting the get or the set accessor, you can make a property read-only or write-only.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

17

The following example shows how to implement a Distance class, which can calculate the length of a trip from start to finish. The class contains three properties: Start, Finish, and Length. The Length property is read-only and is calculated on the fly.
class Distance { float start, finish; public float Start { get { return start; } set { if (start >= 0) start = value; } } public float Finish { get { return finish; } set { if (finish >= start) finish = value; } } public float Length { get { return (finish - start); } } public class MainClass { public static void Main() { Distance d = new Distance(); d.Start = 5; d.Finish = 10; float length = d.Length; } } }

In the preceding example, verification code is used in the set statements to control how the properties are set. Negative numbers are not allowed. Additional code could be written to throw an exception if invalid values are used.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 5: Common Type System

The client code in MainClass does not have to use method syntax with parentheses to refer to properties. In general, you should always use properties to expose data items to external classes. Properties allow you to encapsulate fields, so that you can change them in the future, if necessary. For more information about encapsulation, see Encapsulation in this module.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

19

Custom Types
Topic Objective
To describe how to build data types that use the C# struct keyword.
! ! !

Inherit from System.ValueType Are Defined with the struct Keyword in C# Can Have Methods, Properties, and Fields

Lead-in
You can build your own data type by using the C# struct keyword.

struct Employee struct Employee { { public string Name; public string Name; public ushort Age; public ushort Age; public DateTime HireDate; public DateTime HireDate; public float Tenure() public float Tenure() { { TimeSpan ts = DateTime.Now HireDate; TimeSpan ts = DateTime.Now HireDate; return ts.Days/(float)365; return ts.Days/(float)365; } } } }

You can build your own data types by using the C# struct keyword. The struct keyword will define a custom type that inherits from System.ValueType, which in turn inherits from System.Object. All value types are sealed; additional classes cannot be derived from them. The following example shows how the C# struct keyword is used to build a simple custom type that describes an individual employee:
struct Employee { public string Name; public ushort Age; public DateTime HireDate; }

In C#, structures can also have methods as in the following example:


struct Employee { public string Name; public ushort Age; public DateTime HireDate; public float Tenure() { TimeSpan ts = DateTime.Now HireDate; return ts.Days/(float)365; } }

Structures can also have properties. For example, the Employee structure could be modified so that employee age is a property. Then the set accessor could be used to verify that the age is a valid age.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 5: Common Type System

Enumerations
Topic Objective
To describe how to create enumerations, which allow developers to specify and represent simple types.
!

.NET Framework Enumerations


$ $

Lead-in
It is common for a variable to take on only one of a small number of values.
!

Inherit from System.Enum Use the enum keyword

Bit Flags

enum SeatPreference : ushort enum SeatPreference : ushort { { Window, //Assigned value 0 Window, //Assigned value 0 Center, //Assigned value 1 Center, //Assigned value 1 Aisle //Assigned value 2 Aisle //Assigned value 2 } }

In programming, it is common for a variable to take on only one of a small number of values. For example, the variable for an airline passengers seating preference has only three values: Window, Center, or Aisle. It is much easier and safer for a developer to reference such values with text, rather than numbers. The .NET Framework common language runtime supports enumerations, which allow a developer to specify and represent these simple types.

.NET Framework Enumerations


In the .NET Framework, enumerations inherit from the class System.Enum, which inherits from System.ValueType. The following example shows how to create an enumeration:
enum SeatPreference : ushort { Window, //Assigned value 0 Center, //Assigned value 1 Aisle //Assigned value 2 }

In the preceding example, the base type of the enumeration is defined as ushort. You can use any simple type for a base type, except System.Char. An enumeration will be of type int, unless otherwise specified. The literals are specified in a comma-delimited list. Unless you specify otherwise, the first literal is assigned a value of 0, the second a value of 1, and so on.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

21

To use enumeration literals, you must fully specify the literal name as in the following example:
SeatPreference sp; //Assign enumerated window type seat to sp variable sp = SeatPreference.Window; Console.WriteLine(sp.GetHashCode()); Console.WriteLine(sp.ToString());

This code generates the following output:


0 Window

The GetHashCode method will return the literal value. By using the ToString method, you can obtain the human-readable string name of the literal from a variable. This feature is useful when you need to print or save a human-readable form of the enumerations literals. Also, you can use the Parse method to obtain an enumerated value from a string. This feature is useful when receiving input in a text form that requires conversion to the appropriate enumerated value. The following example shows how to convert the string center into an enumerated value for the SeatPreference enumeration.
sp = (SeatPreference) System.Enum.Parse(typeof(SeatPreference), Center);

Bit Flags
Enumerations in the .NET Framework are also useful for storing bit flags that often involve bitwise operations, such as the bitwise AND operator (&), and the bitwise OR operator (|).

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 5: Common Type System

Use the Flags attribute to create an enumeration of bit flags. The following example refers to a computer-controlled weather display that uses icons to represent weather conditions. The enumeration would allow you to combine the icons in various ways to represent different conditions:
[Flags] enum WeatherDisplay : ushort { Sunny = 1, Cloudy = 2, Rain = 4, Snow = 8, Fog = 16 } WeatherDisplay wd; //Assign both Sunny and Cloudy attributes //to create partly sunny forecast wd = WeatherDisplay.Sunny | WeatherDisplay.Cloudy; Console.WriteLine(wd.ToString()); wd = (WeatherDisplay)System.Enum.Parse(typeof(WeatherDisplay), "Rain, Snow"); Console.WriteLine(wd.GetHashCode());

This code generates the following output:


Sunny, Cloudy 12

When using the Flags attribute, you must specify the values for the literals manually.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

23

Interfaces
Topic Objective
To describe the uses of interfaces.
!

An Interface Is a Contractual Description of Methods and Properties An Interface Has No Implementation Use Casting in Client Code to Use an Interface

Lead-in
An interface is a contractual description of a set of related methods and properties.

! !

interface ICDPlayer interface ICDPlayer { { void Play(short playTrackNum); void Play(short playTrackNum); void Pause(); void Pause(); void Skip(short numTracks); void Skip(short numTracks); short CurrentTrack short CurrentTrack { { get; get; set; set; } } } }

An interface is a contractual description of a set of related methods and properties. An interface has a name, and it has methods and properties. For example, an interface named ICDPlayer may have methods, such as Play, Pause, and Skip. It may also have properties, such as CurrentTrack and Time. The following example shows how to define an interface called ICDPlayer that has the methods Play, Pause, and Skip, and has the property CurrentTrack:
interface ICDPlayer { void Play(short playTrackNum); void Pause(); void Skip(short numTracks); short CurrentTrack { get; set; } }

An interface has no implementation. Any class can inherit from any interface. To inherit from an interface, a class must implement all methods, properties, and events on that interface. Thus an interface serves as a contract specifying to any user of the class that the class has implemented all methods properties, and events defined in the interface. The following example shows how to implement the ICDPlayer interface in a class called Device.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 5: Common Type System


public class Device : ICDPlayer { // Internal property values protected string deviceName; protected short currentTrack; //Constructor public Device() { deviceName = "Default"; currentTrack = 1; } //Properties public string DeviceName { get { return deviceName; } set { deviceName = value; } } public short CurrentTrack { get { return currentTrack; } set { currentTrack = value; } } //Methods public void Play(short playTrackNum) { Console.WriteLine("Now Playing Track: {0}", playTrackNum); currentTrack = playTrackNum; } public void Pause() { Console.WriteLine("Now Paused"); } public void Skip(short numTracks) { Console.WriteLine("Skipped {0} Tracks",numTracks); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

25

In the preceding example, all of the methods and properties of ICDPlayer were implemented. A class may implement additional properties and methods, such as the DeviceName property in the Device class. Client code uses an interface by casting to the interface name. The following example shows how a client can create an instance of the Device class and then use the ICDPlayer interface:
public class MainClass { public static void Main() { Device Device1 = new Device(); ICDPlayer CD1 = (ICDPlayer) Device1; //Call Play method on ICDPlayer interface CD1.Play(1); //Get CurrentTrack property of ICDPlayer interface Console.WriteLine("Current Track = {0}", CD1.CurrentTrack); //Get DeviceName property of Device object Console.WriteLine("Device Name = {0}", Device1.DeviceName); } }

In the preceding example, the Device1 variable also could have been used to access methods and properties of the ICDPlayer interface. For more information about how to separate interface methods and properties from class methods and properties, see Module 6, Working with Types, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 5: Common Type System

# Object-Oriented Characteristics
Topic Objective
To provide an overview of the topics covered in this section.
! ! ! !

Abstraction Encapsulation Inheritance Polymorphism

Lead-in
In this section, you will learn how the object-oriented characteristics of the .NET Framework common language runtime are supported.

In this section, you will learn how the object-oriented characteristics of the .NET Framework common language runtime are supported. Everything in the common language runtime is an object that encompasses fields, methods, properties, and events. Object-oriented characteristics, such as abstraction, encapsulation, inheritance, and polymorphism, make it easier to work with code in the .NET Framework.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

27

Abstraction
Topic Objective
To describe the use and advantages of abstraction in object-oriented programming.
! !

Abstraction Works from the Specific to the General Grouping Elements Makes It Easier to Work with Complex Data Types Abstraction Is Supported Through Classes

Lead-in
In object-oriented programming, the term abstraction refers to the process of reducing an object to its essence so that only essential elements are represented.

In object-oriented programming, the term abstraction refers to the process of reducing an object to its essence so that only essential elements are represented. For programmers, abstraction means working from the specific to the general. An example of abstraction would be a phone number, such as (206) 555-1212. At the specific level, this phone number is a sequence of numbers: 2065551212. However, most people do not memorize phone numbers at this specific level. Instead they memorize such information by grouping the numbers into meaningful chunks. In this example, the phone number becomes an area code (206), prefix (555), and number (1212). This abstraction makes it easier for a person to remember the number. The number is reduced to three chunks to memorize, instead of 10 individual numbers. Abstraction is a powerful process that allows people to group and communicate information in simpler and more meaningful ways. In the Common Type System and other object-oriented systems, the fundamental unit of abstraction is the class. Class types allow you to group different types of information, and they provide the functionality to help you operate on that information. From a design perspective, abstraction allows you to treat information and functionality as complete functional units, rather than as disparate pieces of information and operations.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

28

Module 5: Common Type System

Encapsulation
Topic Objective
To explain the process of encapsulation in objectoriented programming.
!

Encapsulation Is the Process of Hiding Internal Details of a Class Encapsulation Keywords


$ $ $ $

Lead-in
Encapsulation, or information hiding, is the process of packaging attributes and functionality to prevent other objects from manipulating data or procedures directly.

public protected internal private

! !

Type-Level Accessibility Nested Classes

In object-oriented programming, encapsulation, or information hiding, is the process of packaging attributes and functionality to prevent other objects from manipulating data or procedures directly. Encapsulation also allows the object that is requesting service to ignore the details of how the service is provided. By hiding the internal unnecessary data and functionality of a class from other classes, encapsulation provides greater flexibility in the design of classes. For example, when a sorting class performs sorts on data items, the internal data structure of the class will probably store the data items, such as a linked list. The class will also have internal functions that operate on the linked list. If clients that use the sorting class have direct access to the linked list, they will incorporate code that relies on the linked list. In fact, if no accessor functions are written for the linked list, the clients must use the linked list to store or retrieve data items. If the sorting class changes in the future, it may change the linked list to an array for optimization, and the clients will stop functioning correctly. At that time, the clients would require rewriting to use the array syntax. If the sorting class hid the internals of its implementation and provided accessor functions that mapped to the internal data structure, this problem could be avoided. C# provides a set of access modifiers that vary the degree of accessibility to members of any type. The following table lists all of the access modifiers supported in C#.
Access modifier public protected internal private Description Makes a member available to all other classes in all assemblies Makes a member available only to classes that inherit from this class Makes a member available only to other classes in the same assembly Makes a member available only to the same class

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

29

If no access modifier is specified, a default modifier is applied. The following table shows which modifiers are applied to different types by default.
Members of enum class interface struct Default member accessibility public private public private

Type-Level Accessibility
You can specify accessibility at the type level and at the member level. Access modifiers can be applied to enumerations, classes, interfaces, and structs. However, for top-level types, internal and public are the only allowed modifiers. You cannot create a private class or a protected interface at the top level in a namespace. The access modifier applied at the type level will supercede member-level access modifiers if the type-level access modifier is more restrictive. For example, an internal class can have a public method, but the internal modifier will make the public method internal as well. The following example shows the effect of applying access modifiers at the class level and the member level:
public class COuter1 { public static short MyPublicShort = 0; internal static short MyInternalShort = 0; private static short MyPrivateShort = 0; } public class MainClass { public static void Main() { COuter1.MyPublicShort = 1; //Success because publicly available COuter1.MyInternalShort = 2; //Success because in same assembly COuter1.MyPrivateShort = 3; //Failure because private only available to COuter1 class } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

30

Module 5: Common Type System

Nested Classes
When classes are nested, the nested classes cannot exceed the accessibility of the containing class. For example, if a nested class is marked as public, but the containing class is marked as internal, the nested class must also be internal. The following example shows the effect of access modifiers on nested classes:
internal class COuter1 { public class CInner1 { public static short MyPublicShort = 0; internal static short MyInternalShort = 0; private static short MyPrivateShort = 0; } internal class CInner2 { public static short MyPublicShort = 0; internal static short MyInternalShort = 0; private static short MyPrivateShort = 0; } private class CInner3 { public static short MyPublicShort = 0; internal static short MyInternalShort = 0; private static short MyPrivateShort = 0; } } public class MainClass { public static void Main() { COuter1.CInner1.MyPublicShort = 1; //Success because internal at class level //and in same assembly COuter1.CInner2.MyPublicShort = 2; //Success because internal and in same assembly COuter1.CInner3.MyPublicShort = 3; //Failure because class is private, and all members are private } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

31

Inheritance
Topic Objective
To explain how inheritance works in the Common Type System.
!

Lead-in
Inheritance is a method of reuse that enables one class to reuse, or inherit, the fields, properties, and methods of another class.
!

Inheritance Is the Reuse of Class Members in Other Classes The Common Type System Only Supports Single Inheritance for Classes Member Hiding
$ $

Redefine the same method in the derived class Use the new keyword

! !

Abstract Members Sealed Classes

In object-oriented programming, inheritance is a method of reuse that enables one class to reuse, or inherit, the fields, properties, and methods of another class. Inheritance represents an is a relationship between classes. For example, if a square class inherits from a shape class, the square is a kind of shape. Inheritance is useful when multiple classes share the same methods or data. The common methods and data can be abstracted into a separate class that the other classes inherit from. Inheritance is pervasive in the Common Type System. Every class must inherit from System.Object, so all classes will have the members of System.Object.

Single Inheritance
The Common Type System only supports single inheritance of class types. Single inheritance means a class can inherit directly from only one other class. Some object-oriented systems, such as C++, allow multiple inheritance, which means that one class can inherit from many other classes. The Common Type System does support multiple inheritance through interfaces. In that case, one class can inherit from one other class and from zero or more interfaces. For more information about multiple inheritance through interfaces, see Module 6, Working with Types, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease). In the simplest form of inheritance, a class inherits its members from the base class and gains all the functionality of the base class, and at the same time it adds additional functionality of its own. In the following example, three classes are defined. The base class is called Animal; it implements an Age property and a Move method. The second class is called Dog; it inherits from Animal and implements an additional method called Bark. The third class is called Cat; it also inherits from Animal and implements an additional method called Meow.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

32

Module 5: Common Type System


public class Animal { protected short age = 0; public short Age { get { return age; } set { if (value > 0) age = value; } } public void Move() { Console.WriteLine("Animal is Moving"); } } public class Dog : Animal { public void Bark() { Console.WriteLine("Bark!"); } } public class Cat : Animal { public void Meow() { Console.WriteLine("Meow!"); } } public class MainClass { public static void Main() { Dog d = new Dog(); Cat c = new Cat(); d.Age = 3; d.Move(); d.Bark(); c.Age = 2; c.Move(); c.Meow(); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

33

This code generates the following output:


Animal is Moving Bark! Animal is Moving Meow!

In the Main method, a Dog object and Cat object are created. Methods and properties of the Animal class are called on the Dog object and the Cat object. In this way, the Animal class functionality for storing the age of an animal and implementing movement in an animal can be written once and reused in multiple classes.

Member Hiding
Sometimes you will want a class to inherit from a base class, but you will want to modify some of the base classs functionality. For example, you may want a new kind of animal class called Slug to inherit from the Animal class, but you will want to use the Move method to make the slug move slowly. You can accomplish this effect by creating a method with the same name and parameter list as the base class method. The following example shows how you can customize the Move method for slugs by making the Slug class replace the Move method of the Animal class:
public class Slug : Animal { public new void Move() { Console.WriteLine("Moving very slowly"); } } public class MainClass { public static void Main() { Slug s = new Slug(); s.Move(); } }

This code generates the following output:


Moving very slowly

In the preceding example, the new keyword is used to signal that a method was replaced. In this context, the new keyword denotes that a method was hidden. This use of the new keyword should not be confused with the use of the new keyword to allocate a new object. While the new keyword is not required for method hiding, it enhances readability. The C# compiler will issue a warning if the new keyword is not used on replaced methods.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

34

Module 5: Common Type System

Abstract Members
Methods, fields, and properties can also be abstract. A method, field, or property is abstract when the base class does not implement the member, and the derived class must implement the member. Abstract members are marked with the abstract keyword. When derived classes implement abstract methods, they must use the override keyword to indicate that they are overriding the base-class functionality. The following example shows an abstract Shape class that has one abstract method called Draw. The Shape class implements a Move method, which, when called, will call the derived class Draw method. Thus the Shape class has information about how to move but does not have information about how to draw after it moves. The abstract method forces the derived class to implement the Draw method so that the Shape class can move properly.
using System; abstract class Shape { protected int x, y; //Derived class must implement next method public abstract void Draw(); public void Move(int x, int y) { this.x = x; this.y = y; //Call derived class implementation Draw(); } } class Square : Shape { public override void Draw() { Console.WriteLine("Drawing a Square at {0},{1}",x,y); } } class MainClass { public static void Main() { Square s = new Square(); //Call base class Move method, which in turn calls //derived class Draw method s.Move(1,1); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

35

This code generates the following output:


Drawing a Square at 1,1

If a class contains any abstract members, the entire class becomes an abstract class. As a result, an instance of the abstract class cannot be created because it is missing functionality for a method. For this reason, the Shape class in the preceding example was marked as abstract.

Sealed Classes
You can prevent other classes from deriving from a specific class by sealing that class. Use the sealed modifier to make a sealed class.
sealed class SealedClass { public static void Foo() { } }

The sealed modifier is primarily used to prevent unintended derivation, but it also enables certain run-time optimizations. In particular, because a sealed class is known to never have any derived classes, it is possible to transform virtual function member invocations on sealed class instances into non-virtual invocations.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

36

Module 5: Common Type System

Polymorphism
Topic Objective
To explain the use of polymorphism to define a base class.
!

Lead-in
In object-oriented programming, polymorphism allows you to define a base class that includes routines that perform standard operations on groups of related objects, without regard to the exact type of each object.
!

Polymorphism Allows a Reference Variable to Call the Correct Method Virtual Methods Enable Polymorphism in the Common Type System
$ $

Use the virtual keyword in the base class Use the override keyword in the derived class

Sealed Methods

Polymorphism derives from the Greek for many forms. In object-oriented programming, polymorphism allows you to define a base class that includes routines that perform standard operations on groups of related objects, without regard to the exact type of each object. For example, in the preceding animal scenario, you could add a method called MakeNoise. When this method is called, Animal objects should print Animal is making noise. A dog object should print Bark!, and a cat object should print Meow! In the following example, the code does not work as expected; it prints Animal is making noise, instead of the desired specific animal noise, such as Bark or Meow:
public abstract class Animal { //..Other properties and methods public void MakeNoise() { Console.WriteLine("Animal is making noise"); } } public class Dog : Animal { //..Other properties and methods public new void MakeNoise() { Console.WriteLine("Bark!"); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System


public class Cat : Animal { //..Other properties and methods public new void MakeNoise() { Console.WriteLine("Meow!"); } } public class MainClass { public static void Main() { Dog d = new Dog(); Cat c = new Cat(); d.Age = 3; c.Age = 2; WorkWithAnimal(d); WorkWithAnimal(c); } public static void WorkWithAnimal(Animal a) { Console.WriteLine("Working with animal age {0}",a.Age); a.MakeNoise(); } }

37

This code generates the following output:


Working with animal age 3 Animal is making noise Working with animal age 2 Animal is making noise

In the preceding example, because the reference in the WorkWithAnimal method is type Animal, the Animal base class MakeNoise always gets called. The desired behavior would be a dog object making a noise like a dog, not an animal.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

38

Module 5: Common Type System

To resolve this problem, use the virtual keyword to mark a method as virtual. Using the virtual keyword will ensure that the correct method call gets called on the basis of the object type, not the reference type. The derived class must then use the override keyword on the same method, as in the following example:
public abstract class Animal { //..Other properties and methods public virtual void MakeNoise() { Console.WriteLine("Animal is making noise"); } } public class Dog : Animal { //..Other properties and methods public override void MakeNoise() { Console.WriteLine("Bark!"); } } public class Cat : Animal { //..Other properties and methods public override void MakeNoise() { Console.WriteLine("Meow!"); } } public class MainClass { public static void Main() { Dog d = new Dog(); Cat c = new Cat(); d.Age = 3; c.Age = 2; WorkWithAnimal(d); WorkWithAnimal(c); } public static void WorkWithAnimal(Animal a) { Console.WriteLine("Working with animal age {0}",a.Age); a.MakeNoise(); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

39

This code generates the following output:


Working with animal age 3 Bark! Working with animal age 2 Meow!

Sealed Methods
You can use the sealed modifier to prevent derived classes from overriding specific methods. Methods marked with the sealed modifier are called sealed methods. The sealed modifier can only be used in conjunction with the override modifier.
class A { public virtual void Foo() {/*...*/ } } class B : A { //Any class derived from B will //not be able to override Foo public sealed override void Foo() {/*..*/ } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

40

Module 5: Common Type System

Lab 5: Building Simple Types


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will create simple types and enumerations, and work with inheritance.

Objectives
After completing this lab, you will be able to:
!" !" !" !" !"

Create enumerations. Create custom value types as structures. Inherit from a base class and override properties and methods. Create constructors. Use appropriate levels of encapsulation through the private and public access modifiers.

Prerequisites
Before working on this lab, you must have:
!"

Knowledge about how to use Microsoft Visual Studio .NET for creating and working with console applications. Knowledge about the C# language. Knowledge about the System.Console namespace for interacting with the console.

!" !"

Estimated time to complete this lab: 45 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

41

Exercise 1 Creating an Enumeration


In this exercise, you will create a simple program that uses an enumeration to reference weekdays. You will enumerate the weekdays, Monday through Friday, as a type. Then you will write code to accept a day from the user, match the day to the enumerated type, and write a response back to the user.

!" create an enumeration To


1. Open the Days project located in the folder <install folder>\Labs\Lab05\Starter\Days. 2. Open the Main.cs file. 3. Create an enumeration called Weekdays. The enumeration should be of type int and should enumerate the literals Monday, Tuesday, Wednesday, Thursday, and Friday.

!" use an enumeration To


1. Locate the Main method of the MainClass class. 2. In the Main method, write code to perform the following tasks: a. Write a question to the console that reads, What day of the week is it? b. Use the Console.ReadLine method to get the users response. c. Determine which day the user selected by parsing the Weekdays enumeration. Store the correct Weekdays literal in a variable of type Weekdays. d. Use a switch statement on the mapped response to determine which day of the week it is. Based on the response, write a string to the user. For example, for Monday, write Monday is the first weekday. For Tuesday, write Tuesday is the second weekday, and so on. 3. Compile and test the code. Run the program and type in a weekday. You should get an appropriate response based on the day you entered.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

42

Module 5: Common Type System

Exercise 2 Creating a Custom Value Type


In this exercise, you will create a custom value type or structure to represent a complex number. Complex numbers have a real part and an imaginary part. You will design the structure to store the real and imaginary parts, and you will perform addition on complex numbers.

!" create a structure To


1. Open the Complex project located in the folder <install folder>\Labs\Lab05\Starter\Complex. 2. Open the Main.cs file. 3. Create a new structure called Complex. a. Create a public member variable called Real of type int. b. Create a public member variable called Imaginary of type int. 4. Create an overloaded Addition operator (+) for the Complex structure. The overloaded operator should look as follows:
public static Complex operator +(Complex c1, Complex c2) { }

a. In the Addition operator method, create a variable called result of type Complex to hold the result of the addition. b. Add c1.Real to c2.Real and store the result in result.Real. c. Add c1.Imaginary to c2.Imaginary and store the result in result.Imaginary. d. Return the result.

!" use the structure To


1. Locate the Main method in the MainClass class. 2. In the Main method, write code to create a variable called num1 of type Complex. 3. Create a second variable called num2 of type Complex. 4. Initialize num1 and num2 with real and imaginary parts. For example, num1 could have values of 2 and 3 for the real and imaginary parts. num2 could have values of 3 and 4 for the real and imaginary parts. 5. Add the two numbers together, and print both the real and imaginary parts. 6. Compile the program and run it. Verify that the result is correct. Using the values above, you should see the results of 5 and 7 for the real and imaginary parts.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

43

Exercise 3 Creating Objects


In this exercise, you will derive new classes from base classes and then use the derived classes. You will work with a base class called Polygon. The class represents the geometric characteristics of polygons. Polygons have a number of sides. Thus the Polygon class defines a NumSides property but does not implement it. The derived classes implement the NumSides property. For example, a Triangle class could be created that overrides the NumSides property and initializes it to 3. A Pentagon class could be created that overrides the NumSides property and initializes it to 5. The Polygon class also implements a Degrees property that returns the sum of all the angles in the polygon. For example, the angles in a triangle always add up to 180 degrees. This simple calculation is based on the number of sides in the polygon, and so the derived class must implement the NumSides property. The Polygon class also defines an abstract method called Area that will return the area of the polygon. The derived class must override this method to calculate the correct area.

!" derive a new class To


1. Open the Shapes project located in the folder <install folder>\Labs\Lab05\Starter\Shapes. 2. Open the Polygon.cs file and study the code for the Polygon class. Notice that it is an abstract class that has an abstract property called NumSides, a property called Degrees, and an abstract method called Area that returns the area inside the polygon. 3. Open the Main.cs file. 4. Create a new class called Square that inherits from Polygon. a. Create private member variables called x1, y1, and size of type int to store the Cartesian coordinates of the upper left corner and the size of the square, which is the length of one side. b. Create a private member variable called numSides of type ushort to store the number of sides that the square has. c. Create a constructor that accepts three integer parameters (x1, y1, size) to construct a new square. Initialize the private member variables to the values passed as parameters. Initialize numSides to 4. d. Override the NumSides property in the base class to return the numSides variable. e. Create read/write properties called X1, and Y1 respectively that map to the private variables x1, and y1. f. Create two read-only properties called X2 and Y2. These represent the lower right coordinate of the square and are calculated by adding size to x1 or y1 respectively. g. Override the Area method to return the area of the square. The area can be calculated with the following formula: (size)2.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

44

Module 5: Common Type System

!" use the derived class To


1. Locate the Main method in the MainClass class. 2. In the Main method, write code to create a new Square object. Initialize the square with values for the upper left corner and size, such as 1, 1, and 4. 3. Write the number of degrees in the square to the console by printing the Degrees property. 4. Write the area to the console by calling the Area method. 5. Write the x1, y1, x2, y2 coordinates to the console by using the properties of the square object. 6. Compile the program and test it. Verify that all the methods and properties work as expected. Given a square with upper left coordinates of 1, 1, and a size of 4, the number of degrees is 360, the area is 16, and the lower right coordinates are 5, 5.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 5: Common Type System

45

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! ! !

An Introduction to the Common Type System Elements of the Common Type System Object-Oriented Characteristics

Lead-in
The review questions cover some of the key concepts taught in the module.

1. What are the differences between value types and reference types? Value types are allocated on the stack, assigned as copies, and passed by value. Reference types are allocated on the heap, assigned as references, and passed by reference.

2. What are the differences between fields and properties? A field is a data value in a class that can be directly accessed and manipulated by other classes. A property is a value in a class that is accessed through get and set accessor methods. The actual data value of a property may be stored in the class instance, or calculated when accessed.

3. How do you create an enumeration in C#? Use the enum keyword: enum name : type { literals }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

46

Module 5: Common Type System

4. What is an interface? An interface is a contractual description of a set of related methods and properties.

5. How is encapsulation supported by the .NET Framework? Encapsulation is supported through access modifiers, such as public, protected, internal, and private.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types


Contents Overview System.Object Class Functionality Specialized Constructors Type Operations Interfaces Managing External Types Lab 6: Working with Types Review 1 2 12 17 27 34 37 42

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

iii

Instructor Notes Module 6


Presentation: 75 Minutes Lab: 45 Minutes After completing this module, students will be able to:
!"

Apply attributes to control visibility and inheritance in classes and interfaces. Create and use interfaces that define methods and properties. Explain how boxing and unboxing works and when it occurs. Use operators to determine types at run time and cast values to different types. Explain what features are available to work with unmanaged types, such as COM types.

!" !" !"

!"

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_06.ppt

Preparation Tasks
To prepare for this module, you should:
!" !"

Read all of the materials for this module. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 6: Working with Types

Module Strategy
Use the following strategy to present this module:
!"

System.Object Class Functionality In this section, discuss how System.Object provides classes to generate hash functions, represent strings, and compare objects for identity and equality. Explain that this section does not cover all of the classes in System.Object, and that other classes are covered elsewhere in the course. For example, finalization and the Finalize method are covered in detail in Module 9, Memory and Resource Management, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

!"

Specialized Constructors This section covers more advanced types of constructors. Explain how static constructors work, when to use them, and when to use private constructors. If the students in your class already have experience in C++, you may not need to spend much time on these topics.

!"

Type Operations The Microsoft .NET Framework common language runtime supports a variety of type operations for working with types. Discuss conversions and conversion operators for determining and converting the type of an object. Also cover how to cast types for conversion and for treating a type as a different type. For experienced C++ programmers, you may be able to cover type conversion and casting quickly. C++ programmers may find it useful that the as operator in C# is similar to dynamic_cast in C++. Spend most of this section discussing boxing and unboxing. Students will need to be aware of the performance consequences of boxing. Explain how you can avoid or minimize these consequences if you must use boxing.

!"

Interfaces Discuss how multiple inheritance works through interfaces and explain how to explicitly implement interfaces. As with the other topics in this module, you may be able to cover this section quickly if your audience is already familiar with object-oriented programming techniques. For experienced C++ programmers, consider mentioning that explicit interface implementation was not possible in C++.

!"

Managing External Types Briefly introduce Platform Invocation Services and COM interoperability. However, note that detailed coverage of these topics is beyond the scope of this course. Recommend that students read more about these topics in the .NET Framework Software Developers Kit (SDK) documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! ! ! ! !

System.Object Class Functionality Specialized Constructors Type Operations Interfaces Managing External Types

Lead-in
In this module, you will learn how to apply your knowledge of the Common Type System to various programming scenarios.

In this module, you will learn how to apply your knowledge of the Common Type System to various programming scenarios. This module will help you understand how to use types efficiently when developing .NET Framework applications. You should understand that many nuances in the type system can affect program clarity and performance if ignored. This module covers the use of attributes to control visibility and inheritance on types and explains how to work with various type operations, such as boxing and unboxing, and type operators. The module then explores how to work with types programmatically by using operators to coerce, cast, or discover types at run time. In addition, this module discusses how to build an interface that supports methods and properties and how to make interface designs more efficient. The module also highlights features that are designed to help you work with unmanaged types, such as COM types. After completing this module, you will be able to:
!"

Apply attributes to control visibility and inheritance in classes and interfaces. Create and use interfaces that define methods and properties. Explain how boxing and unboxing works and when it occurs. Use operators to determine types at run time and cast values to different types. Explain what features are available to work with unmanaged types, such as COM types.

!" !" !"

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

# System.Object Class Functionality


Topic Objective
To provide an overview of the topics covered in this section.
! ! ! !

Hash Codes Identity Equality String Representation

Lead-in
In this section, you will learn about the common methods that you need to override on the System.Object class.

In this section, you will learn about the common methods that you need to override on the System.Object class. This section does not cover finalization and the Finalize method, which are covered in detail in Module 9, Memory and Resource Management, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease). Also, this section does not cover the MemberwiseClone method.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

Hash Codes
Topic Objective
To explain how to use hash codes to perform quick lookups in tables and other types of collections.
! ! !

Hash Code Used to Perform Quick Lookups Override GetHashCode Method on System.Object Should Return Same Hash Code for Objects of Same Value Should Implement Efficient Algorithm

Lead-in
A hash function is used to quickly generate a number, or hash code, that corresponds to the value of an object.
!

struct Student { struct Student { string name; string name; int ID; //Unique for each instance int ID; //Unique for each instance public override int GetHashCode() { public override int GetHashCode() { return ID; return ID; } } } }

A hash function is used to quickly generate a number, or hash code, that corresponds to the value of an object. Hash codes are useful for performing quick lookups in tables, such as the HashTable class, and other kinds of collections. A hash table uses the hash code to drastically limit the number of objects that must be searched to find a specific object in a collection of objects. The hash table does this by getting the hash value of the object and eliminating all objects with a different hash code. This preliminary search leaves only those objects with the same hash code to be searched. Because there are few instances with that hash code, searches are much quicker. System.Object provides a GetHashCode method, which returns an int type. You should override this method to return a hash code on any custom classes or structures that you create. One reason for overriding this method is that when two objects are equal in value, you should get the same hash code for each object if you call GetHashCode. In the case of custom objects, the default implementation of GetHashCode does not give you the same hash code for two objects that are equal in value. A good hash code algorithm will support the best performance by generating a random distribution for all input. You should base your hash code algorithm on one of the unique fields in the class. Also, you should never throw an exception from the GetHashCode method because GetHashCode can be called frequently and should always work reliably.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

The following example shows how to implement GetHashCode for a Student structure that stores a students name and ID.
struct Student { string name; int ID; //Unique for each instance public override int GetHashCode() { return ID; } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

Identity
Topic Objective
To explain how identity is determined in the .NET Framework common language runtime.
!

Compare to Determine If Two References Are Actually the Same Object Use the Object.ReferenceEquals Method to Test Identity

Lead-in
There are two kinds of comparison for objects: identity and equality. This topic covers object identity.

There are two kinds of comparison for objects: identity and equality. This topic covers object identity.

Determining Identity
Two objects are identical if they are, in fact, the same object. Every object in the .NET Framework common language runtime has an identity that makes it unique in the system. In C++, an objects identity is determined by its address. Thus, if two pointers are compared and contain the same address, they point to the same object. In COM, an objects identity is determined by the IUnknown interface. Thus, if two IUnknown interface pointers are compared and contain the same address, they are the same COM object. In the .NET Framework common language runtime, you can use the Object.ReferenceEquals method to compare for identity. Internally, ReferenceEquals compares the addresses of the objects in memory to determine if they are the same object. If they are the same object, ReferenceEquals returns true.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

Using the Object.ReferenceEquals Method


In the following example, a value type variable called x is created and passed in two parameters to the Test method. The Test method compares the two parameters to determine if they are identical.
class MyObject { public int X; } class MainClass { public static void Main() { MyObject obj1 = new MyObject(); obj1.X = 5; Test(obj1, obj1); MyObject obj2 = new MyObject(); obj2.X = 5; Test(obj1, obj2); } public static void Test(MyObject a, MyObject b) { if (Object.ReferenceEquals(a,b)) Console.WriteLine("Identical"); else Console.WriteLine("Not Identical"); } }

This code generates the following output:


Identical Not Identical

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

Equality
Topic Objective
To explain how to override the Equals method and to introduce guidelines for implementing code to provide equality comparison for types.
! ! ! !

Comparing Two Objects to Determine If They Are Equal Override the Equals Method Supply == and != Operators Guidelines
$ $

Lead-in
Objects can also be compared for equality.

If overriding Equals, override GetHashCode If overloading ==, override Equals to use same algorithm If implementing IComparable, implement Equals Equals, GetHashCode, and == operator should never throw exceptions

$ $

Objects can also be compared for equality. The Object.Equals method, equality operator (==), or inequality operator (!=) are used to test equality.

Equals Method
The Equals method is part of the Object class. You should override this method in your classes and structures to perform appropriate behavior when comparing objects of certain types. The default Object.Equals method calls Object.ReferenceEquals which results in an identity comparison instead of a value comparison. In general, you should also override the == and != operators to allow easier syntax to compare objects. The following example shows how to override the Equals method and the == and != operators to test user-defined Rectangle objects for equality.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types


class Rectangle { //Rectangle coordinates public int x1,y1,x2,y2; public Rectangle(int x1, int y1, int x2, int y2) { this.x1 = x1; this.x2 = x2; this.y1 = y1; this.y2 = y2; } public override int GetHashCode() { return x1; } public override bool Equals (Object obj) { //Check for null and compare run-time types. if (obj == null || GetType() != obj.GetType()) return false; Rectangle r = (Rectangle)obj; return (x1 == r.x1) && (y1 == r.y1) && (x2 == r.x2) && (y2 == r.y2); } static public bool operator == (Rectangle r1, Rectangle r2) { //Check for null parameters //Cast to object to avoid recursive call if ((object)r1 == null) return false; //Let Equals method handle comparison return r1.Equals(r2); } static public bool operator != (Rectangle r1, Rectangle r2) { //Check for null parameters //Cast to object to avoid recursive call if ((object)r1 == null) return true; //Let Equals method handle comparison return !r1.Equals(r2); } } class MainClass { public static void Main() { Rectangle r1 = new Rectangle(5,5,50,55); Rectangle r2 = new Rectangle(5,5,50,55); Console.WriteLine(r1.Equals(r2)); Console.WriteLine(r1 == r2); Console.WriteLine(null == r1); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

This code generates the following output:


True True False

Guidelines for Equality Comparison


Use the following guidelines when implementing code to provide equality comparison for types.
!"

Anytime you override the Equals method, also override the GetHashCode method. If two objects are equal, they must return the same hash code. The default implementation of GetHashCode does not return the same value. Anytime you overload the == operator, also override the Equals method and the != operator to use the same algorithm. This technique allows infrastructure code, such as HashTable and ArrayList classes, that uses the Equals method, to behave in the same manner as user code that is written with the == operator. Anytime you implement the IComparable interface, also implement the Equals method, and ensure that both elements use the same algorithm for comparisons. You should also consider overloading the comparison operators because any client code that uses the IComparable interface is also likely to use these operators. The Equals method, GetHashCode method, and comparison operators should never throw an exception. Exceptions in comparison operators can cause confusion because most programmers do not anticipate these types of exceptions. Also, these methods are called frequently and need to be efficient and clean to avoid writing additional error-handling code for what are considered simplistic methods.

!"

!"

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 6: Working with Types

String Representation
Topic Objective
To explain how the ToString method is used in the .NET Framework common language runtime.
!

Override ToString to Customize String Form of a Class

Lead-in
All objects have the ability to represent themselves in a string form.

struct President struct President { { public string FirstName; public string FirstName; public string LastName; public string LastName; public override string ToString() public override string ToString() { { return FirstName + + LastName; return FirstName + + LastName; } } } }
!

Use IFormattable Interface and Format Method for Localized Strings

One characteristic of all objects is the ability to represent themselves in a string form. The ToString method provides this ability for all objects. Methods in the Microsoft .NET Framework common language runtime, such as Console.WriteLine, frequently use ToString. The ToString method also is useful for debugging. The default behavior of the Object.ToString method is to return the name of the class. The following example shows what happens when ToString is called on a President structure.
struct President { public string FirstName; public string LastName; } class MainClass { public static void Main() { President firstPres; firstPres.FirstName = "George"; firstPres.LastName = "Washington"; Console.WriteLine(firstPres); } }

This code generates the following output:


President

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

11

You can override the ToString method to provide custom behavior, as shown in the following example:
struct President { public string FirstName; public string LastName; public override string ToString() { return FirstName + " " + LastName; } } class MainClass { public static void Main() { President firstPres; firstPres.FirstName = "George"; firstPres.LastName = "Washington"; Console.WriteLine(firstPres); } }

This code generates the following output:


George Washington

If an object needs to be represented in localized string forms, you should not override Object.ToString. Instead, you should implement the IFormattable interface and its ToString method. The IFormattable interface can take into account different locales.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 6: Working with Types

# Specialized Constructors
Topic Objective
To provide an overview of the topics covered in this section.
! !

Static Constructors Private Constructors

Lead-in
This section covers more advanced types of constructors. It explains how static constructors work, when to use them, and when to use private constructors.

This section covers more advanced types of constructors. It explains how static constructors work, when to use them, and when to use private constructors.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

13

Static Constructors
Topic Objective
To explain how static constructors work.
!

Lead-in
Static constructors are used to initialize static fields.

Used to Initialize Static Members

class DeviceConnection class DeviceConnection { public static uint ConnectionCount; { public static uint ConnectionCount; public void OpenConnection(string connectionName) public void OpenConnection(string connectionName) { ConnectionCount++; { ConnectionCount++; //Other work to open device } //Other work to open device } static DeviceConnection() static DeviceConnection() { //Initialize static members { //Initialize static members ConnectionCount = 0; } ConnectionCount = 0; } } }
!

.cctor in Disassembly

Static constructors are used to initialize static fields. Static constructors are also known as class constructors and type constructors. Static constructors are called after a program begins running but before the first instance of the class is created. The following example shows a DeviceConnection class that represents a generic connection to a device. The class maintains a static field that holds the current connection count. The static constructor is created with the same name as the class but has the static attribute, rather than the public or private attribute.
class DeviceConnection { public static uint ConnectionCount; public void OpenConnection(string connectionName) { ConnectionCount++; //Other work to open device } static DeviceConnection() { //Initialize static members ConnectionCount = 0; } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 6: Working with Types


class MainClass { public static void Main() { // At some point before next line, // static constructor is called DeviceConnection d = new DeviceConnection(); d.OpenConnection("GameConsole:Joy1/3"); // Next line prints 1 Console.WriteLine(DeviceConnection.ConnectionCount); } }

A static constructor has no access modifiers, such as private or public. Inside a static constructor, only static fields can be used. Instance fields must be initialized in an instance constructor. When the static constructor is viewed in disassembly, it has a different name, .cctor, which stands for class constructor. In disassembly, instance constructors are called .ctor. You can have both types of constructors in the same class. If you initialize a static field inline with a value, a static constructor is created automatically. The following example shows how the DeviceConnection class can be rewritten to use an implicit static constructor. The presence of the static constructor can be verified by viewing the disassembly of the code.
class DeviceConnection { //Next line automatically creates static constructor public static uint ConnectionCount = 0; public void OpenConnection(string connectionName) { ConnectionCount++; //Other work to open device } }

In the preceding example, the static field ConnectionCount is initialized inline to a value of zero. When you initialize static fields inline, a static constructor is implicitly created in which the initialization occurs. If you also provide an explicit static constructor, the inline initialization is compiled into the explicit static constructors. Inside the static constructor, the code for the inline initializations runs first, and then the code that you wrote in the static constructor runs.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

15

Private Constructors
Topic Objective
To explain when to use private constructors.
! ! !

Prevent a Class from Being Instantiated Use Them on Classes with All Static Members Use a Protected Constructor to Inherit from the Class

Lead-in
A private constructor can never be called. Therefore any class with a private constructor cannot be instantiated.

class Trig class Trig { { public static double Sin public static double Sin { //Calculate and return { //Calculate and return public static double Cos public static double Cos { //Calculate and return { //Calculate and return public static double Tan public static double Tan { //Calculate and return { //Calculate and return private Trig(){} private Trig(){} } }

(double x) (double x) sin(x) } sin(x) } (double x) (double x) cos(x) } cos(x) } (double x) (double x) tan(x) } tan(x) }

A private constructor can never be called. Therefore any class with a private constructor cannot be instantiated. The only type of class that uses a private constructor is a class with all static members. The following example shows how a private constructor is used to prevent a class from being instantiated.
class Trig { public static double Sin (double x) { //Calculate and return sin(x) } public static double Cos (double x) { //Calculate and return cos(x) } public static double Tan (double x) { //Calculate and return tan(x) } private Trig(){} }

Classes with all static members can be used to maintain global algorithms, as shown in the preceding example. They can also be used as a singleton class, which has only one set of values and methods that is available while a program is running. One possible use for classes with all static members is maintaining global algorithms, as shown in the previous example. Another use would be for using a class as a singleton class. A singleton class only has one set of values and methods available while a program is running.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 6: Working with Types

To derive from a class with static members, you should mark the constructor as protected. Marking the constructor as protected will prevent programmers from creating instances of the class, but allow other classes to derive from it. Note A class with static members is different than an interface. The static members can contain implementations, a class can have static fields, but an interface cannot.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

17

# Type Operations
Topic Objective
To provide an overview of the topics covered in this section.
! ! !

Conversions Casting Boxing

Lead-in
The .NET Framework common language runtime supports a variety of type operations for working with types.

The .NET Framework common language runtime supports a variety of type operations for working with types. This section discusses conversions and conversion operators for determining and converting the type of an object. This section also discusses how to cast types for conversion and for treating a type as a different type. It also describes boxing and unboxing value types to treat them as reference types.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 6: Working with Types

Conversions
Topic Objective
To explain when and how to use explicit and implicit conversions.
!

Explicit Conversions Implicit Conversions Conversion Operators


static static static static implicit implicit explicit explicit operator operator operator operator byte(Digit d) byte(Digit d) Digit(byte b) Digit(byte b)

Lead-in
Conversion is the process of changing a type to another type.

int x = 5; int x = 5; double y = (double) x; double y = (double) x;


!

int x = 5; int x = 5; double y = x; double y = x;


!

public public public public

Conversion is the process of changing a type to another type. Conversions are necessary when a value of one type must be assigned to a variable of a different type during assignment or when passing arguments to a method call.

Explicit and Implicit Conversions


In explicit conversions, you do not need to specify the name of the type in a cast for assignment conversions or operand conversions. The following example shows how to convert an int value to a double value by using an explicit conversion.
public static bool BiggerThanFive(double value) { if (value > 5) return true; else return false; } public static void Main() { int x = 5; //Use an explicit conversion for assignment double y = (double) x; //Use an explicit conversion for operand bool answer = BiggerThanFive((double) x); }

The preceding example is an example of a widening conversion. The bit size of an int is 32 bits, and the bit size of a double is 64 bits. Therefore, the type was widened during the conversion.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

19

In implicit conversions, you do not need to specify the name of the type during the conversion. Widening conversions can occur implicitly, and so they allow for simpler syntax. The preceding example could be written more simply as follows:
public static void Main() { int x = 5; //Use an implicit conversion for assignment double y = x; //Use an implicit conversion for operand bool answer = BiggerThanFive(x); }

The following table shows the allowable implicit conversions for numeric types in the common language runtime.
From sbyte byte short ushort int uint long char float ulong To short, int, long, float, double, or decimal short , ushort, int, uint, long, ulong, float, double, or decimal int, long, float, double, or decimal int, uint, long, ulong, float, double, or decimal long, float, double, or decimal long, ulong, float, double, or decimal float, double, or decimal ushort, int, uint, long, ulong, float, double, or decimal double float, double, or decimal

Some conversions can result in a loss of precision. For example, converting an int to a float is an allowable implicit conversion, but a float has only seven digits of precision. Depending on the value of the int, some digits of precision may be lost. The following example shows a narrowing conversion in which a double is converted to an integer.
double y = 4.56; int x = (int) y;

In this case, narrowing conversions must be explicit because there is almost always a loss of precision in the value that is being converted. In the preceding example, the value 4.56 will be truncated to 4 when it is assigned to x.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 6: Working with Types

Conversion Operators
You can create user-defined conversions by providing conversion operators in your class or struct. Use the following syntax for specifying a conversion operator: public static [implicit | explicit] operator conv-type-out (conv-type-in operand) in which:
!" !" !"

conv-type-out is the name of the type to convert to. conv-type-in is the name of the type to convert from. operand is the name of the parameter holding the value being converted.

The following example shows how a structure that is called Digit, which represents a value from 0 to 9, can convert implicitly to a byte and explicitly to a Digit.
struct Digit { byte value; public Digit(byte value) { if (value < 0 || value > 9) throw new ArgumentException(); this.value = value; } public static implicit operator byte(Digit d) { //Implicitly convert from Digit to short return d.value; } public static explicit operator Digit(byte b) { //Explicitly convert from short to Digit return new Digit(b); } } class MainClass { public static void Main() { Digit dig = new Digit(3); byte b = dig; //Implicit conversion operator invoked Console.WriteLine(b); //Prints 3 Digit dig2 = (Digit) b; //Explicit conversion invoked Console.WriteLine(dig2); //Implicit conversion prints 3 } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

21

In the preceding example, the conversion from Digit to byte is implicit, while the conversion from byte to Digit is explicit. You should use the following guidelines to determine whether a conversion operator should be implicit or explicit.
!"

A conversion operator should be implicit to make code easier to read. Implicit conversions should never throw an error. A conversion operator should be explicit whenever information could be lost in the conversion or if the conversion could throw an exception.

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 6: Working with Types

Casting
Topic Objective
To explain how casting is used in the .NET Framework.
! ! !

Casting Up from Derived Class to Base Class Casting Down from Base Class to Derived Class Type Operators
$ $ $

Lead-in
Casting is used for explicit conversions. However, casting is also used for changing the type that is used to reference an object.

is as typeof

Casting Interfaces

Casting is used for explicit conversions. However, casting is also used for changing the type that is used to reference an object.

Casting in an Inheritance Hierarchy


Casting on objects is frequently used to change the reference type of an object to a base class reference or a derived class reference. When casting a derived class to a base class, you do not need to explicitly cast the object. The following example shows how a Shape type reference can be used to work with a Square object.
//Shape is a base class class Shape {...} //Square is a derived class class Square : Shape {...} Square sq = new Square(); Shape sh = sq; sh.ShapeMethod();

When casting from a base class to a derived class, you must explicitly cast the object. If you cast to a derived type that does not match the underlying object, an InvalidCastException error will be thrown.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

23

The following example shows how to cast from a base class type to a derived class type.
Square sq = new Square(); Shape sh = sq; Square sq2 = (Square) sh;//Cast down to Square sh = new Shape(); sq2 = (Square) sh;//InvalidCastException

Type Operators
C# provides several operators to help cast object types appropriately. These operators help you avoid InvalidCastException errors. The is operator compares an object to a type. If the type matches the object, true is returned. If the type does not match the object, false is returned.
Shape sh = new Shape(); Square sq; if (sh is Square) sq = (Square) sh;

The as operator attempts to convert an object to a type. If the conversion is successful, a reference of the specified type is assigned. Otherwise, null is assigned.
Shape sh = new Shape(); Square sq = sh as Square; if (sq == null) Console.WriteLine("Shape was not a square"); else Console.WriteLine("Shape was a square");

You can use the typeof operator for more advanced type operations. The typeof operator will return a System.Type instance that describes the type through reflection. If you have an instance of a class, you can call GetType to obtain the same information. For more information about reflection, the mechanism for obtaining information about loaded assemblies and the types defined within them, including classes, interfaces, and value types, see Discovering Type Information at Run time, in the .NET Framework Software Developers Kit (SDK) documentation and Module 2, Creating an Assembly, in Course 2350A, Securing and Deploying Microsoft .NET Assemblies (Prerelease).

Casting Interfaces
Casting is also used to obtain interface references to an object. The following example shows how the interface ICDPlayer can be obtained through casting from the Device class, which implements the ICDPlayer interface.
ICDPlayer player; Device d = new Device(); player = (ICDPlayer) d;//Cast to interface player.Play();

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 6: Working with Types

Boxing
Topic Objective
To explain when and how boxing occurs.
!

Boxing Occurs to Convert a Value Type to a Reference Type


$ $

Lead-in
Boxing and unboxing are conversions that occur automatically when a value type is converted to an object or when an object is converted to a value type.

Instance of System.Object is allocated on heap Value type is copied to new object

int x = 5; //Value type int x = 5; //Value type Object o = x; //Boxed Object o = x; //Boxed Console.WriteLine("The answer is : {0} ", x);//Boxed Console.WriteLine("The answer is : {0} ", x);//Boxed
!

Unboxing Occurs to Retrieve Value Type from Object Boxing Can Be Expensive If Inside Loops

int y = (int) o; //unbox int y = (int) o; //unbox


!

Boxing and unboxing are conversions that occur automatically when a value type is converted to an object or when an object is converted to a value type. Boxing and unboxing occur implicitly and can affect the performance of your application code.

When Boxing Occurs


Boxing occurs when a value type must be converted to a reference type. Boxing only occurs when converting to the type System.Object. Any other reference type must have implicit or explicit conversion operators to convert from value types. The following example shows how an integer value type is converted to an object reference type.
int x = 5; //Value type Object o = x; //Implicit boxing operation occurs

In the preceding example, a boxing operation occurs when the object o is assigned the value in x. Boxing frequently occurs when calling methods that accept parameters of type Object. For example, Console.WriteLine can accept a string and an object parameter as follows.
int x = 5; Console.WriteLine("The answer is: {0}",x);//Boxing occurs

In the preceding example, a boxing operation occurs on the call to Console.WriteLine. Because Console.WriteLine requires an Object type as the second parameter, x is implicitly boxed as an Object type.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

25

You can determine where boxing operations occur in your code by examining the disassembly. For example, if you use the Microsoft intermediate language (MSIL) Disassembler (Ildasm.exe), you will see an operation code called box, which is followed by the type that is being boxed.

How Boxing Works


A value type must be copied from the stack to the heap if the value is going to be treated as a reference type. The boxing operation allocates memory on the heap for the value type and creates a reference to the new memory location. Then it copies the value type into the new memory location.

Unboxing
To work with the value inside a boxed type, it must first be unboxed. Unboxing a type will copy it from the heap into a variable on the stack. The following example shows how to unbox an integer.
int x = 5; Object o = x; //box int y = (int) o; //unbox

If the underlying value type that is being unboxed is incompatible with the type of the variable that it is assigned to, you will get an InvalidCastException.
int x = 5; short s; Object o = x; //box s = (short) o; //Will throw InvalidCastException

Consequences
Boxing can cause performance problems if you do not minimize its occurrence. The following example shows the consequences of boxing.
int age = 5; int count = 1; for (count = 1;count < 10;count++) { Console.WriteLine("Current Age = {0}",age);//1 Box Console.WriteLine("Age in {0} year(s) will be {1}", count, age+count);//2 box operations }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 6: Working with Types

In the preceding example, three boxing operations will occur for every iteration through the loop. This kind of scenario can be very costly in terms of performance. One solution is to box value types before entering a loop, as in the following example.
int age = 5; Object oAge = age; //1 box operation int count = 1; for (count = 1;count < 10;count++) { Console.WriteLine("Current Age = {0}",oAge); Console.WriteLine("Age in {0} year(s) will be {1}", count, age+count);//2 box operations }

In cases when the need for a higher level of performance is necessary, custom classes can be created to encapsulate values and work with values as reference types.
class RefInt32 { public int Value; public RefInt32(int value) { this.Value = value; } public override string ToString() { return Value.ToString(); } public static implicit operator int (RefInt32 refInt) { return refInt.Value; } } int age = 5; RefInt32 refAge = new RefInt32(age); //Convert to ref type int count = 1; RefInt32 refCount = new RefInt32(count); //Convert to ref type RefInt32 refTotal = new RefInt32(0); for (refCount.Value = 1;refCount.Value < 10;refCount.Value++) { refTotal.Value = refAge.Value + refCount.Value; Console.WriteLine("Current Age = {0}",refAge); Console.WriteLine("Age in {0} year(s) will be {1}", refCount,refTotal);//0 box operations }

The preceding example demonstrates the importance of overriding appropriate Object methods to get expected behavior. If the recipient of your reference type calls one of the methods that are expecting appropriate behavior, it may cause problems. In the preceding example, you must override ToString.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

27

# Interfaces
Topic Objective
To provide an overview of the topics covered in this section.
! !

Inheritance Considerations Explicit Interface Implementation

Lead-in
When designing and using interfaces, you should consider a number of factors.

When designing and using interfaces, you should consider a number of factors. This section discusses how multiple inheritance works through interfaces. This section also explains how to explicitly implement interfaces.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

28

Module 6: Working with Types

Inheritance Considerations
Topic Objective
To explain the use of inheritance and the use of interfaces.
!

Multiple Inheritance
{void DoSomething1();} {void DoSomething1();} {void DoSomething2();} {void DoSomething2();} : IFoo, IBar {...} : IFoo, IBar {...}

Lead-in
Interfaces are used only through inheritance.

interface IFoo interface IFoo interface IBar interface IBar class MyObject class MyObject
!

Deriving New Interfaces from Existing Ones

interface INewInterface : IFoo, IBar interface INewInterface : IFoo, IBar {void DoSomething3();} {void DoSomething3();}
!

Base Class Interfaces

Interfaces are used only through inheritance. There are several ways to group or partition functionality when you are using interfaces. You can use multiple inheritance to combine functionality from multiple interfaces. Interfaces also can inherit from other interfaces, allowing functionality to be partitioned into multiple groups.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

29

Multiple Inheritance
In the .NET Framework common language runtime, a class must inherit from only one class. However, a class can inherit from zero or more interfaces in addition to inheriting from one class. Interfaces are the only type to allow multiple inheritance in the common language runtime. The following example shows how a class can inherit from two interfaces.
interface IFoo { void DoSomething1(); } interface IBar { void DoSomething2(); } class MyObject : IFoo, IBar { public void DoSomething1() { Console.WriteLine("DoSomething1 called"); } public void DoSomething2() { Console.WriteLine("DoSomething2 called"); } }

Multiple inheritance is an important design consideration when you are choosing between abstract classes and interfaces. If two sets of functionality are designed into two abstract classes, a single class cannot inherit from both classes. However, if interfaces are used, a single class can inherit from both interfaces. If a specification of functions, properties, or events is likely to be used by many different kinds of classes, you should use an interface instead of an abstract class.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

30

Module 6: Working with Types

Deriving New Interfaces from Existing Ones


You can also create new interfaces by deriving from other interfaces. The following example shows how a new interface that is called INewInterface is created from the IFoo and IBar interfaces.
interface IFoo { void DoSomething1(); } interface IBar { void DoSomething2(); } interface INewInterface : IFoo, IBar { void DoSomething3(); } class MyObject : INewInterface { public void DoSomething1() { Console.WriteLine("DoSomething1 called"); } public void DoSomething2() { Console.WriteLine("DoSomething2 called"); } public void DoSomething3() { Console.WriteLine("DoSomething3 called"); } }

Base Class Interfaces


If you derive a new class from a base class that implements an interface, you must decide if the derived class will also implement the interface. When an instance of the derived class is converted to the interface, the inheritance hierarchy is searched until a class that implements the interface is found. Then the interface methods are called on that class.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

31

The following example shows what happens when interface methods are called on a derived class that does not implement the interface.
interface IFoo { void DoSomething1(); } class Base : IFoo { public void DoSomething1() { Console.WriteLine("Base DoSomething1 called"); } } class Derived : Base { public new void DoSomething1() { Console.WriteLine("Derived DoSomething1 called"); } } class MainClass { public static void Main() { Derived d = new Derived(); IFoo i = (IFoo) d; d.DoSomething1(); i.DoSomething1(); } }

This code generates the following output:


Derived DoSomething1 called Base DoSomething1 called

In the preceding example, the base class DoSomething1 method is called when an IFoo variable is used. If this behavior is not the desired behavior, then the derived class must be modified to also inherit from the IFoo interface. Then the derived class DoSomething1 method will be called when the IFoo variable is used.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

32

Module 6: Working with Types

Explicit Interface Implementation


Topic Objective
To distinguish class accessibility and interface accessibility, and to explain when to use explicit interface implementation.
! !

Class vs. Interface Accessibility Use Explicit Interface Implementation


$

When interface member names that are combined with class names are confusing When inheriting from multiple interfaces with same members

Lead-in
When you implement an interface in a class, the interface methods are exposed through the interface type, and the class type.

interface IFoo {void DoSomething();} interface IFoo {void DoSomething();} interface IBar {void DoSomething();} interface IBar {void DoSomething();} class MyObject : IFoo, IBar { class MyObject : IFoo, IBar { void IFoo.DoSomething() void IFoo.DoSomething() {Console.WriteLine("IFoo DoSomething called");} {Console.WriteLine("IFoo DoSomething called");} void IBar.DoSomething() void IBar.DoSomething() {Console.WriteLine("IBar DoSomething called");} {Console.WriteLine("IBar DoSomething called");} } }

When you implement an interface in a class, the interface methods are exposed through the interface type and the class type. The following example shows how an interface method can be called by both the class type and the interface type.
interface IFoo { void DoSomething(); } class MyObject : IFoo { public void DoSomething() { Console.WriteLine("DoSomething called"); } } class MainClass { public static void Main() { MyObject o = new MyObject(); //Call method through class type o.DoSomething(); IFoo foo = (IFoo) o; //Call method through interface type foo.DoSomething(); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

33

You can use explicit interface implementation to prevent the class type from accessing the method. This technique is useful if the interface member names are likely to confuse a user of the class. Also, explicit interface implementation is mandatory if you inherit from multiple interfaces that have the same members. To use explicit interface implementation, you prepend the name of the interface to the name of the member in your class definition. You should not use any access modifiers in the member definition. Access modifiers are not allowed because the explicit interface implementation is only accessible through the interface type. The following example shows how explicit interface implementation can avoid conflicts between multiple interfaces with the same members.
interface IFoo { void DoSomething(); } interface IBar { void DoSomething(); } class MyObject : IFoo, IBar { void IFoo.DoSomething() { Console.WriteLine("IFoo DoSomething called"); } void IBar.DoSomething() { Console.WriteLine("IBar DoSomething called"); } } class MainClass { public static void Main() { MyObject o = new MyObject(); IFoo foo = (IFoo) o; IBar bar = (IBar) o; foo.DoSomething(); bar.DoSomething(); } }

This code generates the following output:


IFoo DoSomething called IBar DoSomething called

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

34

Module 6: Working with Types

# Managing External Types


Topic Objective
To provide an overview of the topics covered in this section.
! !

Platform Invocation Services COM Interoperability

Lead-in
The .NET Framework common language runtime is not an isolated system. Most programs will require some level of interaction with outside applications.

The .NET Framework common language runtime is not an isolated system. Most programs will require some level of interaction with outside applications. The common language runtime provides Platform Invocation Services for interacting with code in DLLs. Also, the common language runtime provides integration services to interact with COM objects. This course does not cover all aspects of Platform Invocation Services or COM Integration Services. For more information, see Interoperating with Unmanaged Code in the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

35

Platform Invocation Services


Topic Objective
To introduce the use of Platform Invocation Services to call external functions.
! !

Also Known as PInvoke Use dllimport Attribute to Import an API Function from an External DLL

Lead-in
Platform Invocation Services, also known as PInvoke, allow managed code to interact with unmanaged code in existing DLLs.

[DllImport("user32.dll", CharSet=CharSet.Ansi)] [DllImport("user32.dll", CharSet=CharSet.Ansi)] public static extern int MessageBox(int h, string m, public static extern int MessageBox(int h, string m, string c, int type); string c, int type); public static void Main() public static void Main() { string pText = "Hello World!"; { string pText = "Hello World!"; string pCaption = "PInvoke Test"; string pCaption = "PInvoke Test"; MessageBox(0, pText, pCaption, 0); } MessageBox(0, pText, pCaption, 0); }

Platform Invocation Services, also known as PInvoke, allow managed code to interact with unmanaged code in existing DLLs. PInvoke provides the code that is needed to locate and invoke a function and to marshal parameters to and from the function. To call an external function, you use the DllImport attribute to provide the name of the DLL and any other characteristics, such as the use of ANSI or Unicode strings by the DLL. After the function has been declared, you can call it from managed code. The following example shows how to call the MessageBox API located in User32.dll.
using System; using System.Runtime.InteropServices; class MainClass { [DllImport("user32.dll", CharSet=CharSet.Ansi)] public static extern int MessageBox(int h, string m, string c, int type); public static void Main() { string pText = "Hello World!"; string pCaption = "PInvoke Test"; MessageBox(0, pText, pCaption, 0); } }

For more information on PInvoke, see the Platform Invocation Services User Guide in the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

36

Module 6: Working with Types

COM Interoperability
Topic Objective
To introduce COM interoperability.
!

Lead-in
COM interoperability allows managed code to create and call COM objects. It also allows COM objects to create and call .NET Framework objects.

Exposing .NET Framework Classes to COM


$ $ $

Must create COM Callable Wrapper Create CCWs by using Tlbexp.exe Register by using Regasm.exe Must create Runtime Callable Wrapper Create RCWs by using Tlbimp.exe

Exposing COM Classes to the .NET Framework


$ $

COM interoperability allows managed code to create and call COM objects. It also allows COM objects to create and call .NET Framework objects.

Exposing .NET Framework Classes to COM


You can expose .NET Framework classes to COM by creating COM callable wrappers (CCW) for each .NET Framework class in your application. The CCW creates and manages standard COM elements, such as IUknown and other standard interfaces, GUIDs, IIDs, and reference counting. These elements allow COM objects to interoperate with your .NET Framework classes as if the .NET Framework classes were real COM classes. The .NET Framework classes that you write do not need to be aware of any COM elements. However, you can directly control some COM elements when necessary, by such means as specifying manual IIDs for your interfaces. You can create CCWs for your .NET Framework classes by running the Type Library Exporter (Tlbexp.exe). You can also register your .NET Framework classes as COM classes by using the Assembly Registration Tool (Regasm.exe).

Exposing COM Classes to the .NET Framework


Managed code can also create and call existing COM objects. You can accomplish this by creating a Runtime Callable Wrapper (RCW) for each COM class that you want to access from managed code. Similar to the CCW, the RCW handles COM specific semantics, such as reference counting, QueryInterface for different IIDs, and marshaling. Your managed code can use COM interfaces as if they were managed interfaces and COM classes as if they were managed classes. You can create RCWs by using the Type Library Importer (Tlbimp.exe). For more information on COM interoperability, see COM Interoperability Specification in the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

37

Lab 6: Working with Types


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will create a class that overrides methods in System.Object. You will also create an interface that must be implemented explicitly.

Objectives
After completing this lab, you will be able to:
!"

Create classes that override the GetHashCode, and equality methods and operators. Create classes that provide conversion operators. Implement an explicit interface in a class and use it from a client.

!" !"

Lab Setup
Starter and solution files are associated with this lab. The starter files are in the folder <install folder>\Labs\Lab06\Starter, and the solution files are in the folder <install folder>\Labs\Lab06\Solution.

Prerequisites
Before working on this lab, you must have:
!"

Knowledge about how to use Microsoft Visual Studio .NET for creating and working with console applications. Knowledge about the C# language. Knowledge about the System.Console namespace for interacting with the console.

!" !"

Estimated time to complete this lab: 45 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

38

Module 6: Working with Types

Exercise 1 Overriding System.Object Methods


In this exercise, you will create a structure that represents an office in a building. The Office structure stores the size, building number, and room number of an office. You will override appropriate methods and operators to support retrieving hash codes and comparing different offices. You will also create a structure called OfficeUnit that is similar to the Office structure. The only difference between the OfficeUnit structure and the Office structure is that OfficeUnit represents size as an enumerated type with the values small, medium, or large. The Office structure represents size as square footage. You will write an explicit conversion operator to convert values of type Office to type OfficeUnit.

!" implement a hash code To


1. Open the Offices project located in the <install folder>\Labs\Lab06\Starter\Offices folder. 2. Open the Office.cs file. 3. Locate the Office structure. 4. Override the GetHashCode method. Generate and return a hash code by using the following algorithm: HashCode = Building * 10000 + Room

!" provide a string representation To


1. Override the ToString method. 2. Generate and return a string that contains the building number, followed by a forward slash, followed by the room number. You can use the following code to build and return the string.
return String.Concat(Building,"/",Room);

!" implement equality To


1. Override the Equals method. 2. Cast the object parameter to type Office. 3. Compare the size, room, and building numbers of the parameter to this. If the values are all equal, return true. If they are not equal, return false. 4. Override the == and != operators. Implement them by calling the Equals method.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

39

!" implement conversion To


1. Define an explicit conversion operator to convert from type Office to OfficeUnit. 2. Convert the size from square footage to an OfficeSizes value according to the following table. The OfficeSizes enumeration is already defined in the start code for you.
Square Footage <= 64 >64 and <100 >=100 OfficeSizes Small Medium Large

3. Assign the Building and Room values to the new type and return an instance of the new type.

!" test To
1. Open the Main.cs file. 2. Create two offices called o1 and o2. Assign different sizes, room numbers, and building numbers to each office variable. 3. Use the == operator to compare the two offices. Print the results to the console. 4. Call GetHashCode on both offices and print the results. 5. Call ToString on both offices and print the results. 6. Create an OfficeUnit and assign it one of the offices. Use explicit conversion to assign the office. 7. Print all of the values of the OfficeUnit. 8. Compile and run the program. The two offices should not be equal. They should have different hash codes. The ToString method should print the building and room numbers, not the class names. Finally, the printed enumerated size should match the square footage appropriately.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

40

Module 6: Working with Types

Exercise 2 Implementing an Explicit Interface


In this exercise, you will create an interface called IRange, which provides properties and methods to select and print a range. You will also modify a class called TextEntry to inherit from IRange. This combination allows text in the TextEntry class to be selected as a range and printed. The TextEntry class already implements a Print method. Because the IRange interface also has a Print method, you will need to explicitly implement IRange in the TextEntry class to avoid a name conflict.

!" create an explicit interface To


1. Open the Interfaces project located in the <install folder>\Labs\Lab06\Starter\Interfaces folder. 2. Open the TextEntry.cs file. 3. Define an interface called IRange that has the following properties.
Property Name RangeBegin RangeEnd Type uint uint

4. Define the following methods for IRange.


Method Name Select Print Return Type void void Parameters uint rb, uint re none

5. Modify the TextEntry class to inherit from IRange. 6. In the TextEntry class, create private fields named rangeBegin and rangeEnd to store the RangeBegin and RangeEnd data values. Use the uint type for both fields. 7. Implement the IRange RangeBegin property. a. Implement the get accessor by returning the value of rangeBegin. b. Implement the set accessor by storing the value in rangeBegin. Check to ensure that the new value is less than the length of the text field, and that the value of rangeEnd is not less than rangeBegin. 8. Implement the IRange RangeEnd property. a. Implement the get accessor by returning the value of rangeEnd. b. Implement the set accessor by storing the value in rangeEnd. Check to ensure that the new value does not exceed the length of the text field, and that the value of rangeEnd is not less than rangeBegin. 9. Implement the IRange Select method. Ensure that the re parameter is not less than the rb parameter, and that the new values are not greater than the length of the text field. Assign rb to rangeBegin and re to rangeEnd. 10. Implement the IRange Print method. Using the rangeBegin and rangeEnd fields, create a text range from the text field by using the SubString method. Then print the resulting string to the console.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

41

!" use the interface To


1. Open the Main.cs file. 2. In the MainClass class, create an instance of the TextEntry class called myEntry. 3. Create an interface of type IRange named r and cast myEntry to r. 4. Initialize the Text property on myEntry with a value, such as The quick brown fox jumped over the gate. 5. Select a range by using the interface variable r. For example, the values 4 and 10 will select the word quick. 6. Call the Print method on myEntry. 7. Call the Print method on r. 8. Compile and run the program. You should see the entire Text property printed to the console, followed by the range of text you selected.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

42

Module 6: Working with Types

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! ! ! ! !

System.Object Class Functionality Specialized Constructors Type Operations Interfaces Managing External Types

Lead-in
The review questions cover some of the key concepts taught in the module.

1. What kind of algorithm should you use to implement the GetHashCode method? The algorithm should be efficient and return a unique number.

2. What is the default behavior of the ToString method? The default behavior of the ToString method is to return the name of the class.

3. How can you determine if two separate object references are the same object? Use the ReferenceEquals method to compare the two references.

4. If you override the Equals method, what else should you override? You should override the == and != operators.

5. When should you use a private constructor? Use a private constructor to prevent a class from being instantiated. An example of such a class is a singleton class with static methods and fields.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 6: Working with Types

43

6. When should you use implicit conversions, and when should you use explicit conversions? Use implicit conversions for improved readability and use. Use explicit conversions when the conversion could cause a loss of data or throw an exception.

7. When do boxing operations occur? Boxing occurs when a value type is converted to an Object type. Unboxing occurs when the value is retrieved from an Object type.

8. How do you explicitly implement an interface? Do not use the public access modifier. Use the name of the interface in front of the field or method names. For example, void IFoo.DoSomething().

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

THIS PAGE INTENTIONALLY LEFT BLANK

Module 7: Strings, Arrays, and Collections


Contents Overview Strings Terminology Collections .NET Framework Arrays .NET Framework Collections Lab 7: Working with Strings, Enumerators, and Collections Review 1 2 20 21 39 57 63

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

iii

Instructor Notes Module 7


Presentation: 120 Minutes Lab: 60 Minutes After completing this module, students will be able to:
!" !" !"

Parse, format, manipulate, and compare strings. Use the classes in the System.Array and System.Collections namespaces. Improve the type safety and performance of collections by using specialized collections and class-specific code.

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_07.ppt

Preparation Tasks
To prepare for this module, you should:
!" !" !"

Read all of the materials for this module. Practice the demonstrations. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 7: Strings, Arrays, and Collections

Demonstrations
This section provides demonstration procedures that will not fit in the margin notes or are not appropriate for the student notes.

Sorting and Enumerating an Array


In this demonstration, you will show students how to sort and enumerate an array. The code for this demonstration is contained in one project and is located in <install folder>\Democode\Demo07\Demo07.1. In addition, the code for the individual demonstration is provided in the student notes.

ArrayList
In this demonstration, you will show students how ArrayList implements the IList interface by using an array whose size is dynamically increased as required. The code for this demonstration is contained in one project and is located in <install folder>\Democode\Demo07\Demo07.2. In addition, the code for the individual demonstration is provided in the student notes.

Hashtable
In this demonstration, you will show students how to create a hash table that is used for searches. The code for this demonstration is contained in one project and is located in <install folder>\Democode\Demo07\Demo07.3. In addition, the code for the individual demonstration is provided in the student notes. In all of the preceding demonstrations, use the debugger to step through the code while you point out features.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

Module Strategy
Use the following strategy to present this module:
!"

Strings Discuss how to work with strings in the Microsoft .NET Framework, including common operations, such as parsing, formatting, manipulating, and comparing strings.

!"

Terminology Collections Define the term collection as it is used in this module and identify where collections are found in the .NET Framework. Be sure that students understand that the term collection is used in its broader sense: to describe a group of items.

!"

.NET Framework Arrays Introduce the System.Array class as the base class of all array types that contains methods for creating, manipulating, searching, and sorting arrays. Discuss features of arrays that are specific to C#. Explain the role of the IEnumerable and IEnumerator interfaces in System.Array and System.Collections classes. Use the Sorting and Enumerating an Array demonstration to show how to sort and enumerate an array.

!"

.NET Framework Collections Briefly introduce some commonly used classes in the System.Collections namespace. Discuss the IList interface with regards to classes that represent an ordered collection of objects that can be individually indexed. Use the ArrayList demonstration to reinforce this concept. Discuss the IDictionary interface and the classes that it implements. Use the Hashtable demonstration to show how to use the IDictionary interface. Provide guidelines to help students distinguish between collections and arrays, and explain when collections are used. Discuss runtime casting for type safety and the effects of runtime casting, and boxing and unboxing on performance. Discuss techniques for handling boxing and unboxing to optimize performance.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! ! ! !

Strings Terminology Collections .NET Framework Arrays .NET Framework Collections

Lead-in
In this module, you will learn about some of the key classes in the .NET Framework class library.

In this module, you will learn about some of the key classes in the Microsoft .NET Framework class library. Specifically, you will learn how to work with strings, arrays, collections, and enumerators. After completing this module, you will be able to:
!" !" !"

Parse, format, manipulate, and compare strings. Use the classes in the System.Array and System.Collections namespaces. Improve the type safety and performance of collections by using specialized collections and class-specific code.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

# Strings
Topic Objective
To introduce the topics in the section.
! ! ! ! ! ! ! ! ! !

Parse Format Format Examples Changing Case Compare Trim and Pad Split and Join StringBuilder C# Specifics Regular Expressions

Lead-in
In this section, you will learn how to work with strings in the .NET Framework.

In the C# language, string is an alias for System.String in the .NET Framework. The System.String type represents a string of Unicode characters. Working with strings is an everyday task in software development, and includes operations, such as parsing, formatting, manipulating, and comparing strings. The String object is immutable. Therefore, every time you use one of the methods in the System.String class, you create a new string object. When you want to perform repeated modifications to a string, the overhead that is associated with creating a new String object can be costly. As an alternative, you can use the System.Text.StringBuilder class to modify a string without creating a new object. In this section, you will learn how to work with strings in the .NET Framework.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

Parse
Topic Objective
To explain how the Parse method is used to convert numeric strings to a .NET Framework numeric base type.
!

Parse Method Converts a Numeric String to a Numeric

Lead-in
The Parse method converts a string that represents a .NET Framework numeric base type to an actual .NET Framework numeric base type.

string MyString = "12345"; string MyString = "12345"; int MyInt = int.Parse(MyString); int MyInt = int.Parse(MyString); MyInt++; MyInt++; Console.WriteLine(MyInt); Console.WriteLine(MyInt); // The output to the console is "12346". // The output to the console is "12346".
!

To Ignore Commas, Use the NumberStyles.AllowThousands Flag

string MyString = "123,456"; string MyString = "123,456"; int MyInt = int.Parse(MyString, int MyInt = int.Parse(MyString, System.Globalization.NumberStyles.AllowThousands); System.Globalization.NumberStyles.AllowThousands); Console.WriteLine(MyInt); Console.WriteLine(MyInt); // The output to the console is "123456". // The output to the console is "123456".

The Parse method converts a string that represents a .NET Framework numeric base type to an actual .NET Framework numeric base type. The Parse method takes a combination of up to three parameters, as follows:
!" !"

The string to be converted One or more values from the System.Globalization.NumberStyles enumeration A NumberFormatInfo class.

!"

Because the Parse method assumes that all string input represents a base-10 value, non-base-10 values are not parsable. The Parse method also does not parse strings that represent the values NaN (Not A Number), PositiveInfinity, or NegativeInfinity of the Single and Double classes because they are not real numbers. The following code example converts a string to an int value, increments that value, and displays the result:
string MyString = "12345"; int MyInt = int.Parse(MyString); MyInt++; Console.WriteLine(MyInt); // The output to the console is "12346".

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

Handling Nonnumeric Characters


The NumberStyles enumeration is useful if you have a string that contains nonnumeric characters that you want to convert into a .NET Framework numeric base type. You must use this enumeration to parse a string with a currency symbol, decimal point, exponent, parentheses, and so on. For example, a string that contains a comma cannot be converted to an int value by using the Parse method unless you pass the System.Globalization.NumberStyles enumeration.

Incorrect Way to Parse a String with Nonnumeric Characters


The following code example is invalid and raises an exception. It illustrates the incorrect way to parse a string that contains nonnumeric characters.
string MyString = "123,456"; int MyInt = int.Parse(MyString); Console.WriteLine(MyInt); // Raises System.Format exception.

Correct Way to Parse a String with Nonnumeric Characters


When you apply the System.Globalization.NumberStyles enumeration with the AllowThousands flag, the Parse method ignores the comma that raised the exception in the preceding example. The following code example uses the same string as the preceding example but does not raise an exception.
string MyString = "123,456"; int MyInt = int.Parse(MyString, System.Globalization.NumberStyles.AllowThousands); Console.WriteLine(MyInt); // The output to the console is "123456"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

Format
Topic Objective
To explain how to use format strings, or specifiers, to format the appearance of your application.
!

Format Strings Are Used in Methods That Create String Representations of a .NET Framework Data Type
$

Lead-in
The .NET Framework provides several format strings that you can use to format the appearance of strings that derive from other objects.

To display $100.00 to the console on computers on which U.S. English is the current culture

int MyInt = 100; int MyInt = 100; string MyString = MyInt.ToString("C"); string MyString = MyInt.ToString("C"); Console.WriteLine(MyString); Console.WriteLine(MyString);
$

Alternatively

int MyInt = 100; int MyInt = 100; Console.WriteLine("{0:C}", MyInt); Console.WriteLine("{0:C}", MyInt);

The .NET Framework provides several format strings, or specifiers, that you can use to format the appearance of strings that derive from other objects. There are several advantages to converting base data types to strings before displaying them to users. Strings are easily displayed and can be appended to the messages and dialog boxes of your application. You can also use format specifiers to display the same numeric value in scientific format, monetary format, hexadecimal format, and so on.

When to Use Format Strings


You can use format specifiers in situations where your application stores information in a format that is designed for use by the application, and not by the user. For example, a business application may keep track of the current date and time in a DateTime object to log when transactions are completed. The DateTime object stores information in which the user is not necessarily interested, such as the number of milliseconds that have elapsed since the creation of the object. You can also use format specifiers to display only information that is of interest to the user, such as the date and hour of the transaction. Additionally, you can dynamically modify strings that are created by using format specifiers to represent monetary, date, and time conventions for the current culture. For example, your application can display the date and time in the notation that is specific to the users current culture.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

Methods Used with Format Strings


Format strings are used with any method that creates a string representation of a .NET Framework data type, such as Int32, Int64, Single, Double, Enumeration, DateTime, and so on. Format strings are also used with Console.Writeline, String.Format, and several methods in the System.IO namespace. Additionally, every base data type contains a ToString method that returns a string representation of the data types value and accepts a string format specifier. You can control the layout and design of strings that are created by any of these methods by using one of several format strings defined by the .NET Framework.

Using the ToString Method


The ToString method is useful if you want to convert one of the standard .NET Framework data types to a string that represents that type in some other format. For example, if you have an integer value of 100 that you want to represent to the user as a currency value, you can easily use the ToString method and the currency format string ("C") to produce a string of "$100.00". The original value that is contained in the data type is not converted, but a new string is returned that represents the resulting value. This new string cannot be used for calculation until it is converted back to a .NET base data type. The original value, however, can be calculated at any time. Note Computers that do not have U.S. English specified as the current culture will display whatever currency notation is used by the current culture. In the following code example, the ToString method displays the value of 100 as a currency-formatted string in a console window:
int MyInt = 100; string MyString = MyInt.ToString("C"); Console.WriteLine(MyString);

The preceding code displays $100.00 to the console on a computer on which U.S. English is the current culture.

Using Console.Writeline
The Console.WriteLine method also accepts a format string specifier as an argument and can produce the same value as the preceding example. Console.Writeline accepts string format specifiers in the form, where the characters inside the curly brackets specify the formatting to apply to the variable. The following code example uses the Console.WriteLine method to format the value of MyInt to a currency value.
int MyInt = 100; Console.WriteLine("{0:C}", MyInt);

In the preceding example, the 0 character specifies the variable or value on which to apply formatting. In this example, it is the first and only variable. The characters that follow the colon are interpreted as string format specifiers.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

Format Examples
Topic Objective
To provide examples of format strings that return common numeric string types.
!

Currency Format C or c
$

$XX,XXX.XX or ($XX,XXX.XX) default format

Lead-in
Lets look at some examples of format strings that return the value of MyString in the currency and date time formats.

int MyInt = 12345; int MyInt = 12345; string MyString = MyInt.ToString( "c" ); string MyString = MyInt.ToString( "c" ); // In the U.S. English culture: "$12,345.00" // In the U.S. English culture: "$12,345.00"
!

Date Time Format D or d


$

M/d/yyyy or dddd, MMMM dd, yyyy default format

DateTime MyDate = new DateTime(2000, 1, 1, 0, 0, 0); DateTime MyDate = new DateTime(2000, 1, 1, 0, 0, 0); string MyString = MyDate.ToString( "d" ); string MyString = MyDate.ToString( "d" ); // In the U.S. English culture: "1/1/2000" // In the U.S. English culture: "1/1/2000"

The standard numeric, picture numeric, date and time, and enumeration format strings are described in detail in the .NET Framework Software Developers Kit (SDK). This topic provides examples of these format strings. Standard numeric format strings are used to return common numeric string types. They take the form Xn, in which X is the format character specifier, and n is the precision specifier. The following examples show the use of the format string that returns the value of MyString in the currency format:
int MyInt = 12345; string MyString = MyInt.ToString( "c" ); // In the U.S. English culture, MyString has the value: // "$12,345.00". MyString = MyInt.ToString( "c3" ); // In the U.S. English culture, MyString has the value: // "$12,345.000".

The following table describes format strings that are used with standard date and time types.
Date and format character d D Description Short date pattern Long date pattern Default return format (without precision specifier) M/d/yyyy dddd, MMMM dd, yyyy

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

The following example shows the use of the format string that returns the value of MyString in the short date pattern format:
DateTime MyDate = new DateTime(2000, 1, 1, 0, 0, 0); string MyString = MyDate.ToString( "d" ); // In the U.S. English culture, MyString has the value: // "1/1/2000".

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

Changing Case
Topic Objective
To explain how to use the String.ToUpper and String.ToLower methods to change the case of a string.
!

Methods That Compare Strings and Characters Are Case-Sensitive


$

Lead-in
You can easily change the case of a string by using the String.ToUpper and String.ToLower methods.
!

You should convert the case of strings that are entered by users before comparing them String.ToUpper converts to upper case

You Can Easily Change the Case of a String


$

string MyString = "hello world!"; string MyString = "hello world!"; // outputs: HELLO WORLD! // outputs: HELLO WORLD! Console.WriteLine(MyString.ToUpper()); Console.WriteLine(MyString.ToUpper());
$

String.ToLower converts to lower case

string MyString = "HELLO WORLD!"; string MyString = "HELLO WORLD!"; // outputs: hello world! // outputs: hello world! Console.WriteLine(MyString.ToLower()); Console.WriteLine(MyString.ToLower());

When you write an application that accepts input from a user, you can never be sure what case the user will use to enter the data. Because the methods that compare strings and characters are case-sensitive, you must convert the case of strings that are entered by users before comparing them to constant values. You can easily change the case of a string by using the two methods that are described in the following table.
Method Name String.ToUpper String.ToLower Use Converts all characters in a string to uppercase. Converts all characters in a string to lowercase.

String.ToUpper and String.ToLower provide an override that accepts a culture. The String.ToUpper method changes all of the characters in a string to uppercase. The following code example converts the string "hello world!" from lowercase to uppercase:
string MyString = "hello world!"; Console.WriteLine(MyString.ToUpper());

The preceding example displays HELLO WORLD! to the console. The String.ToLower method is similar to the String.ToUpper method, but it converts all of the characters in a string to lowercase. The following code example converts the string "HELLO WORLD!" to lowercase.
string MyString = "HELLO WORLD!"; Console.WriteLine(MyString.ToLower());

The preceding example displays hello world! to the console.


BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 7: Strings, Arrays, and Collections

Compare
Topic Objective
To introduce some of the value-comparison methods that are used to compare the values of strings.
!

The .NET Framework Has Methods to Compare Strings


$

Lead-in
The .NET Framework provides several valuecomparison methods to compare the values of strings.

For example, the Compare method compares the current string object to another string or object, returning: - Negative if first string is less than second string - 0 if the two strings are equal - Positive if first string is greater than second string

string MyString = "Hello World!"; string MyString = "Hello World!"; Console.WriteLine( Console.WriteLine( String.Compare(MyString,"Hello World!")); String.Compare(MyString,"Hello World!")); // outputs: 0 // outputs: 0

The .NET Framework provides several methods to compare the values of strings. The following table describes some of the value-comparison methods.
Method Name String.Compare String.StartsWith String.IndexOf Use Compares the values of two strings. Returns an integer value. Determines if a string begins with the string passed. Returns a Boolean value. Returns the index position of a character, starting from the beginning of a string.

For more information about value comparison methods and for a complete list of these methods, see Comparing Strings in the .NET Framework SDK documentation. For example, the String.Compare method provides a thorough way to compare the current string object to another string or object. You can use this function to compare two strings or substrings of two strings. Additionally, overloads are provided that regard or disregard case and cultural variance. The following table shows the three integer values that are returned by the Compare(string strA, string strB) method.
Value Type A negative integer 0 A positive integer Condition strA is less than strB strA equals strB strA is greater than strB

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

11

The following code example uses the Compare method to determine whether two strings are the same.
string MyString = "Hello World!"; Console.WriteLine(String.Compare(MyString, "Hello World!"));

The preceding example displays 0 to the console.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 7: Strings, Arrays, and Collections

Trim and Pad


Topic Objective
To explain how to use methods of the System.String class to trim and pad strings.
!

Trim Methods Remove Spaces

Lead-in
You can remove or extend the spaces around strings by using methods of the System.String class.

string MyString = " Big "; string MyString = " Big "; Console.WriteLine("Hello{0}World!", MyString ); Console.WriteLine("Hello{0}World!", MyString ); string TrimString = MyString.Trim(); string TrimString = MyString.Trim(); Console.WriteLine("Hello{0}World!", TrimString ); Console.WriteLine("Hello{0}World!", TrimString ); // outputs the following lines to the console: // outputs the following lines to the console: //Hello Big World! //Hello Big World! //HelloBigWorld! //HelloBigWorld!
!

Pad Methods Expand a Specific Number of Characters

string MyString = "Hello World!"; string MyString = "Hello World!"; Console.WriteLine(MyString.PadLeft(20, '-')); Console.WriteLine(MyString.PadLeft(20, '-')); // outputs the following line to the console: // outputs the following line to the console: //--------Hello World! to the console. //--------Hello World! to the console.

When you want to remove or extend the spaces around strings, the System.String class provides methods for trimming and padding strings.

Trimming
When you are parsing a sentence into individual words, you might have white spaces on either end of a word. You can use one of the trim methods in the System.String class to remove any number of spaces from the beginning or end of the string. The following table describes two of the available trim methods.
Method Name String.Trim String.Remove Use Removes white spaces from the beginning and end of a string. Removes a specified number of characters from a specified index position in a string.

For example, you can easily remove white spaces from both ends of a string by using the String.Trim method, as shown in the following code example.
string MyString = " Big "; Console.WriteLine("Hello{0}World!", MyString ); string TrimString = MyString.Trim(); Console.WriteLine("Hello{0}World!", TrimString );

This code outputs the following lines to the console:


Hello Big World! HelloBigWorld!

For a complete list of trim methods in the System.String class, see Trimming and Removing Characters in the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

13

Padding
System.String also provides methods that you can use to create a new version of an existing string that is expanded by a specific number of characters. The following table describes the available pad methods.
Method Name String.PadLeft String.PadRight Use Right aligns and pads a string, so its rightmost character is a specified distance from the beginning of the string. Left aligns and pads a string, so its rightmost character is a specified distance from the beginning of the string.

For example, the String.PadLeft method creates a new string that moves an existing string to the right, so its last character is a specified number of spaces from the first index of the string. White spaces are inserted if you do not use an override that allows you to specify your own custom padding character. The following code example uses the PadLeft method to create a new string with a total length of 20 spaces.
string MyString = "Hello World!"; Console.WriteLine(MyString.PadLeft(20, '-'));

This example displays the following text to the console.


--------Hello World! to the console.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 7: Strings, Arrays, and Collections

Split and Join


Topic Objective
To explain how to use the Split and Join methods to break up and concatenate strings.
!

Split Method Is Used to Break Up a String Into an Array of Substrings


$

Lead-in
The System.String class provides the Split method to break up strings and the Join method to concatenate strings.

String is broken at positions indicated by the specified separator characters parameter If the separator parameter is null, the whitespace characters are assumed to be the separator

string Line = "Hello World"; string Line = "Hello World"; string[] Words = Line.Split(null); string[] Words = Line.Split(null); // Words[0] = "Hello" and Words[1] = "World" // Words[0] = "Hello" and Words[1] = "World"
!

Join Method Is Used to Concatenate Strings


$

A specified separator string is placed between each element of a string array

The System.String class provides the Split method to break up strings and the Join method to concatenate strings.

The Split Method


For Your Information
You should cover the String.Split method because it is used in the lab.

You use the Split method to break up a string instance into an array of substrings at the positions that are specified by separator characters. If separator characters are omitted, that is to say, if the parameter is null, the whitespace characters are assumed to be the separator. If the separator is a zero-length string, a single-element array that contains the entire expression string is returned. The following example shows how to break up a string into a string array of words:
string Line = "Hello World"; string[] Words = Line.Split(null); // Words[0] = "Hello" and Words[1] = "World"

The Join Method


You use the Join method to concatenate a specified separator string between each element of a specified String array, which yields a single concatenated string. If the separator is omitted, that is to say null, the space character (" ") is used. If the separator is a zero-length string (""), all of the items in the list are concatenated with no delimiters.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

15

StringBuilder
Topic Objective
To explain how to use the StringBuilder method to modify a string without creating a new object.
! !

The String Object is Immutable System.Text.StringBuilder Allows You to Modify a String Without Creating a New Object You Can Specify the Maximum Number of Characters

Lead-in
When you want to perform repeated modifications to a string, use the System.Text.StringBuilder class to modify a string without creating a new object.

StringBuilder MyStringBuilder = new StringBuilder("Hello"); StringBuilder MyStringBuilder = new StringBuilder("Hello");


!

// MyStringBuilder can hold a maximum of 25 characters // MyStringBuilder can hold a maximum of 25 characters StringBuilder MyStringBuilder = StringBuilder MyStringBuilder = new StringBuilder("Hello World!", 25); new StringBuilder("Hello World!", 25);
!

Methods Include:
$

Append, AppendFormat, Insert, Remove, and Replace

The String object is immutable. Therefore, every time you use one of the methods in the System.String class, you create a new string object. When you want to perform repeated modifications to a string, the overhead that is associated with creating a new String object can be costly. As an alternative, you can use the System.Text.StringBuilder class to modify a string without creating a new object.

Creating a StringBuilder Object


You can create a new instance of the StringBuilder object by initializing your variable with one of the overloaded constructor methods, as shown in the following code example:
StringBuilder MyStringBuilder = new StringBuilder("Hello");

Although the StringBuilder object is a dynamic object that allows you to expand the number of characters in the string that it encapsulates, you can specify a value for the maximum number of characters that it can hold. This value is called the capacity of the object and must not be confused with the length of the string that the current StringBuilder object holds. Any attempt to expand the StringBuilder class beyond the maximum range causes an ArgumentOutOfRangeException to be thrown. The following code example specifies that the MyStringBuilder object can be expanded to a maximum of 25 spaces.
StringBuilder MyStringBuilder = new StringBuilder("Hello World!", 25);

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 7: Strings, Arrays, and Collections

StringBuilder Methods
The following table describes the methods that you can use to modify the contents of the StringBuilder object.
Method Name StringBuilder.Append StringBuilder.AppendFormat StringBuilder.Insert StringBuilder.Remove StringBuilder.Replace Use Appends information to the end of the current StringBuilder object. Replaces zero or more format specifications with the appropriately formatted value of an object. Inserts a string or object into the specified index of the current StringBuilder object. Removes a specified number of indexes from the current StringBuilder object. Replaces a specified index or character with the passed character.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

17

C# Specifics
Topic Objective
To explain what the string type is in the .NET Framework and to describe the functions of the +, [], and != operators, and @quoting.
!

C# string Type Is a String of Unicode Characters


$ $

Alias for System.String Equality operators (== and !=) compare the values of string objects, not references The + operator concatenates strings

Lead-in
The string type represents a string of Unicode characters; string is an alias for System.String in the .NET Framework.

string a = "\u0068ello "; string a = "\u0068ello "; string b = "world"; string b = "world"; Console.WriteLine( a + b == "hello world" );//True Console.WriteLine( a + b == "hello world" );//True $ The [] operator accesses individual characters of a string char x = "test"[2]; // x = 's'; char x = "test"[2]; // x = 's';
$

With @-quoting, escape sequences are not processed

@"c:\Docs\Source\a.txt" @"c:\Docs\Source\a.txt" // rather than "c:\\Docs\\Source\\a.txt" // rather than "c:\\Docs\\Source\\a.txt"

The string type represents a string of Unicode characters; string is an alias for System.String in the .NET Framework. Although string is a reference type, the equality (==) operator and the inequality (!=) operator are defined to compare the values of string objects, not the references. Comparing the values of string objects makes testing for string equality more intuitive, as in the following example:
string a = "hello"; string b = "hello"; Console.WriteLine( a == b );

// output: True -- same value

The + operator concatenates strings, as in the following example:


string a = "good " + "morning";

The [] operator accesses individual characters of a string, as in the following example:


char x = "test"[2]; // x = 's';

String literals are of type string and can be written in two forms: quoted and @quoted. Quoted string literals are enclosed in double quotation marks ("), as in the following example:
"good morning" // a string literal

Quoted string literals can also contain any character literal, including escape sequences, as in the following example:
string a = "\\\u0066\n"; // backslash, letter f, new line

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 7: Strings, Arrays, and Collections

@-quoted string literals start with @ and are enclosed in double quotation marks, as in the following example:
@"good morning" // a string literal

The advantage of using @-quoted string literals is that escape sequences are not processed. This makes it easy to write a fully qualified file name, as in the following example:
@"c:\Docs\Source\a.txt" // rather than "c:\\Docs\\Source\\a.txt"

To include a quoted phrase in an @-quoted string, use two pairs of double quotation marks, as in the following example:
@"""Ahoy!"" cried the captain." // "Ahoy!" cried the captain.

The following code example uses the C# features that are discussed in this topic:
using System; class test { public static void Main( String[] args ) { string a = "\u0068ello "; string b = "world"; Console.WriteLine( a + b ); Console.WriteLine( a + b == "hello world" ); } }

The preceding code example displays the following output to the console:
hello world True

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

19

Regular Expressions
Topic Objective
To briefly describe how regular expressions can be used in the .NET Framework.
! !

Regular Expressions Powerful Text Processing Pattern-Matching Notation Allows You to:
$ $ $

Lead-in
Regular expressions allow you to quickly parse large amounts of text in order to find specific character patterns; to extract, edit, replace, or delete text substrings; and to add the extracted strings to a collection to generate a report.

Find specific character patterns Extract, edit, replace, or delete text substrings Add the extracted strings to a collection to generate a report

Designed to be Compatible With Perl 5

This topic provides a brief summary of regular expressions. Do not spend much time on this slide, but encourage students to refer to the .NET Framework SDK, especially for details about using the regular expression classes.

Regular expressions provide a powerful, flexible, and efficient method to process text. The extensive pattern-matching notation of regular expressions allows you to quickly parse large amounts of text to find specific character patterns; to extract, edit, replace, or delete text substrings; and to add the extracted strings to a collection in order to generate a report. For many applications that deal with strings, such as HTML processing, log file parsing, and HTTP header parsing, regular expressions are an essential tool. The .NET Framework regular expressions incorporate the most popular features of other regular expression implementations, such as those used in Perl and awk. Designed to be compatible with Perl 5 regular expressions, .NET Framework regular expressions include features that are not yet available in other implementations, such as right-to-left matching and dynamic compilation. The .NET Framework regular expression classes are part of the .NET Framework class library and can be used with any language or tool that targets the common language runtime, including ASP.NET and Microsoft Visual Studio .NET. A detailed explanation of how to use the regular expression classes is beyond the scope of this course. For more information about using regular expression classes, see the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 7: Strings, Arrays, and Collections

Terminology Collections
Topic Objective
To define the term collection as it is used in this module and to identify where collections are found in the .NET Framework.
!

In This Module, the Term Collection Is Used in Its Broader Sense to Refer to a Group of Items In the .NET Framework, Collections Are Found in the Namespaces
$ $

Lead-in
In this module, the term collection is used in its broader sense: to describe a group of items.

System.Array System.Collections

Do not spend much time on this slide. The objective of this slide is to define the term collection clearly, before discussing the collections that are found in the .NET Framework.

In this module, the term collection is used in its broader sense to refer to a group of items. In the .NET Framework, examples of collections are found in the namespaces System.Array, and System.Collections.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

21

# .NET Framework Arrays


Topic Objective
To introduce the topics in the section.
! ! ! ! !

Lead-in
The System.Array class is the base class of all array types and contains methods for creating, manipulating, searching, and sorting arrays.

System.Array C# Specifics Iterating Over Comparing Sorting

The System.Array class is the base class of all array types and contains methods for creating, manipulating, searching, and sorting arrays. The Array class is not part of the Collections namespace. However, it is still a collection because it is based on the IList interface. In an array style of collection, an item in the collection is referred to by the term element. Specific elements are identified by their array index. The low bound or lower bound of an Array is the index of its first element. To understand the functionality of the various collection classes, you must understand their key interfaces. In this section, you will learn about the interfaces that are used by the methods of System.Array.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 7: Strings, Arrays, and Collections

System.Array
Topic Objective
To explain how array types are used and defined.
! !

System.Array Is the Base Class of All Array Types Arrays Implement the Following Interfaces
$

Lead-in
The System.Array class is the base class of all array types and contains methods for creating, manipulating, searching, and sorting arrays.

ICloneable, IList, ICollection, and IEnumerable Creating, manipulating, searching, and sorting

System.Array Has Methods For


$

Null, Empty String, and Empty (0 item) Arrays Should Be Treated the Same
$

Therefore, return an Empty array, instead of a null reference

The System.Array class is the base class of all array types and contains methods for creating, manipulating, searching, and sorting arrays. Arrays are always allocated on the garbage-collected heap. Arrays can be single dimensional or multidimensional. You can also create arrays of arrays, called jagged arrays. For optimum performance, it is highly recommended that each rank of an array be zero-based. Additionally, each rank of an array must be zero-based when passing arrays between programming languages.

Defining an Array Type


You define an array type by specifying the element type of the array, the rank, or number of dimensions, of the array, and the upper and lower bounds of each dimension of the array. All of these details are included in any signature of an array type. The runtime automatically creates exact array types as they are required. No separate definition of the array type is needed. Arrays of a given type can only hold elements of that type. If you need to manipulate a set of unlike objects or value types, consider using one of the collection types that are defined in the System.Collections namespace.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

23

Methods and Properties of System.Array


Some of the methods and properties for the System.Array class are described in this topic. Many of these methods are used to implement the classs interfaces. System.Array implements the interfaces that are described in the following table.
Interface ICloneable IList ICollection IEnumerable Use Supports cloning, which creates a new instance of a class with the same value as an existing instance. Represents a collection of objects that can be individually indexed. Defines size, enumerators, and synchronization methods for all collections. Exposes the enumerator, which supports a simple iteration over a collection.

The interfaces that are listed in the preceding table are supported not only by arrays but also by many of the System.Collections classes. Subsequent topics in this module discuss specific interfaces and the classes that implement them. The following tables describe some of the public members that are available through the System.Array class.
Static Method BinarySearch CreateInstance Sort Use Overloaded. Searches a one-dimensional sorted Array for a value, using a binary search algorithm. Overloaded. Initializes a new instance of the Array class. Overloaded. Sorts the elements in one-dimensional Array objects. Use Gets a value that indicates whether the Array has a fixed size. Gets a value that indicates whether the Array is read-only. Gets the total number of elements in all of the dimensions of the Array. Gets the rank (number of dimensions) of the Array.

Property IsFixedSize IsReadOnly Length Rank

Note The IsFixedSize and IsReadOnly properties are always false unless they are overridden by a derived class.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 7: Strings, Arrays, and Collections

The following table describes some of the public instance methods that are available through the System.Array class.
Instance Method Clone GetEnumerator GetLength GetLowerBound GetUpperBound GetValue SetValue Use Creates a shallow copy of the Array. Returns an IEnumerator for the Array. Gets the number of elements in the specified dimension of the Array. Gets the lower bound of the specified dimension in the Array. Gets the upper bound of the specified dimension in the Array. Overloaded. Gets the values of the Array elements at the specified indexes. Overloaded. Sets the specified Array elements to the specified value.

For complete lists of public members of the System.Array class, see Array Members in the .NET Framework SDK documentation.

Empty Arrays
Nulls should only be returned by reference properties that refer to another object or component. String and Array properties should never return null, because a programmer typically does not expect null in this context. For example, a programmer typically would assume that the following code works:
public void DoSomething() { string[] sa = SomeOtherFunc(); // The following line assumes sa.Length is never null if (sa.Length > 0) { // do something else } }

Generally, null, empty string, and empty (0 item) arrays should be treated in the same way. Therefore, return an Empty array, instead of a null reference.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

25

C# Specifics
Topic Objective
To explain features that are unique to C# arrays.
! !

C# Array Indexes Start at Zero Declaring an Array Size Is Not Part of Its Type Creating an Array

Lead-in
C# arrays are similar to arrays in most other popular languages, but you should be aware of the differences that are presented in this topic.

int[] numbers; // declare numbers as int[] numbers; // declare numbers as // an int array of any size // an int array of any size
!

int[] numbers = new int[5]; // declare and create int[] numbers = new int[5]; // declare and create
!

Initializing an Array Using System.Array Members

int[] numbers = new int[5] {1, 2, 3, 4, 5}; int[] numbers = new int[5] {1, 2, 3, 4, 5};
!

int[] numbers = {1, 2, 3, 4, 5}; int[] numbers = {1, 2, 3, 4, 5}; int LengthOfNumbers = numbers.Length; int LengthOfNumbers = numbers.Length;

C# arrays are zero-indexed. That means the array indexes start at zero. Arrays in C# and arrays in most other popular languages work similarly, but there are a few differences that you should be aware of. When declaring an array, the square brackets ([]) must come after the type, and not after the identifier. Placing the brackets after the identifier is not legal syntax in C#, as shown in the following example:
int[] table; // not int table[];

In addition, and unlike the C language, the size of the array is not part of its type. This allows you to declare and assign to an array any array of int objects, regardless of the arrays length, as in the following examples.
int[] numbers; // declare numbers as an int array of any size numbers = new int[10]; numbers = new int[20]; // numbers is a 10-element array // now it's a 20-element array

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 7: Strings, Arrays, and Collections

Declaring an Array
C# supports single-dimensional arrays and multidimensional arrays, which are also know as rectangular arrays, and jagged arrays. The following code examples show how to declare each of these arrays:
int[] numbers; // single-dimensional array string[,] names; // multidimensional array byte[][] scores; //Array-of-arrays

Instantiating an Array
Declaring arrays, as shown in the preceding examples, does not actually create the arrays. As discussed later in this topic, arrays in C# are objects and must be instantiated. The following code examples show the syntax to create an array for each of the arrays already discussed:
int[] numbers = new int[5]; // Single-dimensional array string[,] names = new string[5,4]; // Multi-dimensional array byte[][] scores = new byte[5][]; // Array-of-arrays for (int x = 0; x < scores.Length; x++) { scores[x] = new byte[4]; }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

27

The following example shows a complete C# program that declares and instantiates arrays as discussed in this topic.
using System; class DeclareArraysSample { public static void Main() { // Single-dimensional array int[] numbers = new int[5]; // Multidimensional array string[,] names = new string[5,4]; // Array-of-arrays (jagged array) byte[][] scores = new byte[5][]; // Create the jagged array for (int i = 0; i < scores.Length; i++) { scores[i] = new byte[i+3]; } // Print length of each row for (int i = 0; i < scores.Length; i++) { Console.WriteLine("Length of row {0} is {1}", i, scores[i].Length); } } }

The preceding program displays the following output:


Length Length Length Length Length of of of of of row row row row row 0 1 2 3 4 is is is is is 3 4 5 6 7

Initializing Arrays
C# provides simple and straightforward ways to initialize arrays when they are declared, by enclosing the initial values in curly braces ( {} ). Important If an array is not initialized when it is declared, array members are automatically initialized to the default initial value for the array type.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

28

Module 7: Strings, Arrays, and Collections

Single-Dimensional Array
The following examples show different ways to initialize single-dimensional arrays:
int[] numbers = new int[5] {1, 2, 3, 4, 5}; string[] names = new string[3] {"Matt", "Joanne", "Robert"};

You can omit the size of the array, as in the following examples:
int[] numbers = new int[] {1, 2, 3, 4, 5}; string[] names = new string[] {"Matt", "Joanne", "Robert"};

If an initializer is provided, you can also omit the new statement, as in the following examples:
int[] numbers = {1, 2, 3, 4, 5}; string[] names = {"Matt", "Joanne", "Robert"};

Multidimensional Array
The following examples show different ways to initialize multidimensional arrays:
int[,] numbers = new int[3, 2] { {1, 2}, {3, 4}, {5, 6} }; string[,] siblings = new string[2, 2] { {"Mike","Amy"}, {"Mary","Albert"} };

You can omit the size of the array, as in the following examples:
int[,] numbers = new int[,] { {1, 2}, {3, 4}, {5, 6} }; string[,] siblings = new string[,] { {"Mike","Amy"}, {"Mary","Ray"} };

If an initializer is provided, you can also omit the new statement, as in the following examples:
int[,] numbers = { {1, 2}, {3, 4}, {5, 6} }; string[,] siblings = { {"Mike", "Amy"}, {"Mary", "Albert"} };

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

29

Jagged Array (Array-of-Arrays)


The following examples show different ways to initialize jagged arrays. You can initialize jagged arrays by using the following style:
int[][] numbers = new int[2][] { new int[] {2,3,4}, new int[] {5,6,7,8,9} };

You can omit the size of the first array, as in the following example:
int[][] numbers = new int[][] { new int[] {2,3,4}, new int[] {5,6,7,8,9} };

Accessing Array Members


Accessing array members in C# is straightforward and similar to how you access array members in C and C++. For example, the following code creates an array called numbers and then assigns 5 to the fifth element of the array:
int[] numbers = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}; numbers[4] = 5;

The following code example declares a multidimensional array and assigns 5 to the member located at [1, 1]:
int[,] numbers = { {1, 2}, {3, 4}, {5, 6}, {7, 8}, {9, 10} }; numbers[1, 1] = 5;

The following code example shows how to access a member of a jagged array:
int[][] numbers { new int[] {1, new int[] {3, }; numbers[1][1] = = new int[][] 2}, 4} 5;

Arrays Are Objects


Arrays in C# are actually objects. System.Array is the abstract base type of all array types. Therefore, you can use the properties and other class members of System.Array. For example, you can use the Length property to get the length of an array. The following code example assigns the length of the numbers array, which is 5, to a variable called LengthOfNumbers:
int[] numbers = {1, 2, 3, 4, 5}; int LengthOfNumbers = numbers.Length;

The System.Array class provides many other useful methods and properties, such as methods for sorting, searching, and copying arrays.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

30

Module 7: Strings, Arrays, and Collections

Iterating Over
Topic Objective
To explain the role of the IEnumerable and IEnumerator interfaces in collections.
!

System.Array and System.Collections Classes Implement IEnumerable Interface and its GetEnumerator Method Enumerator Classes Implement IEnumerator
$

Lead-in
A .NET Framework interface provides a way to group a set of related members that can be used to perform a particular action.

Members: MoveNext, Reset, and Current

int[] numbers = new int[5] {1, 2, 3, 4, 5}; int[] numbers = new int[5] {1, 2, 3, 4, 5}; IEnumerator e = numbers.GetEnumerator(); IEnumerator e = numbers.GetEnumerator(); while (e.MoveNext()) { while (e.MoveNext()) { Console.WriteLine("Number: {0}", (int)e.Current); Console.WriteLine("Number: {0}", (int)e.Current); } } // alternatively // alternatively foreach (int i in numbers) foreach (int i in numbers) { { Console.WriteLine("Number: {0}", i); Console.WriteLine("Number: {0}", i); } }

Emphasize the difference between enumeration and an enumerator.

To understand the functionality of the various collection classes, you must understand the key interfaces of the collection classes. A .NET Framework interface provides a way to group a set of related members that can be used to perform a particular action. For example, a client of an object of any class that implements the IEnumerable interface can obtain an enumerator object for that class. The System.Array class and all of the System.Collections classes support the IEnumerable interface. Note It is easy to confuse the term enumerator with enumeration. However, enumerator and enumeration are very different concepts. Enumeration, an enum type in C#, is a distinct type with named constants, as in the following example:
enum Color {Red,Green,Blue}

Support for IEnumerable and the GetEnumerator Method


These classes inherit from IEnumerable and implement its single method GetEnumerator. The GetEnumerator method returns an enumerator that implements the IEnumerator interface. Enumerators are intended to be used only to read data in the collection. You cannot use enumerators to modify the underlying collection. The enumerator is required to be safe. In other words, enumerators must have a fixed view of the items in a collection that remain the same, even if the collection is modified. For example, if you call GetEnumerator on a collection at the point in time when the collection contains the elements 1, 2, and 3, the enumerator object that is returned by this method must always produce 1, 2, and 3 when it is iterated over, even if the collection is later changed.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

31

Using Enumerators with Collections


When working with collections, you typically implement an enumerator in one of the following ways:
!"

The enumerator makes a copy of all of the items in the collection. Making a copy of a large collection guarantees safety but imposes a severe penalty in performance and memory utilization for large collections and therefore is usually not done.

!"

The enumerator has a reference to the collection. If the enumerator implementation uses a reference to the collection, the copy penalty is avoided. However, safety must be guaranteed by another means. If the collection is static or unchanging, you need take no additional action to ensure safety. The .NET Framework collections are typically not static. Instead, they implement a versioning mechanism. Every time a .NET Framework collection changes, the collections version number is incremented. An enumerator that detects that the collections version number has changed after the enumerator was created throws an InvalidOperationException that should be caught and handled by the enumerators client.

The IEnumerator interface has the following public instance property: Current The Current property gets the current element in the collection. An enumerator maintains a reference to the item in the collection that is currently being enumerated. The enumerator is in an invalid state if it is positioned before the first element in the collection or after the last element in the collection. When the enumerator is in an invalid state, calling Current throws an exception. The IEnumerator interface also requires the following public instance methods.
Method MoveNext Reset Use Advances the enumerator to the next element of the collection. Sets the enumerator to its initial position, which is before the first element in the collection.

Initially, the enumerator is positioned before the first element in the collection. Reset also brings the enumerator back to this position. Therefore, after an enumerator is created or after a Reset, you must call MoveNext to advance the enumerator to the first element of the collection before reading the value of Current. Current returns the same object until MoveNext or Reset is called. Once the end of the collection is passed, the enumerator returns to an invalid state. At this time, calling MoveNext returns false. Calling Current throws an exception if the last call to MoveNext returned false.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

32

Module 7: Strings, Arrays, and Collections

The following code example shows how to iterate over a collection. In this example, the collection is an instance of System.Array.
int[] numbers = new int[5] {1, 2, 3, 4, 5}; IEnumerator e = numbers.GetEnumerator(); while (e.MoveNext()) { Console.WriteLine("Number: {0}", (int)e.Current); }

This code outputs:


Number: Number: Number: Number: Number: 1 2 3 4 5

Using foreach to Iterate Through an Array


C# provides the foreach statement, which is a less verbose way to iterate through the elements of an array. For example, the following code example creates an array called numbers and iterates through it with the foreach statement:
int[] numbers = {4, 5, 6, 1, 2, 3, -2, -1, 0}; foreach (int i in numbers) { System.Console.WriteLine("Number: {0}", i); }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

33

Comparing
Topic Objective
To explain how the IComparer and IComparable interfaces are used to sort and order a collections items.
!

To Sort and Search, Collections Must Be Able to Compare Items

! IComparers Compare Method Compares Two Objects of Any Type int Compare( object x, object y ); int Compare( object x, object y );
$

Lead-in
To sort a collection, you must be able to compare and order the items of the collection.

Comparer class is the default implementation of IComparer Its Compare method uses IComparable.CompareTo

IComparables CompareTo Method Compares the Current Instance to an Object of the Same Type

int CompareTo( object anObject ); int CompareTo( object anObject ); ! CompareTo Returns

Value Less than zero Zero Greater than zero

Meaning Instance is less than object Instance is equal to object Instance is greater than object

To sort a collection, you must be able to compare and order the items of the collection. The IComparer and IComparable interfaces are used to sort and order a collections items. The IComparer interfaces Compare method compares two objects of any type and returns a value that indicates whether one object is less than, equal to, or greater than the other. The Compare method provides the sort order of a collection and is also used in conjunction with the Array.BinarySearch method.

Default Implementation of IComparer


The Comparer class provides the default implementation of the IComparer interface. The Comparer classs Compare(object a, object b) method is implemented as follows:
!" !"

If a implements IComparable, then a.CompareTo(b) is returned. Otherwise, if b implements IComparable, then b.CompareTo(a) is returned.

The IComparable interface has a single CompareTo method that compares the current instance with another object of the same type.

Return Values of CompareTo


The value returned by the CompareTo method is a 32-bit signed integer that indicates the relative order of the instance and the object that is passed as a parameter, as in the following example:
int CompareTo(object anObject);

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

34

Module 7: Strings, Arrays, and Collections

The following table describes the possible meanings of the return value.
Value Less than zero Zero Greater than zero Meaning This instance is less than anObject. This instance is equal to anObject. This instance is greater than anObject.

By definition, any object compares greater than a null reference, and two null references compare equal to each other.

Issues with Using IComparable.CompareTo


The parameter, anObject, must be the same type as the class or value type that implements this interface. Otherwise, ArgumentException is thrown. The default comparison procedures use the Thread.CurrentCulture of the current thread unless it is otherwise specified. String comparisons may have different results depending on the culture. To perform case-insensitive comparisons on strings, you can use the CaseInsensitiveComparer classs implementation of the IComparer interface.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

35

Sorting
Topic Objective
To explain how to compare and order the items of a collection by using the IComparer and IComparable interfaces. Knowledge of this topic is required for the lab.
!

Sort Method Using Elements IComparable.CompareTo


Array.Sort( anArray ); Array.Sort( anArray );

IComparable.CompareTo Design Pattern

Lead-in
Some collections, such as Array, sort their items when their Sort method is called.

public int CompareTo(Object anObject) { public int CompareTo(Object anObject) { if ( anObject == null) return 1; if ( anObject == null) return 1; if ( !(anObject is <classname>) ) { if ( !(anObject is <classname>) ) { throw new ArgumentException(); } throw new ArgumentException(); } // Do comparison and return a // Do comparison and return a // negative integer if instance < anObject // negative integer if instance < anObject // 0 if instance == anObject // 0 if instance == anObject // positive integer if instance > anObject // positive integer if instance > anObject } }

Some collections, such as Array, sort their items when their Sort method is called. Overloaded versions of the Sort method allow you to supply an IComparer implementation in the method call that is used to perform the ordering of the elements. These overloaded versions of the Sort method provide you with the flexibility to resort the same collection of items by using different IComparer implementations. If you use the arrays public static void Sort(Array) method, the default Comparer class implementation of IComparer is used, and the arrays elements are sorted by using the elements implementation of the CompareTo method of the IComparable interface. Other collection classes, such as SortedList, have constructors whose parameters determine the sort order. These classes are less flexible than classes that implement a sort method because once they are constructed their sort, ordering cannot be changed.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

36

Module 7: Strings, Arrays, and Collections

Demonstration: Sorting and Enumerating an Array


Topic Objective
To demonstrate how to sort and enumerate an array.

Lead-in
In this demonstration, we will sort an array by using the CompareTo method when the value type or class of the items in the collection implements the IComparable interface.

As stated in Sorting in this module, you can sort an array by using the CompareTo method when the value type or class of the items in the collection implements the IComparable interface. For Your Information
You should carefully cover the CompareTo method because it is used in the lab.

In this demonstration, an Employee class contains an employees name, level number, and hiring date. To sort an array of Employees based on increasing level numbers where equal level numbers are then ordered by increasing hiring date, implement the following:
using System; namespace ArraySorting { public class Employee : IComparable { public string name; public int level; public DateTime hiringDate; public Employee( string name,int level,DateTime hiringDate) { this.name = name; this.level=level; this.hiringDate=hiringDate; } public int CompareTo(Object anObject) { if (anObject == null) return 1; if ( !(anObject is Employee) ) { throw new ArgumentException(); }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections


Employee anEmployee = (Employee)anObject; if ( level < anEmployee.level ) return -1; else { if ( level == anEmployee.level ) { if (hiringDate < anEmployee.hiringDate) return -1; else { if ( hiringDate == anEmployee.hiringDate) return 0; else return 1; } } else return 1; } } } public class ArraySort { {

37

public static void Main()

// Create and initialize a new Array instance. Employee[] myEmployees = new Employee[10]; myEmployees[0] = new Employee( "a",2,new DateTime(1990,1,1)); myEmployees[1] = new Employee( "b",2,new DateTime(2000,1,1)); myEmployees[2] = new Employee( "c",2,new DateTime(1990,1,1)); myEmployees[3] = new Employee( "d",4,new DateTime(2000,1,1)); myEmployees[4] = new Employee( "e",4,new DateTime(1990,1,1)); myEmployees[5] = new Employee( "f",4,new DateTime(2000,1,1)); myEmployees[6] = new Employee( "g",1,new DateTime(1990,2,5)); myEmployees[7] = new Employee( "h",1,new DateTime(2000,1,1)); myEmployees[8] = new Employee( "i",1,new DateTime(1990,1,1)); myEmployees[9] = new Employee( "j",0,new DateTime(2001,1,1)); // Display the values of the Array. Console.WriteLine( "The Array instance initially contains values:" ); PrintIndexAndValues( myEmployees ); // Sort the values of the Array. Array.Sort( myEmployees ); // Code continued next page
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

38

Module 7: Strings, Arrays, and Collections


// Display the values of the Array. Console.WriteLine( "After sorting:" ); PrintIndexAndValues( myEmployees ); } public static void PrintIndexAndValues( Array myEmployees ) { foreach ( Employee e in myEmployees ) { Console.WriteLine( "name: {0} \tlevel: {1} \tdate:{2:d}", e.name, e.level, e.hiringDate); } } } }

The preceding code displays the following output to the console:


The Array instance initially contains values: name: a level: 2 date:1/1/1990 name: b level: 2 date:1/1/2000 name: c level: 2 date:1/1/1990 name: d level: 4 date:1/1/2000 name: e level: 4 date:1/1/1990 name: f level: 4 date:1/1/2000 name: g level: 1 date:2/5/1990 name: h level: 1 date:1/1/2000 name: i level: 1 date:1/1/1990 name: j level: 0 date:1/1/2001 After sorting: name: j level: 0 date:1/1/2001 name: i level: 1 date:1/1/1990 name: g level: 1 date:2/5/1990 name: h level: 1 date:1/1/2000 name: c level: 2 date:1/1/1990 name: a level: 2 date:1/1/1990 name: b level: 2 date:1/1/2000 name: e level: 4 date:1/1/1990 name: d level: 4 date:1/1/2000 name: f level: 4 date:1/1/2000

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

39

# .NET Framework Collections


Topic Objective
To introduce the topics in the section.
! ! ! ! ! !

Lead-in
The System.Collections namespace contains interfaces and classes that define various collections of objects, such as lists, queues, arrays, hashtables, and dictionaries.

Examples of System.Collections Classes Lists Dictionaries SortedList Collection Usage Guidelines Type Safety and Performance

The System.Collections namespace contains interfaces and classes that define various collections of objects, such as lists, queues, arrays, hashtables, and dictionaries.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

40

Module 7: Strings, Arrays, and Collections

Examples of System.Collections Classes


Topic Objective
To show some of the collection classes in the System.Collections namespace.
!

ArrayList
$

Implements IList by using a dynamically-sized array Provides abstract base class for strongly-typed collection of associated keys and values Represents a collection of keys and values that are organized around the keys hash code Represents the collection of keys and values, sorted by keys and accessible by key and index

DictionaryBase
$

Lead-in
Lets look briefly at some of the collection classes in the System.Collections namespace.
!

Hashtable
$

SortedList
$

BitArray, Queue, Stack, CollectionBase, ReadOnlyCollectionBase

Do not spend a lot of time on this slide. Just introduce students to some commonly used collection classes and encourage them to refer to the .NET Framework SDK for more information.

The following table shows some of the collection classes in the System.Collections namespace.
Class ArrayList BitArray Description Implements the IList interface by using an array whose size is dynamically increased as required. Manages a compact array of bit values, which are represented as Booleans, where true indicates that the bit is on (1) and false indicates the bit is off (0). Provides the abstract base class (MustInherit in Microsoft Visual Basic) for a strongly-typed collection. Provides the abstract base class (MustInherit in Visual Basic) for a strongly-typed collection of associated keys and values. Represents a collection of associated keys and values that are organized around the hash code of the key. Represents a first-in, first-out collection of objects. Provides the abstract base class (MustInherit in Visual Basic) for a strongly-typed read-only collection. Represents a collection of associated keys and values that are sorted by the keys and are accessible by key and by index. Represents a simple last-in-first-out collection of type Object.

CollectionBase DictionaryBase

Hashtable Queue ReadOnlyCollectionBase SortedList

Stack

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

41

Lists
Topic Objective
To describe the public instance members that the IList interface implements.
!

Lead-in
IList is an interface for classes that represent an ordered collection of objects that can be individually indexed. Array, ArrayList, StringCollection, and TreeNodeCollection are some of the classes that implement IList.
!

IList Interface for Classes That Represent an Ordered Collection of Objects That Can Be Individually Indexed Some Classes That Implement IList
$

Array, ArrayList, StringCollection, and TreeNodeCollection Add, Clear, Contains, Insert, IndexOf, Remove, and RemoveAt

Methods Include:
$

IList is an interface for classes that represent an ordered collection of objects that can be individually indexed. Array, ArrayList, StringCollection, and TreeNodeCollection are some of the classes that implement IList. The following tables describe the public instance properties that the IList interface implements.
Property IsFixedSize IsReadOnly Item Use When implemented by a class, gets a value indicating whether the IList has a fixed size. When implemented by a class, gets a value indicating whether the IList is read-only. When implemented by a class, gets or sets the element at the specified index. In C#, this property is the indexer for the IList class.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

42

Module 7: Strings, Arrays, and Collections

The following table describes the public instance methods that the IList interface defines.
Method Add Clear Contains IndexOf Insert Remove RemoveAt Use When implemented by a class, adds an item to the IList. When implemented by a class, removes all items from the IList. When implemented by a class, determines whether the IList contains a specific value. When implemented by a class, determines the index of a specific item in the IList. When implemented by a class, inserts an item to the IList at the specified position. When implemented by a class, removes the first occurrence of a specific object from the IList. When implemented by a class, removes the IList item at the specified index.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

43

Demonstration: ArrayList
Topic Objective
To demonstrate how ArrayList implements the IList interface by using an array whose size is dynamically increased as required.

Lead-in
In this demonstration, ArrayList implements the IList interface by using an array whose size is dynamically increased as required.

In this demonstration, ArrayList implements the IList interface by using an array whose size is dynamically increased as required.
using System; using System.Collections; class listSample { public static void Main(string[] args) { ArrayList fruit = new ArrayList(); fruit.Add("Apple"); fruit.Add("Pear"); fruit.Add("Orange"); fruit.Add("Banana"); Console.WriteLine ("\nList Contains:"); foreach (string item in fruit) { Console.WriteLine(item); } Console.WriteLine ( "\nResult of Contains method for Kiwi: {0}", fruit.Contains("Kiwi")); Console.WriteLine ( "\nAdding Kiwi at Orange:"); fruit.Insert(fruit.IndexOf("Orange"),"Kiwi"); Console.WriteLine ("\nList Contains:"); foreach (string item in fruit) { Console.WriteLine(item); } // Code continued next page
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

44

Module 7: Strings, Arrays, and Collections


Console.WriteLine ( "\nResult of Contains method for Kiwi: {0}", fruit.Contains("Kiwi")); Console.WriteLine ( "\r\nPress Return to exit."); Console.Read(); } }

The preceding code example displays the following output to the console:
List Contains: Apple Pear Orange Banana Result of Contains method for Kiwi: False Adding Kiwi at Orange: List Contains: Apple Pear Kiwi Orange Banana Result of Contains method for Kiwi: True Press Return to exit.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

45

Dictionaries
Topic Objective
To describe the IDictionary interface and the classes that it implements.
!

Lead-in
IDictionary is an interface for collections of associated keys and values.
!

IDictionary is an Interface for Collections of Associated Keys and Values


$

Each association must have a unique non-null key, but the value of an association can be any object reference, including a null reference Hashtable, DictionaryBase, and SortedList Add, Clear, Contains, GetEnumerator, and Remove

Collection Classes That Implement IDictionary Include


$

Methods Include:
$

IDictionary is an interface for collections of associated keys and values. Each association must have a unique non-null key, but the value of an association can be any object reference, including a null reference. Hashtable, DictionaryBase, and SortedList are examples of collection classes that implement IDictionary. The IDictionary interface allows the contained keys and values in the items in a collection to be enumerated, but it does not imply any particular sort order. The IDictionaryEnumerator interface inherits from IEnumerator and adds members to return the objects Key and Value fields individually or in a DictionaryEntry structure. IDictionary implementations can be divided into the following categories:
!"

Read-only You cannot modify a read-only IDictionary. Fixed-size You cannot add or remove elements from a fixed-size IDictionary, but you can modify existing elements.

!"

!"

Variable-size You can add, remove, or modify elements in a variable-size IDictionary.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

46

Module 7: Strings, Arrays, and Collections

The following tables describe some of the public instance properties that the IDictionary interface implements.
Property IsFixedSize IsReadOnly Item Use When implemented by a class, gets a value indicating whether the IDictionary has a fixed size. When implemented by a class, gets a value indicating whether the IDictionary is read-only. When implemented by a class, gets or sets the element at the specified index. In C#, this property is the indexer for the class. Keys Values When implemented by a class, gets an ICollection containing the keys of the IDictionary. When implemented by a class, gets an ICollection containing the values in the IDictionary.

The following tables describe some of the public instance methods that the IDictionary interface implements.
Method Add Contains GetEnumerator Remove Use When implemented by a class, adds an entry with the provided key and value to the IDictionary. When implemented by a class, determines whether the IDictionary contains an entry with the specified key. When implemented by a class, returns an IDictionaryEnumerator for the IDictionary. When implemented by a class, removes the entry with the specified key from the IDictionary.

For a complete list of the members of the IDictionary interface, see IDictionary Members in the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

47

Demonstration: Hashtable
Topic Objective
To demonstrate how to create a hash table that is used for searches.

Lead-in
The Hashtable class represents a collection of associated keys and values that are organized on the basis of the keys hash code.

The Hashtable class represents a collection of associated keys and values that are organized on the basis of the keys hash code. The objects that are used as keys in a Hashtable must implement or inherit the Object.GetHashCode and Object.Equals methods. If key equality were simply reference equality, the inherited implementation of these methods would suffice. Furthermore, these methods must produce the same results when they are called with the same parameters while the key exists in the Hashtable. Key objects must be immutable as long as they are used as keys in the Hashtable. The foreach statement of the C# language requires the type of the elements in the collection. Because each element of the Hashtable is a key-and-value pair, the element type is not the type of the key or the type of the value. Instead, the element type is DictionaryEntry, as in the following example:
foreach (DictionaryEntry myEntry in myHashtable) {...}

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

48

Module 7: Strings, Arrays, and Collections

The code in this demonstration creates a hash table of employee numbers and names, and searches the table for an employee by number and by name.
using System; using System.Collections; class HashTableSample { public static void Main(String[] args) { //create hash table of employee numbers and names Hashtable table = new Hashtable(); table.Add("0123","Jay"); table.Add("0569","Brad"); table.Add("1254","Brian"); table.Add("6839","Seth"); table.Add("3948","Rajesh"); table.Add("1930","Lakshan"); table.Add("9341","Kristian"); printTable(table); //now we'll look to see if an employee is in the table //by key Console.Write( "Search for employee by key, enter ID ==-> "); string input = Console.ReadLine(); if (table.Contains(input)) { Console.WriteLine("Found {0} in the list.",input); } else { Console.WriteLine("Employee {0} not found.",input); } //by value Console.Write( "Search for employee by value, enter name ==-> "); input = Console.ReadLine(); if (table.ContainsValue(input)) { Console.WriteLine("Found {0} in the list.",input); } else { Console.WriteLine("Employee {0} not found.",input); } printTable(table); // remove an employee by key Console.Write("Remove employee by key, enter ID ==-> "); input = Console.ReadLine(); table.Remove(input); printTable(table); Console.WriteLine ("\r\nPress Return to exit."); Console.Read(); } // Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections


public static void printTable(Hashtable table) { Console.WriteLine ("Current list of employees:\n"); Console.WriteLine ("ID\tName"); Console.WriteLine ("--\t----"); foreach (DictionaryEntry d in table) { Console.WriteLine ("{0}\t{1}", d.Key, d.Value); } } }

49

The preceding code example displays the following output or similar output to the console:
Current list of employees: ID Name ----1254 Brian 6839 Seth 3948 Rajesh 1930 Lakshan 0123 Jay 0569 Brad 9341 Kristian Search for employee by key, enter ID ==-> 111 Employee 111 not found. Search for employee by value, enter name ==-> Jay Found Jay in the list. Current list of employees: ID Name ----1254 Brian 6839 Seth 3948 Rajesh 1930 Lakshan 0123 Jay 0569 Brad 9341 Kristian Remove employee by key, enter ID ==-> 9341 Current list of employees: ID -1254 6839 3948 1930 0123 0569 Name ---Brian Seth Rajesh Lakshan Jay Brad

Press Return to exit.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

50

Module 7: Strings, Arrays, and Collections

SortedList
Topic Objective
To explain how arrays are used in a SortedList and how to create, initialize, and access a SortedList. This topic is very important because its contents are required for the lab.
!

SortedList Maintains Two Arrays for Entries


$

One array for the keys and another array for the associated values

Lead-in
A SortedList maintains two arrays internally to store entries to the list: one array for the keys, and another array for the associated values.

SortedList mySL = new SortedList(); SortedList mySL = new SortedList(); // Add an entry with a key = "First" and a value = 1 // Add an entry with a key = "First" and a value = 1 mySL.Add("First", 1); mySL.Add("First", 1); // Increment the value of the entry whose key = "First" // Increment the value of the entry whose key = "First" mySL["First"] = (Int32)mySL["First"] + 1; mySL["First"] = (Int32)mySL["First"] + 1;
! !

Count Property Number of Elements in the SortedList Sorted Using a Specific IComparer Implementation or According to the Key's IComparable Implementation Printing the Keys and Values of a SortedList

for ( int i = 0; i < myList.Count; i++ ) { for ( int i = 0; i < myList.Count; i++ ) { Console.WriteLine( "\t{0}:\t{1}", Console.WriteLine( "\t{0}:\t{1}", myList.GetKey(i), myList.GetByIndex(i) ); } myList.GetKey(i), myList.GetByIndex(i) ); }

A SortedList maintains two arrays internally to store entries to the list: one array for the keys, and another array for the associated values. An entry is a key-and-value pair. A SortedList implements the IDictionary, IEnumerable, ICollection, and ICloneable interfaces. The Count property gets the number of elements that are contained in the SortedList. The Add method is used to add an entry to the SortedList. The [] Operator is used to modify the value of an entry with the specified key. For Your Information
You should carefully cover the SortedList class, the Add method, and the [] Operator because they are used in the lab.

You can sort the keys of a SortedList according to an IComparer implementation that is specified when the SortedList is instantiated or according to the IComparable implementation that is provided by the keys themselves. In either case, a SortedList does not allow duplicate keys. Operations on a SortedList tend to be slower than operations on a Hashtable because of the sorting. However, the SortedList offers more flexibility by allowing access to the values through the associated keys or through the indexes. A key cannot be a null reference, but a value can be a null reference. Indexes in the SortedList collection are zero-based.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

51

The following example shows how to create a SortedList, add an entry, modify an entrys value, and print out the SortedLists keys and values.
using System; using System.Collections; public class SamplesSortedList public static void Main() {

// Create and initialize a new SortedList. SortedList mySL = new SortedList(); mySL.Add("First", 1); mySL.Add("Second", 2); mySL.Add("Third", 3); // Display the properties and values of the SortedList. Console.WriteLine( "mySL" ); Console.WriteLine( " Count: {0}", mySL.Count ); Console.WriteLine( " Capacity: {0}", mySL.Capacity ); Console.WriteLine( " Keys and Values:" ); PrintKeysAndValues( mySL ); // increment the value of the entry whose key is "Third" mySL["Third"] = (Int32)mySL["Third"] + 1; PrintKeysAndValues( mySL ); }

public static void PrintKeysAndValues( SortedList myList ){ Console.WriteLine( "\t-KEY-\t-VALUE-" ); for ( int i = 0; i < myList.Count; i++ ) { Console.WriteLine( "\t{0}:\t{1}", myList.GetKey(i), myList.GetByIndex(i) ); } Console.WriteLine(); } }

The preceding code example displays the following output to the console:
Count: 3 Capacity: 16 Keys and Values: -KEY-VALUEFirst: 1 Second: 2 Third: 3 -KEYFirst: Second: Third: -VALUE1 2 4

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

52

Module 7: Strings, Arrays, and Collections

Collection Usage Guidelines


Topic Objective
To distinguish between collections and arrays and explain when collections are used.
!

Use a Collection instead of an Array:


$

Lead-in
Arrays and collections are used similarly, but they perform differently.
!
$

When Add, Remove, or other methods for manipulating the set of objects are supported. This scopes all related methods to the collection When you want to provide a read-only set of objects. System.Array objects are always writable - You can add read-only wrappers around internal arrays

Indexed Properties in Collections Should Only Be Used As the Default Member of a Collection Class or Interface Use Collections to Avoid the Inefficiencies in the Following Code

for (int i = 0; i < obj.Foo.Count; i++) for (int i = 0; i < obj.Foo.Count; i++) DoSomething(obj.Foo[i]); DoSomething(obj.Foo[i]);

Class library designers sometimes need to decide when to use an array and when to use a collection. Arrays and collections have similar usage models, but they differ somewhat in performance.

Collections vs. Arrays


When Add, Remove, or other methods for manipulating the collection are supported, use a collection, instead of an array. Using a collection scopes all related methods to the collection. Also, use collections to add read-only wrappers around internal arrays. System.Array objects are always writable.

Array Valued Properties


Use collections to avoid the inefficiencies in the following naive code:
for (int i = 0; i < obj.Foo.Count; i++) DoSomething(obj.Foo[i]);

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

53

Choosing A Collection Class


Choosing the right Collections class must be done carefully. Using the wrong collection can unnecessarily restrict how you use it. Consider the following questions:
!"

Do you need temporary storage? If yes, consider Queue or Stack. If no, consider the other collections.

!"

Do you need to access the elements in a certain order, such as first-in-firstout or last-in-first-out or randomly? The Queue offers first-in, first-out access. The Stack offers last-in, first-out access. The rest of the collections offer random access.

!"

Do you need to access each element by index? ArrayList and StringCollection offer access to their elements by the zero-based index. Hashtable, SortedList, ListDictionary, and StringDictionary offer access to their elements by the key of the element. NameObjectCollectionBase and NameValueCollection offer access to their elements either by the zero-based index or by the key of the element.

!"

Will each element contain just one value or a key-singlevalue pair or a keymultiplevalues combination? One value: Use any of the collections based on IList. Key-singlevalue pair: Use any of the collections based on IDictionary. Key-multiplevalues combination: Consider using or deriving from the NameValueCollection class in the Collections.Specialized namespace.

!"

Do you need to sort the elements differently from how they were entered? Hashtable sorts the elements by the hash code of the key. SortedList sorts the elements by the key, based on an IComparer implementation. ArrayList provides a Sort method that takes an IComparer implementation as a parameter.

!"

Do you need fast searches and retrieval of information? ListDictionary is faster than Hashtable for small collections of ten items or less.

!"

Do you need collections that accept only strings? StringCollection (based on IList) and StringDictionary (based on IDictionary) are in the Collections.Specialized namespace.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

54

Module 7: Strings, Arrays, and Collections

Type Safety and Performance


Topic Objective
To discuss runtime casting for type safety and the effects of runtime casting and boxing and unboxing on performance.
! !

System.Collections Items Require a Runtime Object Cast Drawbacks of Runtime Casting


$ $ $

Type errors found at runtime, rather than at compile time Runtime overhead of casting Runtime overhead of boxing/unboxing operations for value types System.Collections.Specialized namespace contains stringspecific collections Create your own type-specific collection class by inheriting from a System.Collections class and adding type-specific members Encapsulate value types in a class Manipulate value types through interfaces

Lead-in
The System.Collections classes are generic collections, which ignore their items true types. Generic collections allow classes to be used for items of any type.
!

Type-Specific Collection Classes Can Eliminate Runtime Casting


$

Ways to Reduce Boxing and Unboxing Operations of Value Types


$ $

The System.Collections classes are generic collections, which ignore their items true types. Generic collections allow classes to be used for items of any type.

Drawbacks of Runtime Casting


The System.Collections classes have properties and methods that manipulate the collections items through the items System.Object base type. The classs members take and return parameters of type System.Object. For example, IEnumerator.Current returns a System.Object instance. This use of an objects base class requires casting a runtime object to obtain the true type of the object. Casting System.Object instances at run time has two drawbacks:
!"

Collection operations with invalid parameter or return types are not flagged at compile time. If the cast is invalid, the problem is only detected at run time when an InvalidCastException is thrown.

!"

Such casting hurts runtime performance because the .NET runtime must perform type-checking.

In addition, in the case of a collection of value types, such as an int, casting to and from System.Object results in boxing and unboxing operations that further impair performance. The ideal solution to these two drawbacks would be a language mechanism that automatically generates a type-specific version of the System.Collections classes that is similar to the C++ template class mechanism. For example, if you declared an ArrayList<int>, this object would store int values directly, without casting and without boxing. This feature is not implemented in the first version of C#; however, it may be implemented in a later version.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

55

The System.Collections classes provide a simple and powerful way to implement collections. Carefully evaluate whether the use of these classes in your programs imposes a significant enough performance penalty to warrant taking the further action that is described in the following sections.

Strongly-Typed Collections
One way to provide compile-time type-checking and improve the performance of collection code is to use strongly-typed collections. The System.Collections.Specialized namespace contains string-specific collection classes, as described in the following table.
Class NameValueCollection Description Represents a sorted collection of associated String keys and String values that can be accessed with the hash code of the key or with the index. Represents a collection of strings. Implements a hash table with the key strongly-typed to be a string, rather than an object. Supports a simple iteration over a StringCollections.

StringCollection StringDictionary StringEnumerator

Creating Custom Collection Classes


You can also create your own strongly-typed collection by creating your own custom collection class. Your class can reuse System.Collections functionality by inheriting from the appropriate System.Collections class. You create the type-specific class with methods and properties whose parameters and return types are type-specific. By using C#s explicit interface implementation mechanism, which is discussed in Module 6, Working with Types, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease), a class can implement both non-interface and interface members of the same name. Explicit interface method implementations are frequently used when you implement such interfaces as IEnumerable, IEnumerator, ICloneable, IComparable, ICollection, IList, and IDictionary. By having both sets of members, clients that expect type-specific or System.Object parameters and return values can use the custom class.

Techniques for Handling Boxing and Unboxing


Instead of creating a type-specific collection class, you can simply remove the overhead of boxing and unboxing by using a reference type, rather than a value type, for the items in a collection. To accomplish this, you can wrap a value type in a class, as shown in Module 6. In some cases, you can reduce boxing and unboxing by using interfaces. Value types can implement interfaces, but because interfaces are referenced types, you can only have an interface reference to a boxed value type. You can define an interface for your value type that has the methods and properties that are needed to manipulate the value type. The value type instance must still be boxed when it is inserted into a generic System.Collections object, but your code will be able to manipulate the items value through its interface without unboxing the item.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

56

Module 7: Strings, Arrays, and Collections

For example, in the case of a collection of integer values where you want to be able to add an integer to an elements value, you can have your value type implement an interface, as in the following code:
interface IAdd { void Add(int amount); }

struct IntStruct: IAdd { int number; public IntStruct(int number) { this.number = number; } public int Number { get { return(number);} } public void Add(int amount) { number += amount; } public override string ToString() { return(number.ToString()); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

57

Lab 7: Working with Strings, Enumerators, and Collections

Objectives
After completing this lab, you will be able to:
!" !"

Create an application that parses and formats strings. Create an application that uses SortedList collection objects.

Lab Setup
Starter and solution files are associated with this lab. The starter files are in the folder <install folder>\Labs\Lab07\Starter, and the solution files are in the folder <install folder>\Labs\Lab07\Solution.

Scenario
In this lab, you are provided with a Visual Studio .NET console application as a starting point. The application, named WordCount, parses a test string into words and then determines the number of unique words and the number of times each word occurs. The results of this analysis are formatted and displayed on the console. The application is a modified version of the .NET Framework SDK sample, Word Count.

Estimated time to complete this lab: 60 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

58

Module 7: Strings, Arrays, and Collections

Exercise 1 Sorting Words Alphabetically


In this exercise, you will create a class that breaks up the test string into words and then stores each word and the number of its occurrences in a SortedList. By default, the sort order will be based on the alphabetical ordering of the word keys.

!" modify the WordCount class to sort words alphabetically To


1. Open the WordCount project in the starter directory by using Visual Studio .NET. 2. Open the WordCount.cs file. 3. In the WordCounter class, create a member named wordCounter that is an instance of the SortedList class. 4. Create a read-only property named UniqueWords that returns the number of items in wordCounter. 5. Create a public method named GetWordsAlphabeticallyEnumerator that takes no arguments and returns a wordCounter enumerator object of type IDictionaryEnumerator. 6. Create a public method named CountStats that takes two out parameters of type Int64 named numWords and numChars and returns a Boolean. 7. Implement the CountStats method to break up the test string, create the alphabetically sorted list, and return the word count statistics. a. Initialize the CountStats methods out parameters to 0. b. Use the String.Split method to break up testString into individual words that are stored in an array of type string named Words. c. Assign to the out parameter numWords the number of words that are obtained in step 7.b. d. For each non-empty string in the array Words: i. Add the number of characters in the word string to numChars. ii. If wordCounter does not already contain the string, add a new entry whose key is the string and whose value is 1. The value represents the number of occurrences of the word. Otherwise, increment by one the value of the existing entry. Tip For information about and examples of the IDictionary methods named Add and Contains, see Dictionaries and Demonstration: Hashtable in Module 7. For an example of how to modify the value of an entry by using the [] Operator, see SortedList in Module 7. iii. Return true.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

59

!" modify the Application class To


1. In the Application class's Main method, create an instance of WordCounter named wc. 2. Create two variables of type Int64 named NumWords and NumChars. 3. Call the wc objects CountStats method to assign the word and character counts to NumWord and NumChars respectively. 4. Output to the console the test string WordCounter.testString. 5. Output to the console a two-column header labeled Words and Chars. Use a tab to separate the columns. 6. Output to the console the number of words, and format this output to occupy five characters, followed by a tab and the number of characters.

!" test the WordCount application To


Build and run the application. You should see output that is similar to the following:
For string Hello world hello here Words 11 Chars 41

i am where are you hello you

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

60

Module 7: Strings, Arrays, and Collections

Exercise 2 Sorting Words by Number of Occurrences


In this exercise, you will create a nested class that implements the IComparable interface and whose CompareTo method will result in a SortedList that is ordered on the basis of the number of occurrences of a word.

!" modify the WordCount class to sort words by occurrences To


1. Add a nested class named WordOccurrence that inherits from IComparable. 2. Add a private member of type int named occurrences. 3. Add a private member of type String named word. 4. Add a constructor that takes two parameters. The first parameter is of type int, and the second parameter is of type String. The constructor assigns the first value to occurrences and the second value to word. 5. Add a public method CompareTo that takes an Object parameter and returns an int. The code should follow the CompareTo design pattern and return a value that results in a sort of words that is ordered by the occurrences of each word in ascending order. Less frequently occurring words should be followed by more frequently occurring words. In the case in which the number of occurrences of the instance and the Object parameter are the same, the sort should be alphabetical by using the String.Compare method. Tip For an example of implementing the CompareTo method see Demonstration: Sorting and Enumerating an Array in Module 7. 6. Add two public read-only properties named Occurrences and Word that return the fields occurrences and word respectively. End the nested class definition. 7. Back in the WordCounter class itself, add a public method named GetWordsByOccurrenceEnumerator that returns an object of type IDictionaryEnumerator. Implement GetWordsByOccurrenceEnumerator as follows: a. Create a new SortedList named sl. b. Iterate through the alphabetically-sorted list named wordCounter by using an enumerator that is obtained by calling the GetWordsAlphabeticallyEnumerator method. i. For each alphabetical list entry, create a new object of type WordOccurence that is initialized with the alphabetically sorted list entrys Value and Key. ii. Add to sl a new entry whose key field is the new WordOccurence object and whose value field is set to null. c. Return an enumerator of sl of type IDictionaryEnumerator.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

61

!" modify the Application class To


1. Output the words to be sorted alphabetically by adding code to the Application classs Main method to: a. Obtain an IDictionaryEnumerator object named de by calling the wc objects GetWordsAlphabeticallyEnumerator method. b. Display a message to inform the user that the output that is generated will display word usage sorted alphabetically. Also inform the user of the number of unique words. c. Iterate over the collection and output each entrys value and key, formatting them so that the value is displayed in the first column and the key is displayed in the second column. 2. Output the words sorted by occurrence by adding code to: a. Assign to de an IDictionaryEnumerator object by calling the wc objects GetWordsByOccurrenceEnumerator method. b. Display a message to inform the user that the output that is generated will display word usage sorted by occurrence. Also inform the user of the number of unique words. c. Iterate over the collection. For each entry, obtain the key fields WordCounter.WordOccurrence object and output to the console the Occurrences property of the WordCounter.WordOccurrence object in the first column and the objects Word property in the second column.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

62

Module 7: Strings, Arrays, and Collections

!" test the WordCount application To


Build and run the application. You should see output that is similar to the following:
For string Hello world hello here

i am where are you hello you

Words Chars 11 41 Word usage sorted alphabetically (9 unique words) 1: "am" 1: "are" 2: "hello" 1: "Hello" 1: "here" 1: "i" 1: "where" 1: "world" 2: "you" Word usage sorted by occurrence (9 unique words) 1: am 1: are 1: Hello 1: here 1: i 1: where 1: world 2: hello 2: you

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 7: Strings, Arrays, and Collections

63

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! ! ! !

Strings Terminology Collections .NET Framework Arrays .NET Framework Collections

Lead-in
The review questions cover some of the key concepts taught in the module.

1. Enter the code to read an integer from the console and assign it to a variable named aNumber. int MyInt = int.Parse(Console.ReadLine());

2. What class should you use to improve performance when you want to perform repeated modifications to a string? System.Text.StringBuilder

3. Name and briefly describe the interfaces implemented by System.Array. ICloneable: Supports cloning, which creates a new instance of a class with the same value as an existing instance. IList: Represents a collection of objects that can be individually indexed. ICollection: Defines size, enumerators, and synchronization methods for all collections. IEnumerable: Exposes the enumerator, which supports a simple iteration over a collection.

4. What does it mean to say that an enumerator is required to be safe. The enumerator must have a fixed view of the items in a collection that remains the same, even if the collection is modified.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

64

Module 7: Strings, Arrays, and Collections

5. Create an array that contains the integers 1, 2, and 3. Then use the C# foreach statement to iterate over the array and output the numbers to the console. int[] numbers = {1, 2, 3}; foreach (int i in numbers) { System.Console.WriteLine("Number: {0}", i); }

6. What is the name of the interface that is implemented by classes that contain an ordered collection of objects that can be individually indexed? Name the System.Collections classes that implement this interface. The IList interface is implemented by Array, ArrayList, StringCollection, and TreeNodeCollection.

7. What is the name of the interface for collections of associated keys and values? Name the System.Collections classes that implement this interface. The IDictionary interface is implemented by Hashtable, DictionaryBase, and SortedList.

8. Generic collection classes require runtime type-casting of their items to obtain the true type of the items in the collection classes. Name the issues raised by runtime casting? Type-checking cannot be done at compile time. Performance overhead of casting. In the case of collection of value types, boxing and unboxing operations.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events


Contents Overview Delegates Demonstration: Using Delegates Multicast Delegates Demonstration: Multicast Delegates Events When to Use Delegates, Events, and Interfaces Lab 8: Creating a Simple Chat Server Review 1 2 8 12 19 22 30 31 40

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

iii

Instructor Notes Module 8


Presentation: 75 Minutes Lab: 70 Minutes After completing this module, students will be able to:
!"

Use the delegate class to create type-safe callback functions and eventhandling methods. Use the event keyword to simplify and improve the implementation of a class that raises events. Implement events that conform to the Microsoft .NET Framework guidelines.

!"

!"

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_08.ppt

Preparation Tasks
To prepare for this module, you should:
!" !" !"

Read all of the materials for this module. Practice the demonstrations. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 8: Delegates and Events

Demonstrations
This section provides demonstration procedures that will not fit in the margin notes or are not appropriate for the student notes.

Using Delegates
In this demonstration, you will use Microsoft Visual Studio .NET to run code in which a delegate to a light objects method is passed to a switch object. When the switch objects state changes, the switch object calls the light objects method and passes its new state. The code for this demonstration is provided in the student notes. The demonstration files are located in <install folder>\Democode\Mod08\Demo08.1\Using Delegates

Multicast Delegates
In this demonstration, you will show students how to add and remove methods from the invocation list of multicast delegates by using the plus operator (+) and the minus operator (-). The code for this demonstration is provided in the student notes. The demonstration files are located in <install folder>\Democode\Mod08\Demo08.2\MULTICAST DELEGATES.

Module Strategy
Use the following strategy to present this module:
!"

Delegates Use the Delegate Scenario to help students to visualize and comprehend the concept of delegates. Some students may question the validity of this scenario. In the real world, a house would never be rewired dynamically, but you can explain that software programs often need to rebind dynamically.

!"

Multicast Delegates Contrast typical multicast delegate use with that of the single delegate example by using the common scenario of a switch that controls two light bulbs. Explain how to create and invoke multicast delegates and show how to use the + and operators in C# to add and remove methods from the invocation list of multicast delegates

!"

Events Emphasize that events are an important building block for creating classes that can be reused in many different programs, and that delegates are particularly suited for event handling. Explain how to declare, connect to, and raise an event. Introduce the .NET Framework guidelines for delegates and events.

!"

When to Use Delegates, Events, and Interfaces Contrast and compare the specific usage characteristics of delegates, interfaces, and events for providing callback functionality in particular situations.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! ! ! !

Delegates Multicast Delegates Events When to Use Delegates, Events, and Interfaces

Lead-in
Delegates are the objectoriented equivalents of function pointers.

In the Microsoft .NET Framework, delegates are the object-oriented equivalents of function pointers. However, unlike function pointers, delegates are type-safe and secure. The common language runtime supports the use of delegates in callback and event-handling scenarios. An event is raised by an object or event source in response to an action performed by a user or some sort of program logic. The event receiver must then respond to the raised event and perform an action. The event keyword lets you specify delegates that will be called upon the occurrence of an event. After completing this module, you will be able to:
!"

Use the delegate class to create type-safe callback functions and eventhandling methods. Use the event keyword to simplify and improve the implementation of a class that raises events. Implement events that conform to the .NET Framework guidelines.

!"

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

# Delegates
Topic Objective
To provide an overview of the topics in this section.
! ! ! !

Delegate Scenario Declaring a Delegate Instantiating a Delegate Calling a Delegate

Lead-in
In this section, you will learn about how delegates are used in the .NET Framework.

You can use delegates to encapsulate a reference to a method inside a delegate object. Because delegates are type-safe, secure, managed objects, they offer all of the advantages of pointers without any of the disadvantages of pointers. For example, delegates will always point to a valid object and cannot corrupt the memory of other objects.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

Delegate Scenario
Topic Objective
To illustrate one use of delegates through the scenario of a switch and a light bulb.
1 - Change in switch position invokes switchs OnFlip method

Switch Object

Lead-in
This scenario of a switch that controls a light illustrates one use of delegates.
OnFlip method
2 - OnFlip Method invokes delegate

Light Object

Delegate object Delegate object


3 - Delegate invokes lights OnFlipCallback method

OnFlipCallback method
4 - OnFlipCallback method changes lights state

To run the build slide, click through the lower left button on the slide.

This scenario of a switch that controls a light illustrates one use of delegates. The switch object models an electric switch, and the light object models an electric light. The delegate object encapsulates a reference to a light objects OnFlipCallback method. The switch object code could be written without a delegate by referring directly to the specific light objects method. However, this approach does not offer the flexibility to dynamically connect, disconnect, and reconnect various light object methods to the switch object. You can use a delegate object that connects the switch object and the light object to achieve this flexibility.

For Your Information


Stress that this scenario reflects a common scenario to which everyone can relate. While you may not use the same light switch to turn different lights on and off at different times, this scenario helps you to visualize and comprehend the concepts behind delegates.

In real life, the preceding scenario would probably not occur as described. While a house would never be rewired dynamically, software programs often need to dynamically rebind. When the switch is flipped in the light switch scenario shown in the slide: 1. The switch objects OnFlip method is invoked. 2. The OnFlip method invokes the delegate object. 3. The delegate object invokes the light objects OnFlipCallback method. 4. The OnFlipCallback method changes the state of the light.

Delivery Tip
You should briefly preview the Demonstration: Using Delegates to provide students with an overview of the code that can be used to implement this scenario. Defer discussion of delegate specific code until after the following topics are covered.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

Declaring a Delegate
Topic Objective
To explain how to declare a delegate.
!

Lead-in
A delegate declaration defines a type that encapsulates a method with a particular set of arguments and return type.

A Delegate Declaration Defines a Type That Encapsulates a Method with a Particular Set of Arguments and Return Type

// declares a delegate for a method that takes a single // declares a delegate for a method that takes a single // argument of type string and has a void return type // argument of type string and has a void return type delegate void MyDelegate1(string s); delegate void MyDelegate1(string s);

A delegate declaration defines a type that encapsulates a method with a particular set of arguments and return type. The delegate declaration is sufficient to define a delegate class whose actual implementation is provided by the common language runtime. For Your Information
The details of how the common language runtime creates delegates are presented later in this module.

The following example shows how to declare a delegate for a method that takes a single argument of type string and has a void return type:
delegate void MyDelegate1(string s);

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

Instantiating a Delegate
Topic Objective
To explain how to instantiate delegates.
! !

A Delegate Object Is Created with the new Operator Delegate Objects Are Immutable

Lead-in
Once you have declared a delegate type, you can create a delegate object and associate it with a particular method.

// instantiating a delegate to a static method Hello // instantiating a delegate to a static method Hello // in the class MyClass // in the class MyClass MyDelegate1 a = new MyDelegate1(MyClass.Hello); MyDelegate1 a = new MyDelegate1(MyClass.Hello); // instantiating a delegate to an instance method // instantiating a delegate to an instance method // AMethod in object p // AMethod in object p MyClass p = new MyClass(); MyClass p = new MyClass(); MyDelegate1 b = new MyDelegate1(p.AMethod); MyDelegate1 b = new MyDelegate1(p.AMethod);

After you have declared a delegate type, you can create a delegate object and associate it with a particular method. This topic explains the code used to instantiate delegates.

Creating a New Delegate Object


Like all objects, a new delegate object is created with the new operator. When creating a delegate, however, the argument passed to the new operator is special: it is written like a method call, but without the arguments to the method. After a delegate is created, the method to which it is associated never changes: delegate objects are immutable. Delivery Tip
To place the delegate instantiation code in a fuller context, refer to the following example.

When referencing an object, an interesting and useful feature of a delegate is that the delegate does not know or care about the class of the object that it references. It can reference any object as long as the methods signature matches the delegates signature. A delegate can reference static or instance methods. When referencing instance methods, the delegate stores not only a reference to the methods entry point, but also a reference to the object instance on which the method is invoked.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

The following example shows how to declare a delegate named MyDelegate1. The code illustrates how this delegate can be instantiated to a static or an instance method. The signature of the method and MyDelegate1 must match; the method must have a void return and take a single argument of type string.
delegate void MyDelegate1(string s); ... public class MyClass { public static void Hello(string s) { //... } public void AMethod(string s) { //... } } ... // instantiating a delegate to a static method MyDelegate1 a = new MyDelegate1(MyClass.Hello); // instantiating a delegate to object p's AMethod method MyClass p = new MyClass(); MyDelegate1 b = new MyDelegate1(p.AMethod);

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

Calling a Delegate
Topic Objective
To explain how to call delegates.
!

Lead-in
After a delegate is created, it can be passed to other code that will call the delegate.

Use a Statement Containing:


$ $

The name of the delegate object Followed by the parenthesized arguments to be passed to the delegate

// // // // // //

given the previous delegate declaration and given the previous delegate declaration and instantiation, the following invokes MyClass' instantiation, the following invokes MyClass' static method Hello with the parameter "World" static method Hello with the parameter "World"

a("World"); a("World");

After a delegate object is created, it can be passed to other code that will call the delegate. For example, a server object may provide a method that a client object calls to register a callback method for a specific event. The server will invoke this callback method when that event occurs. Typically, the client instantiates a delegate that refers to its callback method. The client passes the callback delegate object as a parameter. For Your Information
Refer to the previous slide on delegate declaration and instantiations.

You can call a delegate object by using the name of the delegate, followed by the parenthesized arguments to be passed to the delegate. For example, given the declaration and instantiations of delegates a and b shown in the previous slide, the following lines invoke the static Hello method of the class MyClass and the AMethod of the MyClass object p with the argument "World":
a("World"); b("World");

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

Demonstration: Using Delegates


Topic Objective
To demonstrate using a callback delegate.

Lead-in
In this demonstration, you will use Microsoft Visual Studio .NET to run code in which a delegate to a light objects method is passed to a switch object. When the switch objects state changes, the switch object calls the light objects method and passes its new state.

Delivery Tip
Use Visual Studio .NET to run the following code. Set breakpoints or single step to illustrate the sequence of events.

In this demonstration, you will use Microsoft Visual Studio .NET to run code in which a delegate to a light objects method is passed to a switch object. When the switch objects state changes, the switch object calls the light objects method and passes its new state.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events


using System; namespace SwitchAndLight { public enum SwitchPosition {Up, Down}; delegate void SwitchFlipped(SwitchPosition switchState); class Light { private string name; public Light(string s) { name = s; } public void OnFlipCallback(SwitchPosition switchState) { if (switchState == SwitchPosition.Up) { Console.WriteLine("... {0} light is on",name); } else { Console.WriteLine("... {0} light is off",name); } } } class Switch { private SwitchPosition switchState = SwitchPosition.Down; private SwitchFlipped switchFlippedHandler = null; public void ConnectToLight(SwitchFlipped lightHandler) { switchFlippedHandler = lightHandler; } public SwitchPosition SwitchState { get {return switchState;} } public void OnFlip() { if (switchState == SwitchPosition.Down) { switchState = SwitchPosition.Up; } else { switchState = SwitchPosition.Down; }
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 8: Delegates and Events


if (switchFlippedHandler != null) { switchFlippedHandler(switchState); } } } class TheApp { static void OnFlip(Switch aSwitch) { Console.WriteLine( "Before flipping, the switch is: {0}", aSwitch.SwitchState); Console.WriteLine("Flipping switch ... "); aSwitch.OnFlip(); Console.WriteLine( "After flipping, the switch is: {0}\n\n", aSwitch.SwitchState); } static void Main(string[] args) { Switch s = new Switch(); Light light1 = new Light("bathroom"); Light light2 = new Light("bedroom"); // connect switch and bathroom light by passing a // delegate to the bathroom light's // OnFlipCallback method to s s.ConnectToLight(new SwitchFlipped(light1.OnFlipCallback)); OnFlip(s); OnFlip(s); // connect switch and bedroom light by passing a // delegate to the bedroom's light's // OnFlipCallback method to s s.ConnectToLight(new SwitchFlipped(light2.OnFlipCallback)); OnFlip(s); OnFlip(s); } } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

11

This code generates the following output:


Before flipping, the switch is: Down Flipping switch ... ... bathroom light is on After flipping, the switch is: Up

Before flipping, the switch is: Up Flipping switch ... ... bathroom light is off After flipping, the switch is: Down

Before flipping, the switch is: Down Flipping switch ... ... bedroom light is on After flipping, the switch is: Up

Before flipping, the switch is: Up Flipping switch ... ... bedroom light is off After flipping, the switch is: Down

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 8: Delegates and Events

# Multicast Delegates
Topic Objective
To provide an overview of the topics in this section.
! ! ! ! !

Lead-in
If you change the state in one object, you may need to broadcast that change to multiple objects.

Multicast Delegate Scenario Single vs. Multicast Delegates Creating and Invoking Multicast Delegates C# Language-Specific Syntax Delegate Details

If you change the state in one object, you may need to broadcast that change to multiple objects. You can use multicast delegate objects to provide this functionality; they can be composed together so that a single invocation invokes all of their methods, just as a single light switch can turn on or off all lights connected to that switch.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

13

Multicast Delegate Scenario


Topic Objective
To illustrate the typical multicast delegate use by using the common scenario of a switch that controls two light bulbs.
1 - Change in switch position invokes switchs OnFlip method

Switch Object

4 - OnFlipCallback method changes light1s state

Light1 Object Light2 Object

Lead-in
The following scenario of a switch that controls two lights illustrates the use of multicast delegates.
OnFlip method
2 - OnFlip method invokes multicast delegate1 OnFlipCallback method OnFlipCallback method 7 - OnFlipCallback method changes light2s state 6 - delegate2 invokes light2s OnFlipCallback

3 - delegate1 invokes light1s OnFlipCallback Invocation list Multicast delegate1 object Multicast delegate1 object

5 - delegate2 is invoked

Multicast delegate2 object Multicast delegate2 object

To run the build slide, click through the lower left button on the slide.

The following scenario of a switch that controls two lights illustrates the use of multicast delegates. The switch object models the light switch, and the two light objects model the two electric lights. To provide the capability to dynamically connect, disconnect, and reconnect light object methods to the switch object, the switch object is dynamically connected to the light objects by instantiating and composing two multicast delegate objects. In the light scenario, multicast delegate1 refers to the light1 objects OnFlipCallback method, and multicast delegate2 refers to the light2 objects OnFlipCallback method. Their composition logically represents an invocation list, a list of methods that are executed when the delegate is invoked. In this case, the invocation list consists of these two methods. In the light switch scenario shown in the slide, the multicast delegate objects encapsulate references to two objects and two methods. When the switch is flipped: 1. The switch objects OnFlip method is invoked. 2. The OnFlip method invokes the multicast delegate1 object. 3. The multicast delegate1 object first invokes the light1 objects OnFlipCallback method. 4. The light1 objects OnFlipCallback method changes the state of the light1 object. 5. The multicast delegate1 object next invokes the multicast delegate2 object. 6. The multicast delegate2 object invokes the light2 objects OnFlipCallback method. 7. The light2 objects OnFlipCallback method changes the state of the light2 object. You can compose additional multicast delegates to allow the switch to control additional lights.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 8: Delegates and Events

Single vs. Multicast Delegates


Topic Objective
To explain the difference between single-cast and multicast delegates.
!

All Delegates Have an Invocation List of Methods That Are Executed When Their Invoke Method is Called Single-Cast Delegates: Derived Directly From System.Delegate
$

Lead-in
When delegate declarations are compiled, the compiler generates a new class, which derives from two delegate classes provided by the .NET Framework.
!

Invocation list contains only one method Invocation list may contain multiple methods Multicast delegates contain two static methods to add and remove references from invocation list: Combine and Remove

Multicast Delegates: Derived from System.MulticastDelegate


$ $

Use GetInvocationList to Obtain an Invocation List as an Array of Delegate References Use a Delegates Target and Method Properties to Determine:
$ $

Which object will receive the callback Which method will be called

When delegate declarations are compiled, the compiler, in effect, generates a new class. The new delegate class derives from one of the two delegate classes provided by the .NET Framework: System.Delegate and System.MulticastDelegate. All delegates have an invocation list, or linked list of delegates that are executed when the invoke method is called. A delegate that derives from the Delegate class contains an invocation list with one method, and a delegate that derives from the MulticastDelegate class may contain an invocation list with multiple methods. The MulticastDelegate class contains two static methods to add and remove method references from an invocation list: Combine and Remove. Combine is declared as follows:
public static Delegate Combine( Delegate a, Delegate b);

The method returns a new multicast Delegate object with an invocation list that concatenates the invocation lists of a and b in that order. Remove is declared as follows:
public static Delegate Remove( Delegate source, Delegate value);

The method returns a new Delegate objectwith an invocation list formed by taking the invocation list of source and removing the last occurrence of value, if value is found in the invocation list of source. If value is null or if value is not found, then source is returned.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

15

You can use the method GetInvocationList to obtain the invocation list as an array of delegate references. You can also use the delegates Target and Method properties to determine which object is to receive the callback and which method is to be called. In the case of a static method, Target is null.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 8: Delegates and Events

Creating and Invoking Multicast Delegates


Topic Objective
To provide specific examples of how to create and invoke multicast delegates, and how to iterate though an invocation list to invoke specific delegates.

// assign to c the composition of delegates a and b // assign to c the composition of delegates a and b c = (MyDelegate2)Delegate.Combine(a, b); c = (MyDelegate2)Delegate.Combine(a, b); // assign to d the result of removing a from c // assign to d the result of removing a from c d = (MyDelegate2)Delegate.Remove(c, a); d = (MyDelegate2)Delegate.Remove(c, a); // Iterate through c's invocation list // Iterate through c's invocation list // and invoke all delegates except a // and invoke all delegates except a Delegate[] DelegateList = c.GetInvocationList(); Delegate[] DelegateList = c.GetInvocationList(); for (int i = 0; i < DelegateList.Length; i++) { for (int i = 0; i < DelegateList.Length; i++) { if (DelegateList[i].Target != aFoo1) { if (DelegateList[i].Target != aFoo1) { ((MyDelegate2) DelegateList[i])(); ((MyDelegate2) DelegateList[i])(); } } } }

Lead-in
This sample code shows how to create and invoke multicast delegates, and how to iterate through an invocation list to invoke specific delegates.

The following sample code shows:


!" !" !"

How to create multicast delegate objects. How to write code to invoke delegates Combine and Remove methods. How to write code to iterate through an invocation list invoking all delegates, except those delegates whose target is a specific object.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events


using System; public delegate void MyDelegate2(); public class Foo { public void Bar() { Console.WriteLine("Bar invoked"); } } class Application { public static void Main() { Foo aFoo1 = new Foo(); Foo aFoo2 = new Foo(); MyDelegate2 a, b, c, d; a = new MyDelegate2(aFoo1.Bar); b = new MyDelegate2(aFoo2.Bar);

17

// assign to delegate c the composition of delegates a and b c = (MyDelegate2)Delegate.Combine(a , b); // assign to d the result of removing a from c d = (MyDelegate2)Delegate.Remove(c , a); // iterate through c's invocation list // and invoke all delegates except those that target aFoo1 Delegate[] DelegateList = c.GetInvocationList(); for (int i = 0; i < DelegateList.Length; i++) { if (DelegateList[i].Target != aFoo1) { ((MyDelegate2) DelegateList[i])(); } } } }

The preceding code invokes the delegate that invokes object aFoo2s Bar method and outputs:
Bar invoked

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 8: Delegates and Events

C# Language-Specific Syntax
Topic Objective
To present helpful alternative C# syntax.
! !

Lead-in
Delegate types with a void return value in C# cause the compiler to derive the delegate class from the MulticastDelegate class.

C# Delegates That Return Void Are Multicast Delegates In C#, Use the + and - Operators to Add and Remove Invocation List Entries
$

Less verbose than Combine and Remove methods

MyDelegate a, b, c, d; MyDelegate a, b, c, d; a = new MyDelegate(Foo); a = new MyDelegate(Foo); b = new MyDelegate(Bar); b = new MyDelegate(Bar); c = a + b; // Compose two delegates to make another c = a + b; // Compose two delegates to make another d = c - a; // Remove a from the composed delegate d = c - a; // Remove a from the composed delegate a += b; // Add delegate b to a's invocation list a += b; // Add delegate b to a's invocation list a -= b; // Remove delegate b from a's list a -= b; // Remove delegate b from a's list

Delegate types with a void return value in C# cause the compiler to derive the delegate class from the MulticastDelegate class. You can also use these delegates addition operator (+) and the subtraction operator (-) to invoke the Combine and Remove methods for delegate composition and decomposition.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

19

Demonstration: Multicast Delegates


Topic Objective
To demonstrate how to use the + and operators to add and remove methods.

Lead-in
You can add and remove methods from the invocation list of multicast delegates by using the + and operators.

In this demonstration, you will learn how to add and remove methods from the invocation list of multicast delegates by using the + and operators. Delivery Tip
Use Visual Studio .NET to run this code. Set breakpoints or single-step to illustrate the sequence of events.
using System; namespace Multicast_Delegates { delegate void MyDelegate3(string s); class MyClass { public static void Hello(string s) { Console.WriteLine(" Hello, {0}!", s); } public static void Goodbye(string s) { Console.WriteLine(" Goodbye, {0}!", s); } //Code continued following page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 8: Delegates and Events


public static void Main() { MyDelegate3 a, b, c, d; a = new MyDelegate3(MyClass.Hello); b = new MyDelegate3(MyClass.Goodbye); c = a + b; // Compose two delegates to make another d = c - a; // Remove a from c to make another Console.WriteLine("Invoking a("A"); Console.WriteLine("Invoking b("B"); Console.WriteLine("Invoking c("C"); Console.WriteLine("Invoking d("D"); delegate a:"); delegate b:"); delegate c:"); delegate d:");

Console.WriteLine("Adding b to a and invoking:"); a += b; // Add the b delegate to a a("E"); Console.WriteLine("Removing b from a and invoking:"); a -= b; // Remove the b delegate from a a("F"); } } }

This code generates the following output:


Invoking delegate Hello, A! Invoking delegate Goodbye, B! Invoking delegate Hello, C! Goodbye, C! Invoking delegate Goodbye, D! Adding b to a and Hello, E! Goodbye, E! Removing b from a Hello, F! a: b: c:

d: invoking:

and invoking:

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

21

Delegate Details
Topic Objective
To show how a delegate declaration is handled by the compiler.
!

Lead-in
When delegate declarations are compiled, the compiler generates a new class that derives from System.Delegate.

A Delegate Declaration Causes the Compiler to Generate a New Class

// delegate void MyDelegate3(string val); // delegate void MyDelegate3(string val); class MyDelegate3 : System.MulticastDelegate { class MyDelegate3 : System.MulticastDelegate { public MyDelegate3(object obj, methodref mref) public MyDelegate3(object obj, methodref mref) : base (obj, mref) { //... : base (obj, mref) { //... } } public void virtual Invoke(string val) { //... public void virtual Invoke(string val) { //... } } }; };

As previously noted in this module, when delegate declarations are compiled, the compiler, in effect, generates a new class that derives from System.Delegate. The new delegate class has two members: a constructor and an Invoke method. The following class declaration resembles what the compiler actually does:
// delegate void MyDelegate3(string val);

For Your Information


There is no actual type named methodref, but having an instance of a type that encapsulates a reference to a class method resembles what the compiler actually does.

class MyDelegate3 : System.MulticastDelegate { public MyDelegate3(object obj, methodref mref) : base (obj, mref) {//... } public void virtual Invoke(string val) {//... } }

The first member is a constructor: its first parameter is the delegates target object, and its second parameter is a reference to a method. When a delegate refers to a static method, the target object is null. The Invoke method for the class MyDelegate3 indicates that delegate instances of this class encapsulate methods that have a void return and a single string parameter. When a delegate is invoked, the Invoke method is called with the specified parameters.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 8: Delegates and Events

# Events
Topic Objective
To provide an overview of the topics in this section.
! ! ! !

Lead-in
An event is a way for a class to notify clients of that class of a change in an object.

Declaring an Event Connecting to an Event Raising an Event .NET Framework Guidelines

An event is a way for a class to notify clients of that class when some interesting thing happens to an object. The most familiar use for events is in graphical user interfaces. Typically the classes that represent controls in the graphical user interface have events that are notified when a user manipulates the control, as when a user clicks a button. However, the use of events is not limited to graphical user interfaces. Events also allow an object to signal state changes that may be useful to clients of that object. Events are an important building block for creating classes that can be reused in many different programs. Delegates are particularly suited for event handling.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

23

Declaring an Event
Topic Objective
To explain how to declare events.
! !

Declare the Delegate Type for the Event Declare the Event
$

Lead-in
To declare an event inside a class, you first must declare a delegate type for the event.

Like the field of delegate type preceded by an event keyword

// MouseClicked delegate declared // MouseClicked delegate declared public delegate void MouseClickedEventHandler(); public delegate void MouseClickedEventHandler(); public class Mouse public class Mouse { { // MouseClicked event declared // MouseClicked event declared public static event MouseClickedEventHandler public static event MouseClickedEventHandler MouseClickedHandler; MouseClickedHandler; //... //... } }

To declare an event inside a class, you first must declare a delegate type for the event. The delegate type defines the set of arguments that are passed to the method that handles the event. Multiple events can share a delegate type, so you need only declare a delegate type for an event if no suitable delegate type has already been declared. For example, in the case of a MouseClicked event in which the method that handles the event takes no arguments and returns void, the delegate is declared as follows:
public delegate void MouseClickedEventHandler();

Next, the event itself is declared. You declare an event as you would declare a field of delegate type, except that the keyword event follows the modifiers and precedes the delegate type. Events usually are declared public, but any accessibility modifier is allowed. The following code declares a class Mouse with an event named MouseClickedHandler:
public class Mouse { public static event MouseClickedEventHandler MouseClickedHandler; //... }

When you declare an event, the compiler generates a private field that references the end of a delegate invocation list. In the preceding example, a private field named MouseClickedHandler, which refers to delegates of type MouseClickedEventHandler, is created.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 8: Delegates and Events

The compiler also generates two public methods for clients to call to compose and remove their delegate objects. In the preceding example, these public methods would be named add_MouseClickedHandler and remove_MouseClickedHandler. You can call these methods in C# by using the += and -= operators. Because client access to the delegate invocation list is restricted to these methods, the use of the event keyword not only makes the implementation of events easier, it also prevents clients from accessing or raising the delegates of other clients.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

25

Connecting to an Event
Topic Objective
To describe how to connect to and disconnect from an event.
! !

Connect by Combining Delegates Disconnect by Removing Delegates

Lead-in
From outside the class that declared it, an event looks like a field, but access to that field is restricted.

// Clients method to handle the MouseClick event // Clients method to handle the MouseClick event private void MouseClicked() { //... private void MouseClicked() { //... } } //... //... // Client code to connect to MouseClicked event // Client code to connect to MouseClicked event Mouse.MouseClickedHandler += new Mouse.MouseClickedHandler += new MouseClickedEventHandler(MouseClicked); MouseClickedEventHandler(MouseClicked); // Client code to break connection to MouseClick event // Client code to break connection to MouseClick event Mouse.MouseClickedHandler -= new Mouse.MouseClickedHandler -= new MouseClickedEventHandler(MouseClicked); MouseClickedEventHandler(MouseClicked);

From outside the class that declared it, an event looks like a field, but access to that field is restricted. You can only add a delegate to an event or remove a delegate from an event. In C#, you add and remove delegates by using the += and -= operators. To begin receiving event invocations, client code first creates a delegate of the event type that refers to the method that should be invoked from the event. Then, the client code uses the + and operators to compose that delegate with any other delegates to which the event might be connected. When the client code is finished receiving event invocations, it removes its delegate from the event by using the -= operator. The following example shows how to connect to and disconnect from a MouseClicked event:
public class aClient { // aClient's method to handle the MouseClick event private void MouseClicked() { //... } //... // code to connect to Mouse class' MouseClicked event Mouse.MouseClickedHandler += new MouseClickedEventHandler(MouseClicked); // code to break the connection to MouseClicked event Mouse.MouseClickedHandler -= new MouseClickedEventHandler(MouseClicked); //... }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 8: Delegates and Events

Raising an Event
Topic Objective
To show when and how to raise an event.
!

Lead-in
Once a class has declared an event, it can treat that event like a field of the indicated delegate type.

Check Whether Any Clients Have Connected to This Event


$

If the event field is null, there are no clients

Raise the Event by Invoking the Events Delegate

if (MouseClickedHandler != null) if (MouseClickedHandler != null) MouseClickedHandler(); MouseClickedHandler();

After a class has declared an event, it can treat that event like a field of the indicated delegate type. The field will be null if no client has connected a delegate to the event, or it will refer to a delegate that should be called when the event is raised. Therefore, when an event is raised, you should first check for null and then call the event. You can only raise an event from within the class that declared the event.
if (MouseClickedHandler != null) MouseClickedHandler();

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

27

.NET Framework Guidelines


Topic Objective
To introduce .NET Framework guidelines for delegates and events.
! ! ! ! !

Name Events with a Verb and Use Pascal Casing Use "Raise" for Events, Instead of "Fire" Event Argument Classes Extend System.EventArgs Event Delegates Return Void and Have Two Arguments Use a Protected Virtual Method to Raise Each Event

Lead-in
You should follow .NET Framework guidelines if you intend to use your component in the .NET Framework.

public class SwitchFlippedEventArgs : EventArgs { //... public class SwitchFlippedEventArgs : EventArgs { //... } } public delegate void SwitchFlippedEventHandler( public delegate void SwitchFlippedEventHandler( object sender, SwitchFlippedEventArgs e); object sender, SwitchFlippedEventArgs e); public event SwitchFlippedEventHandler SwitchFlippedHandler; public event SwitchFlippedEventHandler SwitchFlippedHandler;

The .NET Framework includes guidelines on the delegate types that should be used for events. If you are creating a component for use with the .NET Framework, you should follow these guidelines: For Your Information
The Pascal Casing convention capitalizes the first character of each word. For example: BackColor The camelCasing convention capitalizes the first character of each word, except the first word. For example: backColor
!"

Consider naming events with a verb and use Pascal Casing. The Pascal Casing convention capitalizes the first character of each word. For example: SwitchFlipped Prefix pre- and post-event names by using the present and past tense. Do not use the BeforeXxx\AfterXxx pattern. For example, a close event that could be canceled should have a Closing and Closed event. An event that indicates that a control has been added should be declared as follows:
public event ControlEventHandler ControlAdded;

!"

Use raise for events, rather than fired. When referring to events in documentation, use an event was raised, instead of an event was fired.

!"

For the events delegate declaration, use a return type of void, two parameters, an object source parameter named sender, and an e parameter that encapsulates any additional information about the event. Delegates should return void and have two arguments: the object that raised the event and the event data object. Use names ending in EventHandler for the events delegate, as in the following example:
public delegate void SwitchFlippedEventHandler( object sender, SwitchFlippedEventArgs e);

The sender parameter represents the object that raised the event and called the delegate. The sender parameter is always a parameter of type object, even if you can employ a more specific type. The state associated with the event is encapsulated in an instance of an event class named e. Use an appropriate and specific event class for its type.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

28

Module 8: Delegates and Events


!"

When necessary, event classes extend System.EventArgs and end in EventArgs, as in the following example:
public class SwitchFlippedEventArgs : EventArgs {//... }

For events that do not use any additional information, the .NET Framework has already defined an appropriate delegate type: EventHandler, whose argument is of the event base type EventArgs, as in the following example:
public delegate void EventHandler( object sender, EventArgs e);
!"

Create an invoking method for the event. Because events can only be raised from within the class that declared them, derived classes cannot directly raise events that are declared within the base class. Often it is appropriate to let the derived class raise the event. You can do this by creating a protected invoking method for the event. By calling this invoking method, derived classes can raise the event.
protected virtual void OnSwitchFlipped (//...) { //... }

For even more flexibility, you can declare the invoking method as virtual, which allows the derived class to override it. This approach allows the derived class to intercept the events that the base class is raising, possibly doing its own processing of them. For this reason, the .NET Framework guideline suggests that you create an invoking method to raise an event that is a protected (family) virtual method. However, if the class is sealed, the method should not be virtual because the class cannot be derived from. Name the method OnEventName where EventName is the event being raised.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

29

The switch and light delegate scenarios in the preceding topics help to put these guidelines in context. When a switch is flipped, the switch object raises a SwitchFlipped event for connected light objects. In this case, the additional SwitchFlipped event data indicates whether the switch is in the up or down position:
public enum SwitchPosition {Up, Down}; // class to encapsulate switch data public class SwitchFlippedEventArgs : EventArgs { private SwitchPosition position; public SwitchFlippedEventArgs(SwitchPosition position) this.position = position; } public SwitchPosition Position { get { return position; } } } //delegate declaration public delegate void SwitchFlippedEventHandler( object sender, SwitchFlippedEventArgs e); public class Switch { //event declaration public event SwitchFlippedEventHandler SwitchFlippedHandler; // ProcessSwitchFlippedUp called when switch flipped up // to create an event argument object and raise the event public void ProcessSwitchFlippedUp() { SwitchFlippedEventArgs e = new SwitchFlippedEventArgs(SwitchPosition.Up); OnSwitchFlipped(e); } // ProcessSwitchFlippedDown when switch flipped down public void ProcessSwitchFlippedDown() { SwitchFlippedEventArgs e = new SwitchFlippedEventArgs(SwitchPosition.Down); OnSwitchFlipped(e); } protected virtual void OnSwitchFlipped ( SwitchFlippedEventArgs e) { if (SwitchFlippedHandler != null) { // call the delegate if non-null SwitchFlippedHandler(this, e); } } //... } {

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

30

Module 8: Delegates and Events

When to Use Delegates, Events, and Interfaces


Topic Objective
To explain when to use delegates, events, and interfaces.
!

Use a Delegate If:


$ $ $

You basically want a C-style function pointer You want single callback invocation The callback should be registered in the call or at construction time, not through methods Client signs up for the callback function through methods More than one object will care The callback function entails complex behavior, such as multiple methods

Lead-in
Delegates, interfaces, and events all provide callback functionality, but each has specific usage characteristics that make it better suited to particular situations.

Use Events If:


$ $

Use an Interface If:


$

Delegates, interfaces, and events all provide callback functionality, but each has specific usage characteristics that make it better suited to particular situations. Use a delegate if:
!" !" !"

You basically want a C-style function pointer. You want single callback invocation. You want the callback function registered in the call or at construction time, not through a separate add method.

Use events if:


!"

Client code signs up for the callback prior to the occurrence of events, typically through a separate add method. More than one client object will care.

!"

Use an interface if: The callback function entails complex behavior, as when more than one callback method is invoked.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

31

Lab 8: Creating a Simple Chat Server


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will create use delegates and events with a simple chat server application.

Objectives
After completing this lab, you will be able to:
!" !"

Write code that uses the delegate class to create type-safe callbacks. Write code that uses the event keyword to simplify and improve the implementation of a class that raises events. Write event code that conforms to the .NET Framework guidelines.

!"

Lab Setup
Only solution files are associated with this lab. The solution files for this lab are in the folder <install folder>\Labs\Lab08\Solution.

Scenario
In this lab, you will create a simple chat-style server to which multiple clients can connect. When one client sends a string message to the server, the server forwards the message to all registered clients that have not been specifically excluded. You should note that a real chat application would be based on a more scalable and flexible design to connect client and servers, such as a publish-andsubscribe design.

Estimated time to complete this lab: 70 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

32

Module 8: Delegates and Events

Exercise 1 Creating a Simple Chat Server Using Delegates


In this exercise, you will implement a simple chat server and clients by using delegates.

Scenario
Each client will register a delegate with the server. Then, when a client sends a message to the server, the server forwards the message to all specified clients. This implementation uses delegates as a callback mechanism.

!" create a Visual Studio .NET project To


Open Visual Studio .NET and create a new C# Console Application project named chat1 in <install folder>\Labs\Lab08.

!" create the chat server class To


1. Create the chat server class and name it DChatServer. 2. Declare within the DChatServer class a delegate that will be used to invoke the callback function in the client when a chat message arrives. a. Name the delegate OnMsgArrived. b. Declare this delegate public and reflect the callback functions signature. The callbacks signature is a void return value with a single argument of type string. 3. Define a field to store the connected clients delegates by performing the following steps. a. Name the field onMsgArrived. b. Make the field a private static reference to the type of the delegate, OnMsgArrived. 4. Define the method that will be called by a client to connect that client to the server by performing the following steps. a. Name the method ClientConnect. b. Declare the method public static void. c. Include an argument of type OnMsgArrived. d. Create the methods implementation by using the delegates Combine method to add this new delegate to the delegate stored in the onMsgArrived invocation list. As an alternative to the Combine method, you can use the += operator. 5. Define a method that will be called by a client to disconnect that client from the server by performing the following steps. a. Name the method ClientDisconnect. b. Declare the method public static void. c. Declare the method so that it has the same signature as ClientConnect. d. Create the methods implementation by using the delegates Remove method to remove the delegate from the onMsgArrived invocation list. As an alternative to the Remove method, you can use the -= operator.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

33

6. Define a method that will send a specified message to the connected clients, with the possible exception of one client, by performing the following steps. a. Name the method SendMsg. b. Declare the method public static void. c. Declare the method so that it takes two arguments: a string argument for the message and an object argument for the excluded client. d. Create the methods implementation. i. If the excluded client argument is null, invoke the multicast delegate to send the message to all the clients. ii. If the excluded client argument is not null, iterate through the onMsgArrived delegates invocation list and invoke only those delegates that do not match the excluded client argument.

!" create the chat client class To


1. Create the chat client class and name it DChatClient. 2. Implement within the DChatClient class a callback method that the server will invoke by a delegate when the server receives a chat message. a. Name the method onMsgArrived. b. Declare the method private void. c. Declare the method so that it takes a single string argument. d. Create the methods implementation so that it prints the name of the client along with the string argument to the console. 3. Add a constructor that will receive the name of the client as a parameter and connect the client with the server. a. Declare the constructor so that it takes a string argument that represents the clients name. b. Create the constructors implementation. i. Store the clients name in a private field. ii. Connect the client to the server by calling the servers ClientConnect method. The calls argument should be an instance of the delegate type DChatServer.OnMsgArrived that was instantiated with the clients callback method: onMsgArrived.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

34

Module 8: Delegates and Events

!" create the programs main entry point To


1. Name the class that contains the programs standard Main entry point, Application. Typically a Visual Studio .NET project creates the class with the Main entry point for you. You may only need to rename this class. 2. Write to the console a line of text to indicate that the program is starting. 3. Instantiate three DChatClient objects, passing the client names 1, 2, and 3 to the constructor. 4. Send a message to the server by invoking the static method SendMsg of the DChatServer. The message should be sent to all clients. 5. Send a second message to all clients, except Client 2. 6. Write to the console a line of text to indicate that the program is finished.

!" compile and test the program To


Build the program and run it. The output should resemble the following:
Demo start: Delegate Chat Server. Msg arrived (Client 1): Hi to all Msg arrived (Client 2): Hi to all Msg arrived (Client 3): Hi to all Msg arrived (Client 1): Hi to all Msg arrived (Client 3): Hi to all Demo stop: Delegate Chat Server. clients clients clients clients except client 2 clients except client 2

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

35

Exercise 2 Creating a Simple Chat Server Using Events


In this exercise, you will implement a simple chat server and clients by using events and delegates. This implementation uses the event keyword, which hides some of the low-level code details associated with delegates and prevents clients from accessing or invoking the delegates of other clients.

Scenario
Each client will connect with the servers on message arrived event. Then, when one client sends a string message to the server, the server forwards the message to all specified connected clients.

!" access the chat1 Visual Studio .NET project To


Open Visual Studio .NET and open the project named chat1, which you created in Exercise 1, in <install folder>\Labs\Lab08. Open the previously created C# source file and perform the following procedures.

!" create the event-based chat server class To


1. Create a new chat server class and name it EChatServer. 2. Declare within the EChatServer class a delegate that will be used to invoke the callback function in the client when a chat message arrives. a. Name the delegate OnMsgArrived. b. This delegate should be declared public and reflect the callback functions signature. The callbacks signature is a void return value with a single argument of type string. 3. Declare an event for the OnMsgArrived delegate type. a. Name the event onMsgArrived. b. Declare the event public static. 4. Define a method that will send a specified message to the connected clients, with the possible exception of one client. a. Name the method SendMsg. b. Declare the method public static void. c. Declare the method so that it takes two arguments: a string argument for the message and an object argument for the excluded client. d. Create the methods implementation. i. If the excluded client argument is null, invoke the multicast delegate to send the message to all of the clients. ii. If the excluded client argument is not null, iterate through the onMsgArrived delegates invocation list and invoke only those delegates that do not match the excluded client argument.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

36

Module 8: Delegates and Events

!" create the event-based chat client class To


1. Create a new chat client class and name it EChatClient. 2. Implement within the EChatClient class a callback method that the server will invoke by a delegate when the server receives a chat message. a. Name the method onMsgArrived. b. Declare the method private void. c. Declare the method so that it takes a single string argument. d. Implement the method so that it prints the name of the client, together with the string argument, to the console. 3. Add a constructor that will receive the name of the client as a parameter and connect the client with the server. a. Declare the constructor so that it takes a string argument that represents the clients name. b. Create the constructors implementation. i. Store the clients name in a private field. ii. Connect the client to the server by using the += operator to add a new delegate instance to the EChatServers event. The += operators right operand should be an instance of the delegate type EChatServer.OnMsgArrived that was instantiated with the clients callback method, onMsgArrived.

!" extend the programs main entry point by performing the following To
procedures 1. Write to the console a line of text to indicate that the event chat portion of the program is starting. 2. Instantiate three EChatClient objects, passing the client names 1, 2, and 3 to the constructor. 3. Send a message to the server by invoking the static method SendMsg of the EchatServer. You should send the message to all clients. 4. Send a second message to all clients except client 2. 5. Write to the console a line of text to indicate that event chat is finished.

!" compile and test the program To


Build the program and run it. The output should resemble the following:
... Demo start: Event Chat Server. Msg arrived (Client 1): Hi to all Msg arrived (Client 2): Hi to all Msg arrived (Client 3): Hi to all Msg arrived (Client 1): Hi to all Msg arrived (Client 3): Hi to all Demo stop: Event Chat Server.

clients clients clients clients except client 2 clients except client 2

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

37

Exercise 3 Conforming to the .NET Framework Guidelines


In this exercise, you will implement the simple chat program with events that conform to the .NET Framework guidelines. Although the C# language allows events to use any delegate type, the .NET Framework has stricter guidelines on the delegate types that should be used for events. If you intend for your component to be used with the .NET Framework, follow these guidelines.

Scenario
As in Exercise 2, each client connects with the servers event. Then, when one client sends a string message to the server, the server forwards the message to all specified clients. In this exercise, the delegate type will conform to the .NET Framework guidelines. The delegate type will take two parameters, an object source parameter, which indicates the source of the event, and an e parameter, which encapsulates information about the event and, in this case, includes the string message that generated the event. In this exercise, you will also instantiate the chat server as an object. Instantiating the chat server will allow you to invoke the connected clients delegates with a non-null object source parameter.

!" create the event class that will encapsulate the events state To
1. Open Visual Studio .NET and open the project named chat1, which you created in Exercise 1, in location <install folder>\Labs\Lab08. Open the previously created C# source file and add the following code. 2. Create a new public class named MsgArrivedEventArgs that inherits from EventArgs. 3. Declare within MsgArrivedEventArgs a private readonly field of type string named message. 4. Declare a public constructor that takes a single string argument and stores it in the field named message. 5. Add a property named Message that returns the value of message.

!" create the guidelines-based chat server class To


1. Create a new chat server class and name it GChatServer. 2. Declare within the GChatServer class a delegate that will be used to invoke the function in the client when a chat message arrives. a. Name the delegate MsgArrivedEventHandler. b. This delegate should be declared public and reflect the guidelines signature of a void return value and two arguments of type object and MsgArrivedEventArgs. 3. Declare an event for the MsgArrivedEventHandler delegate type. a. Name the event MsgArrivedHandler. b. Make the event public. Do not make it static.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

38

Module 8: Delegates and Events

4. Define a method that will send a specified message to the connected clients, with the possible exception of one client. a. Name the method SendMsg. b. Declare the method public void. c. Declare the method so that it takes two arguments: a string argument for the message and an object argument for the excluded client. d. Create the methods implementation. i. Instantiate an instance of the event class MsgArrivedEventArgs with the message string. ii. Invoke the OnMsgArrived method, which is implemented in the next step. 5. Define the OnEvent method to raise the event. a. Name the method OnMsgArrived. In accordance with the .NET Framework guidelines declare the method protected virtual void with two arguments of type MsgArrivedEventArgs and object. b. Create the methods implementation. i. If the events field contains a non-null delegate list and the excluded client argument is null, invoke the multicast delegate with the appropriate arguments. ii. If the events field contains a non-null delegate list and the excluded client argument is not null, iterate through the MsgArrivedHandler delegates invocation list and invoke only those delegates that do not match the excluded client argument. iii. If the events field contains a null delegate list, do nothing.

!" create the guidelines-based chat client class To


1. Create a new chat client class and name it GChatClient. 2. Implement within the GChatClient class a callback method that the server will invoke by a delegate when the server receives a chat message. a. Name the method onMsgArrived. b. Declare the method private void. c. Declare the method so that it takes an object and MsgArrivedEventArgs arguments. d. Create the methods implementation so that it prints the name of the client, the Message property of MsgArrivedEventArgs, and the server object as a string to the console.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

39

3. Add a constructor that will receive the name of the client and a reference to the server, and will connect the client with the server. a. Declare the constructor so that it takes a string argument that represents the clients name and a GChatServer argument that specifies the server object. b. Create the constructors implementation. i. Store the clients name in a private field. ii. Store the servers reference in a private field. iii. Connect the client to the server by using the += operator to add a new delegate instance to the GChatServers event. The += operators right operand should be an instance of the delegate type GChatServer.MsgArrivedEventHandler that was instantiated with the clients callback method: onMsgArrived.

!" extend the programs main entry point by performing the following To
procedures 1. Create an instance of the GChatServer object. 2. Write to the console a line of text to indicate that the guidelines-based chat server class portion of the program is starting. 3. Instantiate three GChatClient objects, passing the client names 1, 2, and 3 to the constructor. 4. Send a message to the server by invoking the SendMsg method of GChatServer. The message should be sent to all clients. 5. Send a second message to all clients except client 2. 6. Write to the console a line of text to indicate that the guidelines-based event chat is finished.

!" compile and test the program To


Build the program and run it. The guidelines-based event chat output should resemble the following:
... Demo start: Guidelines Based Event Chat Server. Server: GChatServer Msg arrived (Client 1): Hi to all clients Server: GChatServer Msg arrived (Client 2): Hi to all clients Server: GChatServer Msg arrived (Client 3): Hi to all clients Server: GChatServer Msg arrived (Client 1): Hi to all clients except client 2 Server: GChatServer Msg arrived (Client 3): Hi to all clients except client 2 Server: GChatServer Demo stop: Guidelines Based Event Chat Server.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

40

Module 8: Delegates and Events

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! ! ! !

Delegates Multicast Delegates Events When to Use Delegates, Events, and Interfaces

Lead-in
The review questions cover some of the key concepts taught in this module.

1. Write the code to declare a delegate that is named ProcessOrderCallback for the following method:
static public bool ProcessOrder(int Quantity, string Item) { //... }

public delegate bool ProcessOrderCallback (int Quantity, string Item);

2. Write the code to call the following EnterOrder method, instantiating and passing an instance of the ProcessOrderCallback delegate that refers to a public static method that is named Foo in the public class Bar.
static public void EnterOrder( ProcessOrderCallback processOrderCallback) { //... };

EnterOrder( new ProcessOrderCallback(Bar.Foo) );

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 8: Delegates and Events

41

3. Write the body of the static method EnterOrder that takes as an argument an instance of the delegate that is declared in question 1. EnterOrder outputs to the console strings to prompt for an item name and quantity and reads in the users input. EnterOrder should invoke the callback delegate with this information. static public void EnterOrder( ProcessOrderCallback processOrderCallback) { Console.WriteLine("Enter Item Name:"); string name = Console.ReadLine(); Console.WriteLine("Enter Item Quanity:"); int quantity = Int32.Parse( Console.ReadLine() ); processOrderCallback(quantity, name); }

4. Given the following declarations, write the code to add delegate b to as invocation list.
delegate void MyDelegate(); MyDelegate a, b; a = new MyDelegate(Bar1.Foo1); b = new MyDelegate(Bar2.Foo2);

a += b;

5. Use the event keyword to write the code to declare a public static event for a delegate type ProcessOrderEventHandler. public static event ProcessOrderEventHandler processOrderHandler;

6. Describe when you should use a delegate and when you should use an event. Use a delegate when: You want a C-style function pointer. You want single callback invocation. You want the callback function to be registered in the call or at construction time, not in a separate add method. Use an event when: Client code signs up for the callback prior to the occurrence of events, typically through a separate add method. More than one client object will be affected.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

THIS PAGE INTENTIONALLY LEFT BLANK

Module 9: Memory and Resource Management


Contents Overview Memory Management Basics Multimedia: Simple Garbage Collection Non-Memory Resource Management Implicit Resource Management Multimedia: Garbage Collection Explicit Resource Management Optimizing Garbage Collection Lab 9: Memory and Resource Management Review 1 2 10 12 13 19 26 36 49 55

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

iii

Instructor Notes Module 9


Presentation: 125 Minutes Lab: 60 Minutes After completing this module, students will be able to:
!" !"

Describe how garbage collection manages object memory. Implicitly manage non-memory resources by using a destructors finalize code. Explicitly manage non-memory resources by using client-controlled deterministic release of resources. Write code by using the temporary resource usage design pattern. Programmatically control the behavior of the garbage collection. Describe advanced garbage collection features.

!"

!" !" !"

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_09.ppt

Preparation Tasks
To prepare for this module, you should:
!" !" !" !"

Read all of the materials for this module. Review the animation. Practice the demonstrations. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 9: Memory and Resource Management

Demonstrations
This section provides demonstration procedures that will not fit in the margin notes or are not appropriate for the student notes. The code for each of the following demonstrations is contained in one project and is located in <install folder>\Democode\Mod09\Demo09\GARBAGE COLLECTION. In addition, the code for the individual demonstrations is provided in the student notes. Use the debugger to step through the code while you point out features and ask students what they think will happen next.

Finalization
In this demonstration, you will show students how garbage collection handles finalization and resurrection. In this demonstration, run the Introduction and Resurrection methods.

The IDisposable Interface


In this demonstration, you will show students how to perform explicit resource management by using the IDisposable interface. In this demonstration, run the DisposeDemo method.

Weak References
In this demonstration, you will show students how garbage collection handles weak references. In this demonstration, run the WeakRefDemo method.

Generations
In this demonstration, you will show students how garbage collection handles generations. In this demonstration, run the GenerationDemo method.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

Module Strategy
Use the following strategy to present this module:
!"

Memory Management Basics Students in your classes will probably use different approaches to memory management. Begin with a brief review of different memory management techniques that you or the students may have learned from experience. Because students will need to adapt their programming practices to the automatic memory management that is provided by the common language runtime, it is important to mention other memory management techniques. Compare and contrast manual memory management with the automatic memory management that is provided by the common language runtime. Outline the simple garbage process without the finalization details and use the Simple Garbage Collection animation to help the students understand the concept of the garbage collection process more easily. Instructions for running the animations in this module are included in Instructor Margin Notes.

!"

Non-Memory Resource Management This topic is an introduction to handling non-memory resources implicitly and explicitly. Tell students that the next two sections cover these areas in detail. You should not spend much time on this slide.

!"

Implicit Resource Management Introduce the finalization phase of the garbage collection process. Emphasize that in C#, a destructor must be used for the finalization code. The second animation, Garbage Collection, is more complex than the first. It shows the garbage collection process with the finalization details. Spend time discussing the drawbacks that are associated with finalization and what to do if finalization is required. Show students how to deal with an object that has been resurrected. Use the Finalization demonstration to highlight how garbage collection deals with finalization and resurrection.

!"

Explicit Resource Management Show students how to perform explicit resource management by using the IDisposable interface and Dispose method. Discuss the temporary resource usage design pattern as an example of how to allocate resources for temporary use.

!"

Optimizing Garbage Collection Use the demonstrations that are provided to show how to optimize garbage collection through weak references and generations. In addition to discussing the programmatic optimizations that can be made to the garbage collection process, briefly mention the use of performance counters to monitor memory activity and the use of a multiprocessor system to scale applications where there are garbage collection bottlenecks.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! ! ! ! !

Memory Management Basics Non-Memory Resource Management Implicit Resource Management Explicit Resource Management Optimizing Garbage Collection

Lead-in
Objects in the Microsoft .NET Framework use memory resources and may use other resources, such as file handles. For software to run properly, these resources must be well managed.

Objects in the Microsoft .NET Framework use memory resources and may use other resources, such as file handles. For software to run properly, these resources must be well managed. In other words, they must be properly allocated and released. After completing this module, you will be able to:
!" !"

Describe how garbage collection manages object memory. Implicitly manage non-memory resources by using a destructors finalize code. Explicitly manage non-memory resources by using client-controlled deterministic release of resources. Write code by using the temporary resource usage design pattern. Programmatically control the behavior of the garbage collection. Describe advanced garbage collection features.

!"

!" !" !"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

# Memory Management Basics


Topic Objective
To provide an overview of the section topics.
! ! ! !

Lead-in
A major feature of the .NET Framework common language runtime is that the runtime automatically handles the allocation and release of an objects memory resources.

Developer Backgrounds Manual vs. Automatic Memory Management Memory Management of .NET Framework Types Simple Garbage Collection

A major feature of the .NET Framework common language runtime is that the runtime automatically handles the allocation and release of an objects memory resources. In most cases, automatic memory management enhances code quality and developer productivity without negatively impacting expressiveness or performance. Understanding how the .NET Framework facilitates resource management is essential for writing correct and efficient code. In this section, you will learn about memory management in the .NET Framework, including simple garbage collection.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

Developer Backgrounds
Topic Objective
To discuss various developer backgrounds with regard to memory management.
!

COM
$

Lead-in
Your experience with memory management will vary depending upon your development background.
!

Manually implement reference counting and handle circular references Manually use the new operator and delete operator Accustomed to automatic memory management

C++
$

Visual Basic
$

Your experience with memory management will vary depending upon your development background. In certain situations, you will need to adapt your programming practices to the automatic memory management that is provided by the common language runtime.

COM Developers
COM developers are accustomed to implementing reference counting as a manual memory management technique. Each time an object is referenced, a counter is incremented. When a reference to an object goes out of scope, the counter is decremented. When an objects reference count reaches zero, the object is terminated and its memory is freed. The reference counting scheme is the source of many bugs. If the reference counting rules are not followed precisely, objects may be freed prematurely or unreferenced objects may accumulate in memory. Circular references are also a common source of bugs. A circular reference occurs when a child object has a reference to a parent object, and the parent object has a reference to the child object. Circular references prevent either object from being released or destroyed. The only solution is for the parent and child objects to agree on a fixed pattern of usage and destruction, such as where the parent always deletes the child first. When you develop applications in a managed language, the runtimes garbage collector eliminates the need for reference counting and, as a result, the bugs that can arise from this manual memory management scheme.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

C++ Developers
C++ developers are accustomed to the tasks that are related to manual memory management. In C++, when you allocate memory for an object by using the new operator, you must release the objects memory by using the delete operator. This can lead to errors such as forgetting to release an object and causing a memory leak, or attempting to access memory for an object that has already been released. When you develop applications by using the Managed Extensions for C++, or another managed language, you do not have to use the delete operator to release an object. The garbage collector does this for you automatically when the object is no longer being used by the application. C++ developers may be accustomed to avoiding the use of short-term objects because of the associated cost of manually managing the memory for these objects. For managed short-term objects that are created and then go out of scope between collections, the cost of allocating and releasing memory is extremely low. In the .NET Framework, the garbage collector is actually optimized to manage objects with short lifetimes. When you develop managed applications, it is appropriate to use short-term objects in situations where they simplify your code.

Visual Basic Developers


Microsoft Visual Basic developers are accustomed to automatic memory management. If you are a Visual Basic developer, the programming practices with which you are familiar apply to the majority of the managed objects that you create in the .NET Framework. However, you should take special note of the suggested design pattern for a Dispose method to use when you create or use objects that encapsulate unmanaged resources.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

Manual vs. Automatic Memory Management


Topic Objective
To introduce the advantages of automatic memory management in the .NET Framework.
!

Manual Memory Management


$

Lead-in
Manual memory management requires that you manage the allocation and deallocation of blocks of memory.
!

Programmer manages memory Failure to release memory Invalid references to freed memory Eases programming task Eliminates a potential source of bugs

Common Problems
$ $

.NET Runtime Provides Automatic Memory Management


$ $

Manual memory management requires that you manage the allocation and deallocation of blocks of memory. The NET Framework common language runtime provides automatic memory management so that you are freed from this time-consuming and difficult task.

Manual Memory Management


The following table provides examples of manual memory management in different programming languages, C and C++, and in COM.
Language or environment C C++ COM Example of manual memory management malloc and free functions new and delete operators AddRef and Release reference counting methods

Automatic Memory Management in the .NET Framework


The .NET Framework common language runtime automatically handles managed object memory and manages references to these objects, releasing managed objects when they are no longer being used. This automatic memory management eliminates the possibility of programming errors that can cause memory leaks and the use of memory that has already been freed. With automatic memory management, you no longer have to deal with complex bugs that are associated with reference counting, circular reference leaks, or dangling references.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

Memory Management of .NET Framework Types


Topic Objective
To explain how a values type affects how the value is managed in memory.
!

Instances of Value Types Use Stack Memory


$

Lead-in
In .the NET Framework, all values have a type, which may be a value type or a reference type.
!

Allocation and deallocation are automatic and safe

Managed Objects Are Reference Types and Use Heap Memory


$ $

Created by calls to the new operator Freed by garbage collection

In the .NET Framework, all values have a type, which may be a value type or a reference type. Each values type affects how that value is managed in memory.

Instances of Value Types


Instances of value types are stored in memory that is allocated on the stack. Allocation and deallocation of memory occur automatically as follows:
!"

Allocation Memory for an instance of a value type is created when the activation record for its scope is pushed onto the stack.

!"

Deallocation Memory is deallocated when the scopes activation record, which contains the value type instance, is popped from the stack.

Value types are always accessed directly. You cannot create a reference to a value type, and therefore you cannot refer to a value instance that has been deallocated. As a result, there is no danger of creating a dangling reference to a value type.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

Instances of Reference Types


Managed objects are reference types, which you create by calls to the new operator. The memory of these objects is allocated in the common language runtime managed heap. You can access reference types only through a reference to that storage. The use of references enables garbage collection to track outstanding references to a particular instance and to free that objects heap memory when appropriate. A managed objects heap memory is only released through garbage collection when there are no reachable references to that object. This mechanism ensures that there will be no invalid references to the objects freed memory and thus no dangling references.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

Simple Garbage Collection


Topic Objective
To explain how simple garbage collection works in the .NET Framework.
!

Simple Garbage Collection Algorithm


$ $ $

Lead-in
Garbage collection is triggered when an application creates an object, and there is not enough space left in the heap to provide memory for the object.
!

Wait until managed code threads are in a safe state Build a graph of all reachable objects Move reachable objects to compact heap - Unreachable objects memory is reclaimed Update references to all moved objects

Reference Cycles Are Handled Automatically

Typically, garbage collection is triggered when an application creates an object, and there is not enough space left in the heap to provide memory for the object. Alternatively, you can invoke garbage collection programmatically. This process is discussed in Optimizing Garbage Collection in this module.

The Garbage Collection Algorithm


Whether garbage collection occurs automatically or you invoke it programmatically, the garbage collection algorithm is used to find any objects in the heap whose memory can be reclaimed. Such objects include objects that are no longer being used by the application. If garbage collection can reclaim enough objects to free sufficient memory, memory for the new objects can be allocated. Otherwise, an OutOfMemoryException is thrown. For the sake of simplicity, this topic describes the simple garbage collection process. The finalization phase and optimization details are discussed in Implicit Resource Management in this module.

Simple Garbage Collection Process


Simple garbage collection uses the following process: 1. Waits until other managed threads reach a safe state, for example, suspended. The garbage collection process modifies managed objects and their references. Therefore it must first wait until other managed threads are suspended. 2. Builds a graph of all reachable objects. 3. Compacts the heap by moving reachable objects. By moving reachable objects down in the heap, garbage collection reclaims the space in the heap that was used by unreachable objects. 4. Updates all application references to moved objects.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

Building the Graph of Reachable Objects


Garbage collection accesses the collection of root references that are maintained by the runtime. Each application has a logical collection of root references. The collection contains all of the managed object references from global and static objects and local variables that are currently on the stack and in CPU registers. To build the graph of reachable objects, garbage collection performs the following actions. 1. It adds all of the objects that are referenced by each root reference. 2. It recursively adds objects that are referenced by any added object. Before an object is added to the graph, garbage collection checks to ensure that the object is not already in the graph. This check prevents garbage collection from entering an infinite loop that is caused by circular references. At the end of the process, any object that is not in the reachable object graph is considered unreachable and therefore garbage.

Reference Cycles Handled Automatically


An object is reachable only if there is a path from a root reference to that object. Therefore, reference cycles between unreachable objects will not prevent the objects memory from being released by the garbage collection process. For example, if A references B and B references A, then both objects will be garbage collected when they are no longer reachable from a root reference.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 9: Memory and Resource Management

Multimedia: Simple Garbage Collection


Topic Objective
To illustrate the .NET Framework garbage collection process.

Lead-in
This animation illustrates the .NET Framework common language runtimes garbage collection process.

To launch the animation, click the button in the lower left corner of the slide. To play the animation, click the Simplified Garbage Collection button at the top of the screen, and then click the play button in the lower left corner of the screen.

This animation illustrates the .NET Framework common language runtimes garbage collection process. Note Compiler optimization is disabled in this scenario to prevent an object from becoming eligible for garbage collection earlier than would be expected. Otherwise, the compiler could optimize away assignments to local variables that are never observed by a later read. This optimization could result in an object being subject to garbage collection before its reference is assigned to null.
!"

The common language runtime allocates memory resources for reference type objects in the section of the applications memory that is called the managed heap. When there is insufficient space in the managed heap, the common language runtime executes the garbage collection algorithm to remove objects that are no longer being used by the application.

!"

The steps of the algorithm are as follows: 1. After all other managed threads reach a safe state, for example suspended, garbage collection builds a graph of all of the objects that are reachable from the root references. 2. Before an item is added to the graph, a check is made to ensure that the object is not already in the graph. This check ensures that circular references are handled without garbage collection entering an infinite loop.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

11

3. After all of the root references and added objects have been processed, any objects that are not in the graph are not reachable by the application. The memory for these objects can be reclaimed when the heap is compacted. 4. The remaining objects are moved down in the heap to fill the gaps. 5. The garbage collection process must then update all references to the moved objects.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 9: Memory and Resource Management

Non-Memory Resource Management


Topic Objective
To provide an overview of non-memory resource management, which is discussed in the following topics.
! !

Implicit Resource Management Explicit Resource Management

Lead-in
Managed objects sometimes encapsulate control over resources that are not managed by the runtime.

For Your Information


This topic is an introduction to handling non-memory resources implicitly and explicitly. Tell students that the next two sections cover these areas in detail. You should not spend much time on this slide.

Managed objects sometimes encapsulate control over resources that are not managed by the runtime. Examples of these non-memory resources include window handles, file handles, and database connections. You need implicit and explicit ways to free these resources. Garbage collection provides implicit resource management of an object by calling the objects finalize code. The client of an object provides explicit resource management by calling the Dispose method on the IDisposable interface of the object when the client is finished using the object.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

13

# Implicit Resource Management


Topic Objective
To provide an overview of the section topics.
! ! ! !

Lead-in
The .NET Framework common language runtime provides the means for notifying an object before it is destroyed so that it can clean up and release nonmemory resources.

Finalization Garbage Collection with Finalization Finalization Guidelines Controlling Garbage Collection

The .NET Framework common language runtime provides the means for notifying an object before it is destroyed so that it can clean up and release nonmemory resources. In this section, you will learn how to take advantage of this feature.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 9: Memory and Resource Management

Finalization
Topic Objective
To define and describe finalization in garbage collection.
! ! !

Finalize Code Called by Garbage Collection In C#, the Finalize Code Is Provided by a Destructor Use C# Destructor to Implicitly Close a FileStream

Lead-in
Implicit management of resources ensures that an object can properly clean up its resources at some time in the future when there are no longer any valid references to the object.

class Foo { class Foo { private System.IO.FileStream fs; private System.IO.FileStream fs; //... //... public Foo() { public Foo() { fs = new System.IO.FileStream( fs = new System.IO.FileStream( bar, FileMode.CreateNew); bar, FileMode.CreateNew); } } ~Foo() { fs.Close(); } ~Foo() { fs.Close(); } } }

Implicit management of resources ensures that an object can properly clean up its resources at some time in the future when there are no longer any valid references to the object. If an object provides finalize code in its destructor, the garbage collection process calls this code when there are no longer any valid references to the object. This phase of garbage collection is referred to as finalization. Finalization allows an object to properly cleanup before its memory resources are freed.

Using a Destructor for Finalization


In C#, the Finalize method is no longer directly accessible, and you cannot call or override the Finalize method. You must place code to be executed during finalization inside a C# destructor. The syntax for a C# destructor is the tilde operator (~), followed by the class name and a block of statements that will be executed during finalization. The following example shows the C# destructor syntax for a class named Foo.
~Foo() { // ... perform some cleanup operation here }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

15

This code implicitly translates to the following:


protected override void Finalize() { try { // ... do something } finally { base.Finalize(); } }

Destructors are not inherited. When the finalization code of an object is executed and the object is destructed, the destructors in the inheritance chain of that object are called in order, from the most derived destructor to the least derived destructor.

Differences Between C# and C++ Destructors


C# destructors and C++ destructors differ in several important ways, as shown in the following table.
Destructor C# destructors Characteristics Execute non-deterministically Automatically invoked at any time after an object becomes eligible for garbage collection Not guaranteed to run in any specific order, even if one object contains or refers to another Cannot be invoked explicitly C++ destructors Execute deterministically Run in the order they are called Can be invoked explicitly

An Example of Implicit Resource Management


A class Foo has a constructor that creates a FileStream. To ensure that the buffer of the FileStream object is properly flushed, the class Foo provides implicit management of the resource through destructor code that closes the FileStream, as shown in the following code:
class Foo { private System.IO.FileStream fs; //... public Foo() { fs = new System.IO.FileStream("bar", FileMode.CreateNew); } ~Foo() { fs.Close(); } }

Implicit management of resources may not be adequate in all circumstances. In the preceding example, full access by other objects to the file that is opened by a Foo object may be delayed for an indeterminate amount of time after the Foo object no longer needs the resource. Therefore, you typically need to use an explicit form of resource management. For more information on explicit resource management, see Explicit Resource Management in this module.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 9: Memory and Resource Management

Garbage Collection with Finalization


Topic Objective
To describe the initial process of garbage collection with finalization.
!

Runtime Maintains a List of Objects That Require Finalization


$

Finalization queue

Lead-in
Finalization adds to the complexity and increases performance overhead of the basic garbage collection process, as it was described in Simple Garbage Collection in this module.

! !

Garbage Collection Process Invoked Unreachable Objects Requiring Finalization


$ $

References added to freachable queue Objects are now reachable and not garbage Unreachable objects' memory is reclaimed

Move Reachable Objects to Compact the Heap


$

Update References to All Moved Objects

Finalization adds to the complexity and increases performance overhead of the basic garbage collection process, as it was described in Simple Garbage Collection in this module. The .NET Framework common language runtime maintains a list of managed objects that require finalization. This list is known as the finalization queue and is used during garbage collection to provide implicit resource management. Garbage collection is typically invoked when the creation of a new object requires more space in the managed heap than is currently available. After waiting for all other managed threads to be suspended, garbage collection with finalization proceeds as follows: 1. Garbage collection builds a graph of all reachable objects, as described in Simple Garbage Collection in this module. Any managed object that is not in the graph is unreachable. 2. Garbage collection checks the finalization queue to see if an unreachable object requires finalization. If an unreachable object requires finalization, it is removed from the finalization queue, and a reference to the object is placed in the freachable (pronounced F-reachable) queue. The freachable queue is part of the root references of an application. The object is therefore now considered reachable and is no longer garbage. 3. Garbage collection compacts the heap and updates references to all moved objects. At this point, the memory resources for the unreachable objects have been freed. 4. Garbage collection allows the application to continue normal operation. At this point, the finalization phase of the garbage collection process can commence on a separate thread.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

17

Garbage Collection with Finalization (continued)


Topic Objective
To describe the latter part of the process of garbage collection with finalization.
!

Finalize Thread Runs


$ $ $ $

Lead-in
After the memory resources for the unreachable objects are freed and the application has continued normal operation, the finalization phase of garbage collection commences on a separate thread.

Executes freachable objects' Finalize methods References removed from freachable queue Unless resurrected, objects are now garbage May be reclaimed next time garbage collection occurs

After the memory resources for the unreachable objects are freed and the application has continued normal operation, the finalization phase of garbage collection commences on a separate thread.

The Finalization Phase


As the application runs, a special runtime thread removes references to objects from the freachable queue and calls the finalize code of those objects. Therefore, it is important that this code does not depend upon the identity of the thread. For example, the method should not depend on thread local storage. After an object has been finalized and removed from the freachable queue, it becomes unreachable again as long as that object has not been resurrected. An object is resurrected if it becomes reachable from an application root after previously being unreachable. However, the objects memory resources are not freed at this time. The reclamation of the objects memory resources must wait until garbage collection occurs next.

Resurrection
Resurrection of an object occurs when a previously unreachable object becomes reachable from an application root during finalization. For example, the finalize code for an object may assign to a global or static variable a reference to the object itself. The object is now reachable and is not subject to garbage collection.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 9: Memory and Resource Management

Issues with Resurrection


You should avoid resurrection when possible because the objects finalize code has been called and may have released resources that are required for the objects proper operation, even if the objects memory is valid. For example, when the destructor of the Foo class that was shown in An Example of Implicit Resource Management in this module executes its finalization code, the file will close, and the other methods of Foo that require an open FileStream may not be able to successfully complete. In addition, when a resurrected object becomes unreachable sometime in the future, its finalize code will not be called unless the object has called the GC.ReRegisterForFinalize method. You should also note that even if the finalize code of a class does not resurrect an object, that object may still be resurrected, as when another object that refers to the object is resurrected. Thus, all objects should be able to handle resurrection. For more information on resurrection and finalization, see Controlling Garbage Collection in this module.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

19

Multimedia: Garbage Collection


Topic Objective
To illustrate how garbage collection, including finalization, works.

Lead-in
This animation illustrates the .NET Framework common language runtimes garbage collection process, including finalization. To launch the animation, click the button in the lower left corner of the slide. To play the animation, click the play button in the lower left corner of the screen.

This animation illustrates the .NET Framework common language runtimes garbage collection process, including finalization. Note Compiler optimization is disabled in this scenario to prevent an object from becoming eligible for garbage collection earlier than would be expected. Otherwise, the compiler could optimize away assignments to local variables that are never observed by a later read. This optimization could result in an object being subject to garbage collection before its reference is assigned to null. In this animation, you will learn that:
!"

The .NET Framework common language runtime allocates memory resources for objects in the section of the applications memory that is called the managed heap. The finalization queue holds references to objects whose classes require finalization. The freachable queue is a special kind of root reference whose entries are references to objects that are ready to have their finalize code invoked. An freachable reference keeps the object alive. The nondeterministic release of memory and non-memory resources is another significant difference between .NET Framework and C++ destructors.

!"

!"

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 9: Memory and Resource Management

Finalization Guidelines
Topic Objective
To alert students to issues that are associated with finalization.
!

Avoid Finalization and Destructors If Possible


$ $ $

Performance costs Complexity Delay of memory resource release Avoid calling other objects Avoid making assumptions about thread ID Avoid making references to other objects

Lead-in
This topic provides guidelines for handling finalization.
!

If You Require Finalization, Finalize Code Should:


$ $

Classes with Finalization Should:


$

This topic provides guidelines for handling finalization. To avoid problems that result from the .NET Frameworks nondeterministic ordering of calls to finalize code, you may need to use explicit resource management in addition to careful design.

Avoid Finalization if Possible


You should only implement finalization, or implement a destructor in C#, on classes that require finalization. If your class has only managed references and does not have to manage non-memory resources, you should not implement finalize code. Finalization adds overhead and complexity, and delays the reclamation of an objects memory resources.

Implementing Finalization
If you must implement finalization, you should obey the following guidelines:
!"

Avoid calling other objects in finalization code. In your finalization code, free any external resources that your object is holding onto. However, you should avoid calling other objects, for example, contained objects, because their finalize code may have already been called. The .NET Framework common language runtime does not specify any order on its invocation of the finalize code of freachable objects. Therefore, if an object of type Foo refers to an object of type Bar, you cannot know whether the finalize code of Foo will be called before or after the finalize code of Bar. This nondeterminism may cause problems if the finalize code of Foo calls a method in Bar that requires a resource that is released by Bar in its finalize code.

!"

Avoid assumptions about thread ID. As previously noted, finalization code should not make any assumptions about the thread ID.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management


!"

21

Ensure that the Finalize code of your base class is called. This call is performed automatically by the C# destructor syntax. Avoid references to other objects. A class that requires finalization should avoid references to other objects because a finalizable object will prolong its own lifetime and the lifetime of objects that it references. If possible, you should factor such classes into the following two classes: One class that contains the resource that requires management and has the finalize code but has no other object references. A second class that holds the references to other objects but has no finalize code.

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 9: Memory and Resource Management

Controlling Garbage Collection


Topic Objective
To introduce techniques to control garbage collection.
!

To Force Garbage Collection To Suspend Calling Thread Until Threads Queue of Finalizers Is Empty To Allow a Finalized Resurrected Object to Have Its Finalizer Called Again

Lead-in
The System.GC class of the .NET Framework contains methods that can be used to control the garbage collection process.

void System.GC.Collect(); void System.GC.Collect();


!

void System.GC.WaitForPendingFinalizers(); void System.GC.WaitForPendingFinalizers();


!

void System.GC.ReRegisterForFinalize(object obj); void System.GC.ReRegisterForFinalize(object obj);


!

To Request the System Not to Call the Finalizer Method

void System.GC.SuppressFinalize(object obj); void System.GC.SuppressFinalize(object obj);

The System.GC class of the .NET Framework contains methods that can be used to control garbage collection. The Collect method with no arguments forces the collection of all generations, as in the following code:
void System.GC.Collect();

For more information on generations, see Generations in this module. Finalizers are run on a separate thread of execution. When the WaitForPendingFinalizers method is called, the current thread is suspended until the queue of finalizers that are waiting to run is empty. Because the running of finalizers may trigger another garbage collection, which may, in turn, re-queue new finalizers, there is no guarantee that the call to WaitForPendingFinalizers will terminate.
void System.GC.WaitForPendingFinalizers();

Once the garbage collection process calls an objects finalize code, garbage collection assumes that there is no need to call it again. However, if an object is resurrected, the ReRegisterForFinalize method may be called to force garbage collection to call the objects finalize code again the next time the object is destroyed. Note that if ReRegisterForFinalize is called multiple times, the objects finalize code will also be called multiple times.
void System.GC.ReRegisterForFinalize(object obj);

If an object that has finalize code no longer requires finalization to manage its resources, the object may call the SuppressFinalize method to improve performance. For example, an object that supports explicit resource management should call the SuppressFinalize method when it releases its resources, as in the following code:
void System.GC.SuppressFinalize(object obj);

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

23

Demonstration: Finalization
Topic Objective
To demonstrate how garbage collection handles finalization and resurrection.

Lead-in
This demonstration shows how garbage collection handles finalization and resurrection.

This demonstration shows how garbage collection handles finalization and resurrection. For Your Information
Use the debugger to step through the code while you point out features and ask students what they think will happen next. In this section run the Introduction and Resurrection methods.
// This method demonstrates how the GC works. private static void Introduction() { Display(0, "\n\nDemo start: Introduction to Garbage Collection.", +1); // Create a new DerivedObj in the managed heap // Note: Both BaseObj and DerivedObj constructors are called DerivedObj obj = new DerivedObj("Introduction"); obj = null; // We no longer need this object // The object is unreachable so forcing a GC causes it to be // finalized. Collect(); // Wait for the GC's Finalize thread to finish // executing all queued Finalize code. WaitForFinalizers(); // // // // NOTE: The GC calls the most-derived (farthest away from the Object base class) destructor. A C# destructor automatically calls its base class destructor.

//Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 9: Memory and Resource Management


// This is the same test as above with one slight variation obj = new DerivedObj("Introduction"); // obj = null; // Variation: this line is commented out Collect(); WaitForFinalizers(); // If compiler optimization was turned on: // Notice that we get identical results as above: // the destructors Finalize code // runs because the just in time compilers optimizer // knows that obj is not referenced later in this function // Now we explicitly release the object and the destructors // Finalize code is run. // If compiler optimization was turned off // we now see the finalization called otherwise nothing. obj = null; Collect(); WaitForFinalizers(); Display(-1, "Demo stop: Introduction to Garbage Collection.", 0); }

// Resurrection // This reference is accessed in the ResurrectObj.Finalize // code and is used to create a strong reference to an // object (resurrecting it). static public ResurrectObj ResObjHolder; // Defaults to null // This method demonstrates how the GC supports resurrection. // NOTE: Resurrection is discouraged. private static void ResurrectionDemo() { Display(0, "\n\nDemo start: Object Resurrection.", +1); // Create a ResurrectObj ResurrectObj obj = new ResurrectObj("Resurrection"); // Destroy all strong references to the new ResurrectionObj obj = null; // Force the GC to determine that the object is unreachable. Collect(); WaitForFinalizers(); // You should see the Finalize code called. // // // // However, the ResurrectObj's Finalize code resurrects the object keeping it alive. It does this by placing a reference to the dying-object in Application.ResObjHolder

// You can see that ResurrectObj still exists because // the following line doesn't raise an exception. ResObjHolder.Display("Still alive after Finalize called"); //Code continued next page
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management


// Prevent the ResurrectObj object from resurrecting // itself again, ResObjHolder.SetResurrection(false); // Now, let's destroy this last reference to the // ResurrectObj ResObjHolder = null;

25

// Force the GC to determine that the object is unreachable. Collect(); WaitForFinalizers(); // You should see the Finalize code called. Display(-1, "Demo stop: Object Resurrection.", 0); }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 9: Memory and Resource Management

# Explicit Resource Management


Topic Objective
To provide an overview of the section topics.
! !

Lead-in
Your classes should provide an explicit and an implicit way to free resources.

The IDisposable Interface and the Dispose Method Temporary Resource Usage Design Pattern

Typically, your classes should provide an explicit and an implicit way to free resources. A class provides explicit control by having a method that a client of the object will call when the client has finished using the object. In this section, you will learn how to perform explicit resource management by using the IDisposable interface and Dispose method, and how to allocate resources for temporary use.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

27

The IDisposable Interface and the Dispose Method


Topic Objective
To explain how to use the IDisposable interface and the Dispose method when working with explicit resource management.
! ! !

Inherit from the IDisposable Interface Implement the Dispose Method Follow the .NET Framework SDKs Design Pattern

Lead-in
Classes that contain nonmemory resources should provide explicit resource management by inheriting from the IDisposable interface and implementing its Dispose method.

class ResourceWrapper : IDisposable class ResourceWrapper : IDisposable { { // see code example for details // see code example for details

} }

Classes that contain non-memory resources should provide explicit resource management by inheriting from the IDisposable interface and implementing its Dispose method. A types Dispose method should release all of the resources that it owns. It should also release all resources owned by its base types by calling its parent types Dispose method. The parent types Dispose method should release all resources that it owns and in turn call its parent types Dispose method, propagating this pattern through the hierarchy of base types. To ensure that resources are always cleaned up appropriately, a Dispose method should be safely callable multiple times and should never throw an exception. For Your Information
The IDisposable interface and Dispose method are important topics that the students will need to know to do the lab. The ResourceWrapper design pattern should be discussed in detail.

A Dispose method should call the GC.SuppressFinalize method for the object it is disposing. If the object is currently on the finalization queue, GC.SuppressFinalize prevents its Finalize code from being called. Remember that executing Finalize code is costly to performance. If your Dispose method has already done the work to clean up the object, then it is not necessary for the garbage collector to call the objects Finalize code. The following code example from the .NET Framework Software Developers Kit (SDK) illustrates one possible design pattern for implementing a Dispose method for classes that encapsulate unmanaged resources. You may find this pattern convenient to use because it is implemented throughout the .NET Framework. However, this is not the only possible implementation of a Dispose method. The base class implements a public Dispose method that can be called by users of the class. The Dispose method in turn calls the appropriate virtual Dispose method, depending upon the identity of the caller. The appropriate cleanup code for the object is executed in the virtual Dispose method. The base class provides a destructor as a safeguard in the event that Dispose is not called, as in the following example of the ResourceWrapper design pattern:

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

28

Module 9: Memory and Resource Management


public class BaseResource: IDisposable { // Pointer to an external resource. private IntPtr handle; // Pointer to a managed object resource this class uses. private Component Components; // To track whether Dispose has been called. private bool disposed = false; // Constructor for the BaseResource Object. public BaseResource() { handle = // Insert code here to allocate on the // unmanaged side. Components = new Component(); } // Implement IDisposable. public void Dispose() { Dispose(true); // Take yourself off of the Finalization queue. GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { // Check to see if Dispose has already been called. if(!this.disposed) { // If this is a call to Dispose, dispose all managed // resources. if(disposing) { Components.Dispose(); } // Release unmanaged resources. this.disposed = true; Release(handle); handle = IntPtr.Zero; } } // Use C# destructor syntax for finalization code. // This destructor will run only if the Dispose method // does not get called. // It gives your base class the opportunity to finalize. ~BaseResource() { Dispose(false); } //Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management


// Allow your Dispose method to be called multiple times, // but throw an exception if the object has been disposed. // Whenever you do something with this class, // check to see if it has been disposed. public void DoSomething() { if(this.disposed) { throw new ObjectDisposedException("BaseResource"); } } } // Design pattern for a derived class. public class MyResourceWrapper: BaseResource { private bool disposed = false; public MyResourceWrapper() { // Constructor for this object. } protected override void Dispose(bool disposing) { if(!this.disposed) { if(disposing) { // Release any managed resources here. } // Release any unmanaged resources here. this.disposed = true; // Call Dispose on your base class. base.Dispose(disposing); } } } // This derived class does not have Finalize code // or a Dispose method because it inherits them from // the base class.

29

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

30

Module 9: Memory and Resource Management

Guidelines for Working with Explicit Resource Management


The preceding example of the ResourceWrapper design pattern highlights some important guidelines that you should follow when working with explicit resource management.
!"

Suppress finalization of your instance once Dispose has been called:


void System.GC.SuppressFinalize(Object obj);

!"

Propagate the Dispose method through containment hierarchies. Dispose should dispose of all resources that are held by an object and any object that is contained by that object. For example, a TextReader object holds onto a Stream object and an Encoding object, but the clients of the TextReader object are unaware of the Stream object and the Encoding object. You can assume that both the Stream and the Encoding objects have acquired external resources. When a client calls Dispose on the TextReader object, the TextReader object should in turn call Dispose on the Stream and the Encoding objects, thus causing them to release their external resources.

For Your Information


Students will need to understand the concept of containment hierarchies and how this relates to the Dispose method to do the lab. Illustrate this important concept with an example or two.

!"

Do not assume that the Dispose method will be called. As a precaution, you should also release resources in the destructor. In finalization code, or code that is called by finalization, for example, freeState, do not propagate the Dispose or Finalize method calls through the containment hierarchy of the object because these contained objects may have been finalized already. For the same reason, you should generally avoid making calls to other objects from within code that may execute during finalization.

!"

Throw an ObjectDisposedException when the methods of your class that depend upon resources that have been disposed are called. Consider not having your object be fully usable after calling Dispose. It is often difficult to recreate an object that has already been disposed. Allow your Dispose method to be called more than once without throwing an exception. It is a no-op after the first call.

For Your Information


Students will need to be able to determine which methods require resources that may have been disposed to be able to do the lab. Illustrate this important concept with an example or two.

!"

!"

Using a Domain-Specific Name


Occasionally, a domain-specific name is more appropriate than the Dispose method. For example, a file encapsulation may want to use the name Close. In this case, you should implement Dispose privately and have the Close method call it, as shown in the following design pattern:
void IDisposable.Dispose() { Dispose(true); // Take yourself off of the Finalization queue. GC.SuppressFinalize(this); } public void Close() { ((IDisposable)this).Dispose(); }

For Your Information


Students will need to implement a domain-specific name in the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

31

Demonstration: The IDisposable Interface


Topic Objective
To demonstrate how to perform explicit resource management by using the IDisposable interface.

Lead-in
This demonstration shows how to perform explicit resource management by using the IDisposable interface.

This demonstration shows how to perform explicit resource management by using the IDisposable interface. For Your Information
Use the debugger to step through the code while you point out features and ask students what they think will happen next. In this section run the DisposeDemo method.

Note The DisposeObj class in the demonstration does not contain any managed resources that have Dispose methods. Therefore, it can use an implementation of the Dispose method that is simpler than the more general design pattern.
// This method demonstrates how to implement a type that // allows its users to explicitly dispose/close the object. // For many objects this paradigm is strongly encouraged. private static void DisposeDemo() { Display(0, "\n\nDemo start: Disposing an object versus Finalize.", +1); DisposeObj obj = new DisposeObj("Explicitly disposed"); // Explicitly cleanup this object, Finalize should run obj.Dispose(); obj = null; Collect(); // Finalize should NOT run (it was suppressed) WaitForFinalizers(); obj = new DisposeObj("Implicitly disposed"); obj = null; Collect(); // No explicit cleanup, Finalize SHOULD run WaitForFinalizers(); Display(-1, "Demo stop: Disposing an object versus Finalize.", 0); }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

32

Module 9: Memory and Resource Management

Temporary Resource Usage Design Pattern


Topic Objective
To explain how to allocate, use, and dispose of a resource in a short period of time.
!

Temporary Resource Use


$

Allocate a resource, use it, and dispose of it

Try and Finally

Lead-in
In a temporary resource use scenario, you allocate, use, and dispose of a resource in a short period of time.

void DoSomething() { void DoSomething() { Resource r = new Resource(...); Resource r = new Resource(...); try { r.Foo(); } try { r.Foo(); } finally { finally { if (r != null) ((IDisposable)r).Dispose(); if (r != null) ((IDisposable)r).Dispose(); } } } }
!

Using Statement

using (Resource r1 = new Resource()) { using (Resource r1 = new Resource()) { r1.Foo(); r1.Foo(); } }
In a temporary resource use scenario, you allocate, use, and dispose of a resource in a short period of time. The best way to ensure that the resource is disposed of, regardless of whether an exception is thrown, is to use a try and finally block. In the following example, a method named DoSomething needs to temporarily use an object of class Resource where Resource implements the IDisposable interface according to the guidelines that were specified in the preceding topic.
void DoSomething() { Resource r = new Resource(...); // acquire resource try { r.Foo(); // use resource } finally { // release resource if (r != null) ((IDisposable)r).Dispose(); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

33

Handling Nested Try and Finally Blocks


The syntax in the preceding example becomes even more awkward when more than one resource is used, and the try and finally blocks require nesting, as in the following example:
Resource r1 = new Resource(); try { Resource r2 = new Resource(); try { r1.Foo(); r2.Foo(); } finally { r2.Dispose(); } } finally { r1.Dispose(); }

C# provides the following using statement to simplify the syntax: using-statement: using ( resource-acquisition ) embedded-statement resource-acquisition: local-variable-declaration expression The using statement requires that the type of the resource acquisition be a type that implements System.IDisposable. Local variables that are declared in a resource acquisition are read-only and must include an initializer. In the following example, Resource is a reference type that implements IDisposable:
using (Resource r1 = new Resource()) { r1.Foo(); }

This statement is semantically equivalent to the following statement:


Resource r1 = new Resource(); try { r1.Foo(); } finally { if (r1 != null) ((IDisposable)r1).Dispose(); }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

34

Module 9: Memory and Resource Management

The following example:


using (Resource r1 = new Resource(), Resource r2 = new Resource()) { r1.Foo(); r2.Foo(); }

is semantically equivalent to:


using (Resource r1 = new Resource()) using (Resource r2 = new Resource()) { r1.Foo(); r2.Foo(); }

By expansion, the preceding example is semantically equivalent to:


Resource r1 = new Resource(); try { Resource r2 = new Resource(); try { r1.Foo(); r2.Foo(); } finally { if (r2 != null) ((IDisposable)r2).Dispose(); } } finally { if (r1 != null) ((IDisposable)r1).Dispose(); }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

35

Defining Generic Locks


In addition to using the using statement for resources, you can also use the using statement to define constructs that protect a block of statements with an object that must be locked and unlocked around that block of statements, as shown in the following example:
class RWLock { ReadKey ReadLock() { /* ... acquire read access ... */ return new ReadKey(this); } void ReadUnlock() { /* ... release read access ... */ } // helper struct to make "using" work with RWLock public struct ReadKey : IDisposable { private RWLock aLock; public ReadKey(RWLock aLock) { this.aLock = aLock; } public void Dispose() { aLock.ReadUnlock(); } } } .... class Test { RWLock aLock = new RWLock(); void f() { using (aLock.ReadLock()) { /* do stuff */ } } }

The method ReadKey.Dispose() is trivially inlined by the just-in-time (JIT) compiler. The code will be similar to the following optimal expansion:
class Test { RWLock aLock = new RWLock(); void f() { aLock.ReadLock(); try { /* do stuff */ } finally { aLock.ReadUnlock(); } } }

Note The use of this design pattern does not preclude use of the class in a natural way by languages that do not support the using pattern. Users of such languages can ignore the returned key and call ReadUnlock directly.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

36

Module 9: Memory and Resource Management

# Optimizing Garbage Collection


Topic Objective
To provide an overview of the section topics.
! ! !

Lead-in
In the .NET Framework, garbage collection has several advanced features that you can use to improve the performance of your software.

Weak References Generations Additional Performance Features

The .NET Framework common language runtimes garbage collection has several advanced features that you can use to improve the performance of your software. In addition to optimizing garbage collection programmatically, you can use the Performance Monitor tool (Perfmon.exe) to tune your application and build in multiprocessor support to enhance performance.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

37

Weak References
Topic Objective
To introduce the use of weak references to conserve memory resources.
!

A Weak Reference Allows an Object to Be Collected If Memory Is Low

Lead-in
A weak reference allows garbage collection to collect objects if memory in the managed heap is low.

Object obj = new Object(); // create strong reference Object obj = new Object(); // create strong reference WeakReference wr = new WeakReference(obj); WeakReference wr = new WeakReference(obj); obj = null; // remove strong reference obj = null; // remove strong reference // ... // ... obj = (Object) wr.Target; obj = (Object) wr.Target; if (obj != null) {//garbage collection hasnt occurred if (obj != null) {//garbage collection hasnt occurred // ... // ... } } else {// object was collected, reference is null else {// object was collected, reference is null //... //... } }

A weak reference to an object allows garbage collection to collect that object if memory in the managed heap is low. Weak references are useful in an application that has large amounts of easily reconstructed data. If the weak references object has not had its memory resources released by garbage collection, then the application can avoid the cost of reconstructing the data.

Strong References vs. Weak References


In the common language runtime, the garbage collection process reclaims inaccessible or unreachable memory that is allocated to an object. An object becomes unreachable if all references to it become invalid. For example, if an objects references are set to a null reference, it is unreachable. A directly or indirectly referenced object is reachable, and garbage collection is not permitted to reclaim it. A reference to a reachable object is called a strong reference. A weak reference also references a reachable object, or target. You acquire a strong reference to the target by assigning the value of the target property to a variable. However, if there are no strong references to the target, the target becomes eligible for garbage collection, even though it still has a weak reference.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

38

Module 9: Memory and Resource Management

Retrieving the Target


There may be a delay between the time when an object becomes eligible for garbage collection and the time when it is collected. If you attempt to retrieve the target after it has been collected, you will only retrieve a null reference. If the target has not yet been collected, you will retrieve a valid reference. The following example shows how to use weak references to improve performance:
Object obj = new Object(); // create strong reference WeakReference wr = new WeakReference(obj); obj = null; // remove strong reference //... obj = (Object) wr.Target; if (obj != null) { // garbage collection has not occurred, // obj valid reference // ... } else { // object was collected, reference is null //... }

A WeakReference object can specify whether the reference to its target is maintained after finalization. In this way, it can specify whether the weak reference should track the targets resurrection. The following table defines two types of weak references.
Type of weak reference Short weak reference Long weak reference Definition Does not track resurrection Tracks resurrection

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

39

Demonstration: Weak References


Topic Objective
To demonstrate how garbage collection handles weak references.

Lead-in
This demonstration shows how garbage collection handles weak references.

This demonstration shows how garbage collection handles weak references. For Your Information
In this section run the WeakRefDemo method. Read and follow the procedure in the Note and avoid using the debugger to single-step through the WeakRefDemo code.

Important Using the debugger to single-step through the WeakRefDemo code may prevent the garbage collection process from collecting an object that is only referenced by a weak reference. Instead of using the debugger to singlestep through the code you should set breakpoints at the beginning and end of the WeakRefDemo method to observe that objects with only weak references to them are collected.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

40

Module 9: Memory and Resource Management


// This method demonstrates how weak references (WR) work. A // WR allows the GC to collect objects if the managed heap is // low on memory. // WRs are useful to apps that have large amounts of easily// reconstructed data that they want to keep around to improve // performance. But, if the system is low on memory, // the objects can be destroyed and replaced when // the app knows that it needs it again. private static void WeakRefDemo(Boolean trackResurrection) { Display(0, String.Format( "\n\nDemo start: WeakReferences that {0}track ! resurrections.", trackResurrection ? "" : "do not "), +1); // Create an object BaseObj obj = new BaseObj("WeakRef"); // Create a WeakReference object that refers to the new // object WeakReference wr = new WeakReference(obj, trackResurrection); // The object is still reachable, so it is not finalized. Collect(); // The Finalize code should NOT execute WaitForFinalizers(); obj.Display("Still exists"); //Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management


// Let's remove the strong reference to the object obj = null; // Destroy strong reference to this object // The following line creates a strong reference to the // object obj = (BaseObj) wr.Target; Display("Strong reference to object obtained: " + (obj != null)); // Destroy strong reference to this object again. obj = null; // The GC considers the object to be unreachable and // collects it. Collect(); WaitForFinalizers(); // Finalize should run. // // // // // // // // // // This object resurrects itself when its Finalize code is called. If wr is NOT tracking resurrection, wr thinks the object is dead If wr is tracking resurrection, wr thinks the object is still alive

41

NOTE: If the object referred to by wr doesn't have a Finalize code, then wr would think that the object is dead regardless of whether wr is tracking resurrection or not.

// The following line attempts to create a strong reference // to the object. obj = (BaseObj) wr.Target; Display("Strong reference to object obtained: " + (obj != null)); if // // // // (obj != null) { The strong reference was obtained so this wr must be tracking resurrection. At this point we have a strong reference to an object that has been finalized but its memory has not yet been reclaimed by the collector. obj.Display("See, I'm still alive"); // Destroy the strong reference to the object obj = null; // Collect reclaims the object's memory since this // object has no Finalize code registered for it // anymore. Collect(); WaitForFinalizers(); // We should see nothing here obj = (BaseObj) wr.Target; // This now returns null Display("Strong reference to object obtained: " + (obj != null)); } //Code continued next page
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

42

Module 9: Memory and Resource Management


// Cleanup everything about this demo so there is no affect // on the next demo // Destroy strong reference (if it exists) obj = null; wr = null; // Destroy the WeakReference object (optional) Collect(); WaitForFinalizers(); // NOTE: You are discouraged from using the // WeakReference.IsAlive property // because the object may be killed immediately after // IsAlive returns making the return value incorrect. // If the Target property returns a non-null value, // then the object is alive and will stay alive // since you have a reference to it. If Target returns null, // then the object is dead. Display(-1, String.Format( "Demo stop: WeakReferences that {0}track resurrections.", trackResurrection ? "" : "do not "), 0); }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

43

Generations
Topic Objective
To explain how the .NET Framework common language runtime uses a system of generations to make garbage collection more efficient.
!

To Force Garbage Collection of Generation 0 Through a Specified Generation:

void System.GC.Collect(int Generation); void System.GC.Collect(int Generation);


!

Lead-in
To improve the performance of garbage collection, the .NET Framework uses a system based on object generations.

To Determine the Generation of an Object:

Int32 System.GC.GetGeneration(Object obj); Int32 System.GC.GetGeneration(Object obj);

To Return the Maximum Number of Generations That the System Currently Supports:

Int32 System.GC.MaxGeneration; Int32 System.GC.MaxGeneration;

To improve the performance of garbage collection, the .NET Framework uses a system based on object generations, which works as follows: 1. When a managed object is created by using the new operator and is added to the managed heap, it becomes part of generation 0. 2. After garbage collection is invoked, any generation 0 objects that remain in the managed heap are promoted to become members of generation 1. 3. Any generation 1 objects that remain in the managed heap are promoted to become members of generation 2. Because generation 2 is the highest generation that is currently supported, generation 2 objects that remain in the managed heap remain in generation 2. When garbage collection is invoked to free heap space, its performance is improved because it only compacts the section of the managed heap that contains generation 0 objects. Typically, the newer an object is, the shorter its lifetime will be. Therefore, sufficient space is usually freed when generation 0 is compacted. If sufficient space cannot be obtained when generation 0 is compacted, garbage collection will compact the older generations. To force the collection of generations from 0 through a specified generation, you can call the .NET Framework System.GC.Collect method, as follows:
void System.GC.Collect(int Generation);

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

44

Module 9: Memory and Resource Management

The System.GC.Generation method returns the current generation of an object as follows:


Int32 System.GC.GetGeneration(Object obj);

The System.GC.MaxGeneration property returns the maximum number of generations that the system currently supports. It is written as follows:
Int32 System.GC.MaxGeneration;

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

45

Demonstration: Generations
Topic Objective
To demonstrate how garbage collection handles generations.

Lead-in
This demonstration shows how garbage collection handles generations.

This demonstration shows how garbage collection handles generations. For Your Information
Use the debugger to step through the code while you point out features and ask students what they think will happen next. In this section run the GenerationDemo method.
// This method demonstrates how objects are promoted between // generations. // Applications could take advantage of this info to improve // performance but most applications will ignore this info. private static void GenerationDemo() { Display(0, "\n\nDemo start: Understanding Generations.", +1); // Let's see how many generations the managed heap supports // (we know it's 2) Display("Maximum GC generations: " + GC.MaxGeneration); // Create a new BaseObj in the heap GenObj obj = new GenObj("Generation"); // Since this object is newly created, it should be in // generation 0 obj.DisplayGeneration(); // Displays 0 // Performing a GC promotes the object's generation Collect(); obj.DisplayGeneration(); // Displays 1 Collect(); obj.DisplayGeneration(); Collect(); obj.DisplayGeneration(); //Code continued next page

// Displays 2

// Displays 2

(max generation)

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

46

Module 9: Memory and Resource Management


// Destroy the strong reference to this object obj = null; Collect(0); WaitForFinalizers(); // Collect objects in generation 0 // We should see nothing

// Collect objects in generations 0 and 1 Collect(1); WaitForFinalizers(); // We should see nothing Collect(2); // Same as Collect() // Now, we should see the Finalize code run WaitForFinalizers(); Display(-1, "Demo stop: Understanding Generations.", 0); }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

47

Additional Performance Features


Topic Objective
To introduce additional resources for improved application performance.
! ! ! !

Performance Monitoring Large Object Heap Multiprocessor Support Unsafe Code

Lead-in
In addition to programmatically manipulating garbage collection through weak references and generations, you can use other features and techniques to improve application performance.

In addition to programmatically manipulating garbage collection through weak references and generations, you can use other features and techniques to improve application performance.

Performance Monitoring
You can obtain real-time information about the memory activity of the .NET Framework common language runtime by using performance counters. You can view these counters by using the Performance Monitor tool (Perfmon.exe). To execute this program, click the Start menu, click Run, and type perfmon.exe in the text box. You can also execute the program by clicking Control Panel, double-clicking Administrative Tools, and double-clicking Performance. To view .NET Framework common language runtime memory statistics in the Performance window: 1. Click the System Monitor icon under the Console Root folder. 2. Click the + button in the right pane to add a counter to the System Monitor. 3. Specify the computer that you wish to monitor. 4. In the Performance object field, select .NET CLR Memory. 5. Select the desired counters and application instance. You can obtain descriptions of the counters by clicking the Explain button. In the future, you will also be able to read these counters by using the APIs that will be provided by the .NET Framework class library.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

48

Module 9: Memory and Resource Management

Large Object Heap


Objects that are larger than 20,000 bytes are allocated from a separate special heap. Garbage collection handles large objects in the same way as it handles other managed heap objects, except it does not compact the separate special heap to avoid the additional performance cost of shifting large blocks of memory.

Multiprocessor Support
The .NET Framework common language runtime provides two forms of garbage collection: a server version (MSCorSvr.dll) and a workstation version (MSCorWks.dll). The server version is multithreaded and highly scalable, while the client version is single-threaded and concurrent. Both versions feature low fragmentation, low overhead, and efficient use of cache space. The server version of the common language runtime contains features that improve the efficiency of resource collection. With synchronization-free allocations and scalable collections, a multiprocessor system receives a managed heap that is split into as many sections as there are CPUs. Each CPU has its own thread, which enables the runtime to perform garbage collection on different heaps simultaneously. If you have a garbage collection bottleneck, you can improve performance by scaling your application to a multiprocessor system.

Using Unmanaged Code to Control Garbage Collection


When you need fine-grained control or that extra margin of performance, C# provides the ability to write code that can deal directly with pointer types, and fix objects to temporarily prevent garbage collection from moving them. You must clearly mark such code in C# with the unsafe modifier. This ensures that other developers cannot possibly use unsafe features accidentally, and that the compiler and the execution engine work together to ensure that unsafe code cannot masquerade as safe code. You should note that unmanaged code is not verifiable by the .NET Framework common language runtime and should only be executed when trusted. It does, however, offer developers and users a way to optimize performance. Further discussion of unsafe code and memory management is beyond the scope of this course.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

49

Lab 9: Memory and Resource Management


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will learn how to use classes to create an application that explicitly manages resources by implementing a design pattern that is based on the IDisposable interface. You will also learn how to create an application that implicitly manages resources by using destructors.

Objectives
After completing this lab, you will be able to:
!"

Create an application, with classes, that explicitly manages resources by implementing a design pattern based on the IDisposable interface. Create an application that implicitly manages resources by using destructors.

!"

Lab Setup
Starter and solution files are associated with this lab. The starter files are in the folder <install folder>\Labs\Lab09\Starter. The solution files for this lab are in the folder <install folder>\Labs\Lab09\Solution.

Scenario
In this lab, you are provided with a Microsoft Visual Studio .NET console application as a starting point. The application is named Memory and Resource Management. It allows a user to enter text data. When the user has finished entering data, the application outputs the number of completed sentences and the character count, and then the text. The text is formatted so that each sentence is displayed on a separate line without an ending period. The application is implemented by using a SentenceFormatter object that buffers the input text until a completed sentence is detected or until its Close method is called.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

50

Module 9: Memory and Resource Management

When a completed sentence is detected or its Close method is called, the SentenceFormatter object sends its buffered text to a SimpleTextBuffer object. The SimpleTextBuffer object buffers this text until it is closed or finalized. At that time, the SimpleTextBuffer object outputs its buffered text to the console. In this lab, the Memory and Resource Management application is used to illustrate some key points about .NET Framework resource management. To provide explicit and implicit resource management, you will modify this program to follow the design pattern that is described in Module 9.

Estimated time to complete this lab: 60 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

51

Exercise 1 Programming for Explicit Resource Management


In this exercise, you will modify the Memory and Resource Management application to incorporate explicit resource management.

!" examine the application To


1. In Visual Studio .NET, open the Memory and Resource Management project, which is located in <install folder>\Labs\Lab09\Starter\Memory and Resource Management. 2. Open the Memory and Resource Management.cs file and examine the code. 3. Build and run the Memory and Resource Management application. The following text should appear in the console output:
Enter text, when finished enter an empty line

4. Enter the following text, which is followed by an empty line, as prompted:


hello world.are you out there?

Text similar to the following should appear in the console output:


SimpleTextBuffer: hello world are you out there? Completed Sentences 1, Output Characters 29 hit enter to exit program

!" add explicit resource management To


Tip For detailed explanations about and code examples for adding explicit resource management, see The IDisposable Interface and the Dispose method in this module. 1. Modify the SentenceFormatter and SimpleTextBuffer classes to inherit from IDisposable. 2. For each of these classes, add a private member of type bool named disposed to indicate whether the objects non-memory resources have been released. Initialize the value of disposed to false.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

52

Module 9: Memory and Resource Management

3. For each of these classes, add a protected virtual void Dispose method that takes a single bool parameter named disposing. If the objects disposed flag indicates that the object has not already been disposed: a. If the parameter disposing indicates that the object is not in finalization mode, then propagate the Dispose/Close method call through any containment hierarchies. Tip Propagating the Dispose/Close method call through a containment hierarchy is discussed in the topic The IDisposable Interface and the Dispose Method in Module 9. The SentenceFormatter contains a SimpleTextBuffer object named aSimpleTextBuffer. Note The SentenceFormatter should send its text buffer to its contained SimpleTextBuffer object named aSimpleTextBuffer before it calls that SimpleTextBuffer objects Close method. b. Free the objects internal state and set disposed to indicate that the object has been disposed. Multiple calls to Dispose should not throw an exception. 4. For both classes, add an IDisposable.Dispose method that calls Dispose with true as its argument followed by a call to the GC classs method to suppress finalization. 5. For both classes, modify the Close method to call the IDisposable.Dispose method. Tip To call IDisposable.Dispose, you must cast this to IDisposable. 6. For the SentenceFormatter and SimpleTextBuffer methods, which require resources that are freed by their classes Dispose method, add an initial check that throws an ObjectDisposedException if those resources have been released. Tip When the SentenceFormatters Dispose method is called it frees its sentenceBuffer and aSimpleTextBuffer resources. The SentenceFormatter;s SentenceCount property does not use either of these resources and therefore does not need to check if these resources have been released. The ProcessInput method uses both these resources and therefore must check whether these resources have been released.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

53

Exercise 2 Programming for Implicit Resource Management


In this exercise, you will modify the Memory and Resource Management application to incorporate implicit resource management.

!" add implicit resource management To


1. Add destructors to the SentenceFormatter and SimpleTextBuffer classes. These destructors should free only their objects internal state by calling Dispose with false. Add code to the destructors to output to the console the name of the class and the fact that the destructor was executed. Note Even though you have inserted code to do implicit resource management, the program is still explicitly managing its resources through the following method call in the Main method:
aSentenceFormatter.Close();

2. Build and run the Memory and Resource Management application. As in the preceding exercise, the following text should appear in the console output:
Enter text, when finished enter an empty line

3. Enter the following text, and then enter an empty line, as prompted:
hello world.are you out there?

Text similar to the following should appear in the console output:


SimpleTextBuffer: hello world are you out there? Completed Sentences 1, Output Characters 29 hit enter to exit program

Note With explicit resource management, the output is identical to the output in Exercise 1. All the characters you entered are output and counted.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

54

Module 9: Memory and Resource Management

!" test implicit resource management performance To


1. In the Main method, add comments to the beginning of the following line of code so that the Close method will not be invoked:
aSentenceFormatter.Close();

2. After the code in the preceding step is a statement that outputs the sentence and character count to the console. After this Console.WriteLine statement, add code to assign the SimpleTextBuffer and SentenceFormatter objects to null, invoke garbage collection on all generations, and wait for pending finalizers. 3. Build and run the Memory and Resource Management application. As in the preceding exercise, the following text should appear in the console output:
Enter text, when finished enter an empty line

4. Enter the following text, followed by an empty line, as prompted:


hello world.are you out there?

Text similar to the following should appear in the console output:


Completed Sentences 1, Output Characters 11 SentenceFormatter destructor called SimpleTextBuffer: hello world SimpleTextBuffer destructor called hit enter to exit program

Note Observe the difference in the number of output characters when using explicit and implicit resource management. Explicit resource management outputs all the characters you entered because it propagates the close/dispose method call down the containment hierarchy, thereby flushing all of the buffers. Implicit resource management cannot safely do this propagation because of the nondeterministic order of destructor calls. Therefore, not all of the characters you entered are output.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 9: Memory and Resource Management

55

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! ! ! ! !

Memory Management Basics Non-Memory Resource Management Implicit Resource Management Explicit Resource Management Optimizing Garbage Collection

Lead-in
The review questions cover some of the key concepts taught in the module.

1. Describe two common problems with manual memory management that the .NET Frameworks automatic memory management addresses. Failure to release memory (Memory leaks) Accessing in valid memory (dangling pointer references)

2. Describe the .NET Framework mechanism that is used to provide implicit resource management. During the finalization phase of garbage collection, garbage collection calls Finalize code (C# destructor), which allows an object to properly clean up its resources before its memory resources are freed.

3. State why explicit resource management is desirable. Describe the interface that a class should inherit from and the method(s) that a class should implement to provide explicit memory management. Implicit resource management is non-deterministic, and therefore an application cannot know exactly when a resource will be freed. Explicit resource management allows a client to invoke a method to deterministically free the resource. Therefore, classes should inherit from IDisposable and implement its Dispose method. Also garbage collections non-deterministic ordering of calls to finalize code makes it dangerous for classes to refer to other objects during finalization. Therefore, explicit resource management may be the only safe way for a class to refer to other objects when it releases resources, as, for example, when it flushes buffers.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

56

Module 9: Memory and Resource Management

4. State the purpose of weak references. Weak references are useful in applications that have large amounts of easily reconstructed data that should be maintained to improve performance. A weak reference allows garbage collection to collect these objects if memory in the managed heap is low.

5. Explain how and why generations are used by garbage collection. When garbage collection is invoked to free heap space, its performance is improved because it only compacts the section of the managed heap that contains generation 0 objects. Typically, the newer an object is, the shorter its lifetime will be. Therefore, sufficient space is usually freed when generation 0 is compacted. If sufficient space cannot be obtained when generation 0 is compacted, garbage collection will compact the older generations.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files


Contents Overview Streams Readers and Writers Basic File I/O Lab 10: Files Review 1 2 4 7 20 25

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

iii

Instructor Notes Module 10


Presentation: 45 Minutes Lab: 45 Minutes After completing this module, students will be able to:
!"

Use Stream objects to read and write bytes to backing stores, such as strings and files. Use BinaryReader and BinaryWriter objects to read and write primitive types as binary values. Use StreamReader and StreamWriter objects to read and write characters to a stream. Use StringReader and StringWriter objects to read and write characters to strings. Use Directory and DirectoryInfo objects to create, move, and enumerate through directories and subdirectories. Use FileSystemWatcher objects to monitor and react to changes in the file system. Explain the key features of the Microsoft .NET Frameworks isolated storage mechanism.

!"

!"

!"

!"

!"

!"

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_10.ppt

Preparation Tasks
To prepare for this module, you should:
!" !"

Read all of the materials for this module. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 10: Data Streams and Files

Module Strategy
Use the following strategy to present this module:
!"

Streams Briefly review fundamental stream operations and introduce the stream classes that are provided by System.IO. Point out that this module discusses synchronous operations only; asynchronous operations are beyond the scope of this course. Tell students that the NetworkStream class is covered in more detail in Module 11, Internet Access, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

!"

Readers and Writers Cover the commonly used reader and writer classes that are used to input and output to streams and strings that use types other than bytes.

!"

Basic File 1/O Discuss in more detail the stream classes that are provided by System.IO for manipulating files and directories. Discuss the security issues that are associated with writing code that will be downloaded over the Internet.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! ! !

Streams Readers and Writers Basic File I/O

Lead-in
In this module, you will learn about how to use types that allow reading from and writing to data streams and files.

The System.IO namespace contains types that allow synchronous and asynchronous reading from and writing to data streams and files. This module discusses synchronous operations only, as asynchronous operations are beyond the scope of this course. After completing this module, you will be able to: For Your Information
When you talk about a particular class, you may want to display the class information for System.IO from the .NET Framework Reference section in the .NET Framework SDK.
!"

Use Stream objects to read and write bytes to backing stores, such as strings and files. Use BinaryReader and BinaryWriter objects to read and write primitive types as binary values. Use StreamReader and StreamWriter objects to read and write characters to a stream. Use StringReader and StringWriter objects to read and write characters to strings. Use Directory and DirectoryInfo objects to create, move, and enumerate through directories and subdirectories. Use FileSystemWatcher objects to monitor and react to changes in the file system. Explain the key features of the Microsoft .NET Frameworks isolated storage mechanism.

!"

!"

!"

!"

!"

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

Streams
Topic Objective
To introduce the functions of the Stream class and its subclasses.
!

A Way to Read and Write Bytes from and to a Backing Store


#

Stream classes inherit from System.IO.Stream CanRead, CanWrite, and CanSeek properties Flush method outputs and clears internal buffers Close method performs an implicit Flush for buffered streams NetworkStream, BufferedStream, MemoryStream, FileStream

Fundamental Stream Operations: Read, Write, and Seek


#

Lead-in
Streams provide a way to read and write bytes from and to a backing store. A backing store is a storage medium, such as a disk or memory.
!

Some Streams Support Buffering for Performance


#

Close Method Frees Resources


#

Stream Classes Provided by the .NET Framework


#

Null Stream Instance Has No Backing Store

Streams provide a way to read and write bytes from and to a backing store. A backing store is a storage medium, such as a disk or memory. All classes that represent streams inherit from the Stream class. The Stream class and its subclasses provide a generic view of data sources and repositories, and isolate the programmer from the specific details of the operating system and underlying devices.

Fundamental Stream Operations


Streams allow you to perform three fundamental operations: 1. You can read from streams. Reading is the transfer of data from a stream into a data structure, such as an array of bytes. 2. You can write to streams. Writing is the transfer of data from a data structure into a stream. 3. Streams can support seeking. Seeking is the querying and modifying of the current position within a stream. Seek capability depends on the kind of backing store that a stream has. For example, network streams have no unified concept of a current position and therefore typically do not support seeking. Depending on the underlying data source or repository, streams may support only some of these capabilities. An application can query a stream for its capabilities by using the CanRead, CanWrite, and CanSeek properties. The Read and Write methods read and write byte data. For streams that support seeking, the Seek and SetLength methods and the Position and Length properties can be used to query and modify the current position and length of a stream.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

Support for Buffering


Some stream implementations perform local buffering of the underlying data to improve performance. For such streams, you can use the Flush method to clear internal buffers and ensure that all data has been written to the underlying data source or repository. Calling the Close method on a stream flushes any buffered data, essentially calling the Flush method for you. The Close method also releases operating system resources, such as file handles, network connections, or memory that is used for any internal buffering.

Stream Classes Provided by the .NET Framework


The .NET Framework contains several stream classes that derive from the System.IO.Stream class. The System.Net.Sockets namespace contains the NetworkStream class. NetworkStream provides the underlying stream of data for network access and will be discussed in more detail in Module 11, Internet Access, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease). The System.IO namespace contains the BufferedStream, MemoryStream, and FileStream classes, which are derived from the System.IO.Stream class.

BufferedStream Class
The BufferedStream class is used to buffer reads and writes to another stream. A buffer is a block of bytes in memory that is used to cache data, thereby reducing the number of calls to the operating system. Buffers thus can be used to improve read and write performance. Another class cannot inherit from the BufferedStream class.

MemoryStream Class
The MemoryStream class provides a way to create streams that have memory as a backing store, instead of a disk or a network connection. The MemoryStream class creates a stream out of an array of bytes.

FileStream Class
The FileStream class is used for reading from and writing to files. By default, the FileStream class opens files synchronously, but it provides a constructor to open files asynchronously.

Null Stream Instance


There are times when an application needs a stream that simply discards its output and returns no input. You can obtain such a stream that has no backing store and that will not consume any operating resources from the Stream classs public static field named Null. For example, you may code an application to always write its output to the FileStream that is specified by the user. When the user does not want an output file, the application directs its output to the Null stream. When the Write methods of Stream are invoked on this Null stream, the call simply returns, and no data is written. When the Read methods are invoked, the Null stream returns zero without reading data.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

Readers and Writers


Topic Objective
To show how reader and writer classes are used to input and output to streams and strings.
!

Classes That Are Derived from System.IO.Stream Take Byte Input and Output Readers and Writers Take Other Types of Input and Output and Read and Write Them to Streams or Strings BinaryReader and BinaryWriter Read and Write Primitive Types to a Stream TextReader and TextWriter Are Abstract Classes That Implement Read Character and Write Character Methods TextReader and TextWriter Derived Classes Include:
# #

Lead-in
As previously mentioned, the Stream class is designed for byte input and output. You can use the reader and writer classes to input and output to streams and strings using other types.
! !

StreamReader and StreamWriter, which read and write to a stream StringReader and StringWriter, which read and write to a string and StringBuilder respectively

As discussed in Streams in this module, the Stream class is designed for byte input and output. You can use the reader and writer classes to input and output to streams and strings that use other types. The following table describes some commonly used reader and writer classes.
Class BinaryReader and BinaryWriter Description These classes read and write primitive types as binary values in a specific encoding to and from a stream. The implementations of these classes are designed for character input and output. These classes are derived from the TextReader and TextWriter classes and read and write their characters to a stream. Theses classes also derive from the TextReader and TextWriter classes but read their characters from a string and write their characters to a StringBuilder class.

TextReader and TextWriter StreamReader and StreamWriter

StringReader and StringWriter

A reader or writer is attached to a stream so that the desired types can be read or written easily.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

The following example shows how to write data of type Integer to and read from a new, empty file stream that is named Test.data. After creating the data file in the current directory, the BinaryWriter class is used to write the integers 0 through 10 to Test.data. Then the BinaryReader class reads the file and displays the files content to the console.
using System; using System.IO; class MyStream { private const string FILE_NAME = "Test.data"; public static void Main(String[] args) { // Create the new, empty data file. if (File.Exists(FILE_NAME)) { Console.WriteLine("{0} already exists!", FILE_NAME); return; } FileStream fs = new FileStream(FILE_NAME, FileMode.CreateNew); // Create the writer for data. BinaryWriter w = new BinaryWriter(fs); // Write data to Test.data. for (int i = 0; i < 11; i++) { w.Write( (int) i); } w.Close(); fs.Close(); // Create the reader for data. fs = new FileStream(FILE_NAME, FileMode.Open, FileAccess.Read); BinaryReader r = new BinaryReader(fs); // Read data from Test.data. for (int i = 0; i < 11; i++) { Console.WriteLine(r.ReadInt32()); w.Close(); } } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

In the following example, the code defines a string and converts it to an array of characters, which can then be read as desired by using the appropriate StringReader.Read method:
using System; using System.IO; public class CharsFromStr { public static void Main(String[] args) { // Create a string to read characters from. String str = "Some number of characters"; // Size the array to hold all the characters of the // string, so that they are all accessible. char[] b = new char[24]; // Create a StringReader and attach it to the string. StringReader sr = new StringReader(str); // Read 13 characters from the array that holds // the string, starting from the first array member. sr.Read(b, 0, 13); // Display the output. Console.WriteLine(b); // Close the StringReader. sr.Close(); } }

The preceding example produces the following output:


Some number o

System.Text.Encoding
Internally, the common language runtime represents all characters as Unicode. However, Unicode can be inefficient when transferring characters over a network or when persisting in a file. To improve efficiency, the .NET Framework class library provides several types that are derived from the System.Text.Encoding abstract base class. These classes know how to encode and decode Unicode characters to ASCII, UTF-7, UTF-8, Unicode, and other arbitrary code pages. When you construct a BinaryReader, BinaryWriter, StreamReader, or StreamWriter, you can choose any of these encodings. The default encoding is UTF-8.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

$ Basic File I/O


Topic Objective
To introduce the classes of the System.IO namespace, which are discussed in this section.
! ! ! ! ! ! !

FileStream Class File and FileInfo Class Reading Text Example Writing Text Example Directory and DirectoryInfo Class FileSystemWatcher Isolated Storage

Lead-in
The .NET Frameworks System.IO namespace provides a number of useful classes for manipulating files and directories.

The .NET Frameworks System.IO namespace provides a number of useful classes for manipulating files and directories. Important Default security policy for the Internet and intranets does not allow access to files. Therefore, do not use the regular, nonisolated storage IO classes if you are writing code that will be downloaded over the Internet. Use Isolated Storage instead. Caution When a file or network stream is opened, a security check is performed only when the stream is constructed. Therefore, be careful when handing off these streams to less trusted code or application domains.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

FileStream Class
Topic Objective
To define the FileStream class and the types that are used as parameters in some FileStream constructors.
! !

The FileStream Class Is Used for Reading from and Writing to Files FileStream Constructor Parameter Classes
# # #

Lead-in
The FileStream class is used for reading from and writing to files. The FileMode, FileAccess, and FileShare types are used as parameters in some FileStream constructors.

FileMode Open, Append, Create FileAccess Read, ReadWrite, Write FileShare None, Read, ReadWrite, Write

FileStream f = new FileStream(name, FileMode.Open, FileStream f = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read); FileAccess.Read, FileShare.Read);
!

Random Access to Files by Using the Seek Method


# #

Specified by byte offset Offset is relative to seek reference point: Begin, Current, End

The FileStream class is used for reading from and writing to files. The FileMode, FileAccess, and FileShare types are used as parameters in some FileStream constructors.

FileMode Parameter
FileMode parameters control whether a file is overwritten, created, or opened, or any combination of those operations. The following table describes constants that are used with the FileMode parameter class.
Constant Open Append Create Description This constant is used to open an existing file. This constant is used to append to a file. This constant is used to create a file if it does not exist.

FileAccess Enumeration
The FileAccess enumeration defines constants for read, write, or read/write access to a file. This enumeration has a FlagsAttribute that allows a bitwise combination of its member values. A FileAccess parameter is specified in many of the constructors for File, FileInfo, and FileStream, and in other class constructors where it is important to control the kind of access that users have to a file.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

FileShare Enumeration
The FileShare enumeration contains constants for controlling the kind of access that other FileStreams can have to the same file. This enumeration has a FlagsAttribute that allows a bitwise combination of its member values. The FileShare enumeration is typically used to define whether two processes can simultaneously read from the same file. For example, if a file is opened and FileShare.Read is specified, other users can open the file for reading but not for writing. FileShare.Write specifies that other users can simultaneously write to the same file. FileShare.None declines sharing of the file. In the following example, a FileStream constructor opens an existing file for read access and allows other users to read the file simultaneously:
FileStream f = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read);

Using the Seek Method for Random Access to Files


FileStream objects support random access to files by using the Seek method. The Seek method allows the read/write position within the file stream to be moved to any position within the file. The read/write position can be moved by using byte offset reference point parameters. The byte offset is relative to the seek reference point, as represented by the three properties of the SeekOrigin class, which are described in the following table.
Property Name Begin Current End Description The seek reference position of the beginning of a stream The seek reference position of the current position within a stream The seek reference position of the end of a stream

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 10: Data Streams and Files

File and FileInfo Class


Topic Objective
To introduce the File and FileInfo classes and demonstrate how they are used to create a new object.
!

File Is a Utility Class with Static Methods Used to:


#

Create, copy, delete, move, and open files Create, copy, delete, move, and open files Can eliminate some security checks when reusing an object. Assign to aStream a newly created file named foo.txt in the current directory

Lead-in
The File and FileInfo classes are utility classes with methods that are primarily used for the creation, copying, deletion, moving, and opening of files.

FileInfo Is a Utility Class with Instance Methods Used to:


# #

Example:
#

FileStream aStream = File.Create("foo.txt"); FileStream aStream = File.Create("foo.txt");

The File and FileInfo classes are utility classes with methods that are primarily used for the creation, copying, deletion, moving, and opening of files. All methods of the File class are static and can therefore be called without having an instance of a file. The FileInfo class contains all instance methods. The static methods of the File class perform security checks on all methods. If you are going to reuse an object several times, consider using the corresponding instance method of FileInfo instead, because the security check will not always be necessary. For example, to create a file named Foo.txt and return a FileStream object, use the following code:
FileStream aStream = File.Create("Foo.txt");

To create a file named Foo.txt and return a StreamWriter object, use the following code:
StreamWriter sw = File.CreateText("Foo.txt");

To open a file named Foo.txt and return a StreamReader object, use the following code:
StreamReader sr = File.OpenText("Foo.txt");

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

11

Reading Text Example


Topic Objective
To provide an example of reading.
!

Read Text from a File and Output It to the Console

Lead-in
In the following example, you read an entire file and are notified when the end of the file is detected.

//... //... StreamReader sr = File.OpenText(FILE_NAME); StreamReader sr = File.OpenText(FILE_NAME); String input; String input; while ((input=sr.ReadLine())!=null) { while ((input=sr.ReadLine())!=null) { Console.WriteLine(input); Console.WriteLine(input); } } Console.WriteLine ( Console.WriteLine ( "The end of the stream has been reached."); "The end of the stream has been reached."); sr.Close(); sr.Close(); //... //...

In the following example of reading text, you read an entire file and are notified when the end of the file is detected.
using System; using System.IO; public class TextFromFile { private const string FILE_NAME = "MyFile.txt"; public static void Main(String[] args) { if (!File.Exists(FILE_NAME)) { Console.WriteLine("{0} does not exist!", FILE_NAME); return; } StreamReader sr = File.OpenText(FILE_NAME); String input; while ((input=sr.ReadLine())!=null) { Console.WriteLine(input); } Console.WriteLine ( "The end of the stream has been reached."); sr.Close(); } }

This code creates a StreamReader object that points to a file named MyFile.txt through a call to File.OpenText. StreamReader.ReadLine returns each line as a string. When there are no more characters to read, a message is displayed to that effect, and the stream is closed.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 10: Data Streams and Files

Writing Text Example


Topic Objective
To provide an example of writing text.
! ! !

Create a File Write a String, an Integer, and a Floating Point Number Close the File

Lead-in
This example creates a new text file that is named MyFile.txt, writes a string, integer, and floating point number to it, and finally closes the file.

//... //... StreamWriter sw = File.CreateText("MyFile.txt"); StreamWriter sw = File.CreateText("MyFile.txt"); sw.WriteLine ("This is my file"); sw.WriteLine ("This is my file"); sw.WriteLine ( sw.WriteLine ( "I can write ints {0} or floats {1}", 1, 4.2); "I can write ints {0} or floats {1}", 1, 4.2); sw.Close(); sw.Close(); //... //...

The following example creates a new text file that is named MyFile.txt, writes a string, integer, and floating-point number to it, and finally closes the file.
using System; using System.IO; public class TextToFile { private const string FILE_NAME = "MyFile.txt"; public static void Main(String[] args) { if (File.Exists(FILE_NAME)) { Console.WriteLine("{0} already exists!", FILE_NAME); return; } StreamWriter sw = File.CreateText(FILE_NAME); sw.WriteLine ("This is my file."); sw.WriteLine ( "I can write ints {0} or floats {1}, and so on.", 1, 4.2); sw.Close(); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

13

Directory and DirectoryInfo Class


Topic Objective
To explain how the Directory and DirectoryInfo classes are used to create directory listings.
!

Directory Has Static Methods Used to:


#

Create, move, and enumerate through directories and subdirectories Create, move, and enumerate through directories and subdirectories Can eliminate some security checks when reusing an object Enumerating through the current directory

DirectoryInfo Has Instance Methods Used to:


#

Lead-in
The Directory and DirectoryInfo classes expose routines for creating, moving, and enumerating through directories and subdirectories.
#

Example:
#

DirectoryInfo dir = new DirectoryInfo("."); DirectoryInfo dir = new DirectoryInfo("."); foreach (FileInfo f in dir.GetFiles("*.cs")) { foreach (FileInfo f in dir.GetFiles("*.cs")) { String name = f.FullName; } String name = f.FullName; }
!

Use Path Class Objects to Process Directory Strings

The Directory and DirectoryInfo classes expose routines for creating, moving, and enumerating through directories and subdirectories. All methods of the Directory class are static and can therefore be called without having an instance of a directory. The DirectoryInfo class contains all instance methods. The static methods of the Directory class do a security check on all methods. If you are going to reuse an object several times, consider using the corresponding instance method of DirectoryInfo instead, because the security check will then not always be necessary. The following example shows how to use the DirectoryInfo class to create a listing of a directory:
using System; using System.IO; class DirectoryLister { public static void Main(String[] args) { DirectoryInfo dir = new DirectoryInfo("."); foreach (FileInfo f in dir.GetFiles("*.cs")) { String name = f.FullName; long size = f.Length; DateTime creationTime = f.CreationTime; Console.WriteLine("{0,-12:N0} {1,-20:g} {2}", size, creationTime, name); } } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 10: Data Streams and Files

In the preceding example, the DirectoryInfo object is the current directory, denoted by ("."). The code lists the names of all of the files in the current directory that have a .cs extension, together with their file size and creation time. Assuming that there are .cs files in the \Bin subdirectory of drive C, the output of this code appears as follows:
953 664 403 7/20/2000 10:42 AM 7/27/2000 3:11 PM 8/8/2000 10:25 AM C:\Bin\paramatt.cs C:\Bin\tst.cs C:\Bin\dirlist.cs

If you want a list of files in another directory, such as C:\, remember to use the backslash (\) escape character, as in the following example:
"C:\\"

Or, use an @-quoted string literal in C#, as in the following example:


@"C:\"

Paths
To processes directory strings in a cross-platform manner, use the Path class. The members of the Path class enable you to quickly and easily perform common operations, such as determining whether a file extension is part of a path, and combining two strings into one path name.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

15

FileSystemWatcher
Topic Objective
To explain how the FileSystemWatcher component can be used to monitor and react to changes in a file system.
! !

FileSystemWatcher Is Used to Monitor a File System Creating a FileSystemWatcher Object

FileSystemWatcher watcher = new FileSystemWatcher(); FileSystemWatcher watcher = new FileSystemWatcher(); ! Configure watcher.Path = args[0]; watcher.Path = args[0]; watcher.Filter = "*.txt"; watcher.Filter = "*.txt"; watcher.NotifyFilter = NotifyFilters.FileName; watcher.NotifyFilter = NotifyFilters.FileName; watcher.Renamed += new watcher.Renamed += new RenamedEventHandler(OnRenamed); RenamedEventHandler(OnRenamed);
!

Lead-in
You use the FileSystemWatcher component to monitor a file system and react when changes to it occur.

Begin Watching

watcher.EnableRaisingEvents = true; watcher.EnableRaisingEvents = true; ! Catch Events


public static void OnRenamed(object s, RenamedEventArgs e) { public static void OnRenamed(object s, RenamedEventArgs e) { Console.WriteLine("File: {0} renamed to {1}", Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath); } e.OldFullPath, e.FullPath); }

You use the FileSystemWatcher component to monitor a file system and react when changes to it occur. By using the FileSystemWatcher component, you can quickly and easily launch business processes when specified files or directories are created, modified, or deleted. For example, if a group of users is collaborating on a document that is stored in a shared directory on a server, you can use the FileSystemWatcher component to easily program your application to watch for changes to the shared directory. When a change is detected, the component can run processing that notifies each user through e-mail. You can configure the component to watch an entire directory and its contents or a specific file or set of files within a given directory. To watch for changes in all files, set the Filter property to an empty string (""). To watch a specific file, set the Filter property to the file name. For example, to watch for changes in the file MyDoc.txt, set the Filter property to "MyDoc.txt". You can also watch for changes in a certain type of file. For example, to watch for changes in text files, set the Filter property to "*.txt". Note Hidden files are not ignored. There are several types of changes you can watch for in a directory or file. For example, you can watch for changes in Attributes, the LastWrite date and time, or the Size of files or directories. This is done by setting the FileSystemWatcher.NotifyFilter property to one of the NotifyFilters values. For more information on the type of changes you can watch, see NotifyFilters in the .NET Framework Software Developers Kit (SDK). You can watch for renaming, deletion, or creation of files or directories. For example, to watch for renaming of text files, set the Filter property to "*.txt" and call one of the WaitForChanged methods with the WatcherChangeTypes value Renamed given.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 10: Data Streams and Files

Creating a FileSystemWatcher Component


The following example creates a FileSystemWatcher component to watch the directory that is specified at run time. The component is set to watch for changes in LastWrite and LastAccess times, and the creation, deletion, or renaming of text files in the directory. If a file is changed, created, or deleted, the path to the file prints to the console. When a file is renamed, the old and new paths print to the console.
using System; using System.IO; public class Watcher { public static void Main(string[] args) { // If a directory is not specified, exit program. if(args.Length != 1) { // Display the proper way to call the program. Console.WriteLine( "Usage: Watcher.exe (directory)"); return; } // Create a new FileSystemWatcher // and set its properties. FileSystemWatcher watcher = new FileSystemWatcher(); watcher.Path = args[0]; /* Watch for changes in LastAccess and LastWrite times, and the renaming of files or directories */ watcher.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName; // Only watch text files. watcher.Filter = "*.txt"; // Add event handlers. // The Changed event occurs when changes are made to // the size, system attributes, last write time, last // access time, or security permissions in a file or // directory in the specified Path of a // FileSystemWatcher. watcher.Changed += new FileSystemEventHandler(OnChanged); // The Created event occurs when a file or directory // in the specified Path of a FileSystemWatcher is // created. watcher.Created += new FileSystemEventHandler(OnChanged);

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files


// The Deleted event occurs when a file or directory // in the specified Path of a FileSystemWatcher is // deleted. watcher.Deleted += new FileSystemEventHandler(OnChanged); // The Deleted event occurs when a file or directory // in the specified Path of a FileSystemWatcher is // deleted. watcher.Renamed += new RenamedEventHandler(OnRenamed); // Begin watching. watcher.EnableRaisingEvents = true; // Wait for the user to quit the program. Console.WriteLine("Press \'q\' to quit the sample."); while(Console.Read()!='q'); } // Define the event handlers. public static void OnChanged( object source, FileSystemEventArgs e) { // Specify what is done when a file is changed, // created, or deleted. Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType); } public static void OnRenamed( object source, RenamedEventArgs e) { // Specify what is done when a file is renamed. Console.WriteLine("File: {0} renamed to {1}", e.OldFullPath, e.FullPath); } }

17

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 10: Data Streams and Files

Isolated Storage
Topic Objective
To introduce isolated storage and its potential uses.
!

Isolated Storage Provides Standardized Ways of Associating Applications with Saved Data Semi-Trusted Web Applications Require:
# #

Lead-in
For some applications, such as downloaded Web applications and code that may come from untrusted sources, the basic file system does not provide the necessary isolation and safety.

Isolation of their data from other applications' data Safe access to a computers file system

System.IO.IsolatedStorage Namespace Contains:

public sealed class IsolatedStorageFile : IsolatedStorage, IDisposable public sealed class IsolatedStorageFile : IsolatedStorage, IDisposable

public class IsolatedStorageFileStream : FileStream public class IsolatedStorageFileStream : FileStream

Basic file I/O functionality, found in the System.IO root, provides the ability to access, store, and manipulate data that is stored in hierarchical file systems whose files are referenced by using unique paths. For some applications, such as downloaded Web applications and code that may come from un-trusted sources, the basic file system does not provide the necessary isolation and safety. Isolated storage is a data storage mechanism that provides isolation and safety by defining standardized ways of associating code with saved data.

Isolation
When an application stores data in a file, the file name and storage location must be carefully chosen to minimize the possibility that the storage location will be known to another application and, therefore, vulnerable to corruption. Isolated storage provides the means to manage downloaded Web applications files to minimize storage conflicts.

Security Risks of Semi-Trusted Code


It is important to restrict semi-trusted codes access from a computer's file system. Allowing code that has been downloaded and run from the Internet to have access to I/O functions leaves a system vulnerable to viruses and unintentional damage. The security risks associated with file access are sometimes addressed by using access control lists (ACLs), which restrict the access that users have to files. However, this approach is often not feasible with Web applications because it requires administrators to configure ACLs on all of the systems on which the application will run.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

19

Safety Through Isolated Storage


Administrators can use tools that are designed to manipulate isolated storage to configure file storage space, set security policies, and delete unused data. With isolated storage, code no longer needs to invent unique paths to specify safe locations in the file system, while data is protected from unauthorized access. There is no need for hard coding of information that indicates where an applications storage area is located. With isolated storage, partially trusted applications can store data in a manner that is controlled by the computers security policy. Security policies rarely grant permission to access the file system by using standard I/O mechanisms. However, by default, code that runs from a local computer, a local network, or the Internet is granted the right to use isolated storage. Web applications can also use isolated storage with roaming user profiles, thereby allowing a users isolated stores to roam with their profile. The namespace System.IO.IsolatedStorage contains the IsolatedStorageFile and IsolatedStorageFileStream classes, which applications can use to access the files and directory in their isolated storage area. Further discussion of isolated storage is beyond the scope of this course.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 10: Data Streams and Files

Lab 10: Files


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will create an application that reads and writes characters to and from files, and create an application that can use StringReader and StreamReader objects to read character data from either files or strings.

Objectives
After completing this lab, you will be able to:
!" !"

Create an application that reads and writes characters to and from files. Create an application that can use StringReader and StreamReader objects to read character data from files or strings.

Lab Setup
Starter and solution files are associated with this lab. The starter files are in the folder <install folder>\Labs\Lab10\Starter, and the solution files are in the folder <install folder>\Labs\Lab10\Solution.

Scenario
In this lab, you are provided with a Microsoft Visual Studio .NET console application as a starting point. The application, named Files, opens one or more files, which are specified on the command line, and counts each files bytes, characters, words, and lines. The results from each file and the total of all files are displayed on the console. The application supports an f switch to allow the output display to be redirected to a file and a t switch to run a special test mode of operation where input is obtained from a coded-in test string, instead of from user-specified files. The application is based on a slightly modified version of the .NET Framework SDK sample, Word Count.

Estimated time to complete this lab: 45 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

21

Exercise 1 Reading and Writing Files and Strings


In this exercise, you will modify the Files application to output to a specified file.

!" examine the application To


1. In Visual Studio .NET, open the Files project, which is located in <install folder>\Labs\Lab10\Starter\Files. 2. Open the WordCount.cs file and examine the code. Pay attention to those methods that you will be modifying: The Main method of the Application class and the CountStats method of the WordCounter class. 3. Build the WordCount application. 4. Set the applications command line arguments by performing the following steps: a. If the Solution Explorer pane in the Visual Studio .NET window is not visible, on the View menu, click Solution Explorer. b. In the Solution Explorer pane, right-click Files to display the contextsensitive menu, and then click Properties. c. In the Files Property Pages dialog box, click the Configuration Properties folder, and then click Debugging. d. In the right pane under Start Options, set the command line arguments, as follows:
-a -o -t -foutput.txt test.txt

5. View the WordCount.cs file, and locate the last line in Applications Main method, which is:
return 0;

6. Right-click on this line, and select Run To Cursor. In the console window, you should see the following text:
Replace this Console.WriteLine in Application's Main! method with code as per the lab Lines Words Chars Bytes Pathname Replace this Console.WriteLine in WordCounter's! CountStats method 0 0 0 0 Test String ------------------------------------0 0 0 0 Total in all files Word usage sorted alphabetically (0 unique words) Word usage sorted by occurrence (0 unique words)

7. Stop debugging, and in the Main method code of the Application class, locate the following line of code:
if (ap.OutputFile != null) {

If ap.OutputFile does not contain null, then it contains the name of the output file that is specified in the f command line switch.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 10: Data Streams and Files

8. Replace the following lines Console.WriteLine call with code that: a. Assigns fsOut to a FileStream object that creates a file with the specified name with Write access and no file sharing. b. Assigns sw to a StreamWriter object that is bound to the FileStream object created in step a. c. Redirects the consoles output to the file by associating the StreamWriter object with the console by using the following command:
Console.SetOut(sw);

9. Rebuild and run the application, and examine the output file that is specified in the command line switch options. The file should be located in the bin\Debug subdirectory. It should contain the following text:
Lines Words Chars Bytes Pathname Replace this Console.WriteLine in WordCounter's! CountStats method 0 0 0 0 Test String ----- ----- ----- ----- --------------------0 0 0 0 Total in all files Word usage sorted alphabetically (0 unique words) Word usage sorted by occurrence (0 unique words)

!" add the test mode and normal mode CountStats processing To
1. Locate the following lines in the CountStats method code of the WordCounter class:
Boolean Ok = true; numLines = numWords = numChars = numBytes = 0; try {

If the t option has been set, the CountStats caller will have set the pathname parameter to the empty string, which is called String.Empty. 2. Replace the following lines Console.WriteLine call with code that: a. Declares a variable of type TextReader and names it tr. You use the type TextReader because it is the common base type for both StringReader and StreamReader. Polymorphism will allow code that uses a TextReader object to be provided with either a StringReader or StreamReader object. b. If the pathname is empty: i. Create a StringReader that is named sr, which is bound to a member of WordCounter that is named testString. ii. Assign the number of bytes in this string to numBytes. iii. Assign sr to tr. This assignment does an implicit cast of a StringReader to a TextReader.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

23

c. If the pathname is not empty: i. Create a FileStream that is named fsIn by opening the file that is specified in the parameter pathname with read access and shared read access. ii. Assign the number of bytes in fsIn to numBytes. iii. Create a StreamReader that is named sr that is bound to this file. iv. Assign sr to tr. This assignment does an implicit cast of a StreamReader to a TextReader d. In this module, uncomment out the for loop that follows the comment:
// Process every line in the file

e. Following the for loop, add code to close the TextReader object. 3. Rebuild and run the application, and examine the output file in the bin\Debug subdirectory. It should contain the following text:
Lines Words Chars Bytes Pathname 2 3 16 17 Test String ----- ----- ----- ----- --------------------2 3 16 17 Total in all files Word usage sorted alphabetically (2 unique words) 2: "hello" 1: "world" Word usage sorted by occurrence (2 unique words) 1: world 2: hello

4. Change the command line options that Visual Studio .NET will use to run the application to remove the test switch. It should be set to:
-a -o -foutput.txt test.txt

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 10: Data Streams and Files

5. Run the application, and examine the output file in the bin\Debug subdirectory. It should contain the following text:
Lines Words Chars Bytes Pathname 5 16 65 73 ...\test.txt ----- ----- ----- ----- --------------------5 16 65 73 Total in all files Word usage sorted alphabetically (14 unique words) 1: "aid" 1: "all" 1: "come" 1: "country" 1: "for" 1: "good" 1: "is" 1: "men" 1: "now" 1: "of" 2: "the" 1: "their" 1: "time" 2: "to" Word usage sorted by occurrence (14 unique words) 1: aid 1: all 1: come 1: country 1: for 1: good 1: is 1: men 1: now 1: of 1: their 1: time 2: the 2: to

6. Examine the file Test.txt in the bin\Debug subdirectory, and verify that the output is what you expected.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 10: Data Streams and Files

25

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! ! !

Streams Readers and Writers Basic File I/O

Lead-in
The review questions cover some of the key concepts taught in the module.

1. Name at least three types of .NET Framework streams and how they differ. FileStream does reads and writes to a file. MemoryStream does reads and writes to memory. BufferedStream is used to buffer reads and writes to another stream. NetworkStream provides the underlying stream of data for network access.

2. Name the three basic stream operations. Read, Write, and Seek.

3. Name the classes that are used to read and write primitive types as binary values. BinaryReader and BinaryWriter.

4. Name the method used to provide random access to files. Seek.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 10: Data Streams and Files

5. Name the class that you would use to monitor changes to a file system. FileSystemWatcher.

6. Name the two important features that the .NET Frameworks isolated storage provides for an application. Isolation and Safety.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access


Contents Overview Internet Application Scenarios The WebRequest and WebResponse Model Application Protocols Handling Errors Security Lab 11: Creating a DateTime Client/Server Application Review 1 2 3 16 25 28 36 40

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

iii

Instructor Notes Module 11


Presentation: 60 Minutes Lab: 45 Minutes After completing this module, students will be able to:
!"

Use the basic request/response model to send and receive data over the Internet. Use the System.Net classes to communicate with other applications by using the HTTP, Transmission Control Protocol (TCP), User Datagram Protocol (UDP), and Socket Internet protocols.

!"

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_11.ppt

Preparation Tasks
To prepare for this module, you should:
!" !"

Read all of the materials for this module. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 11: Internet Access

Module Strategy
Use the following strategy to present this module:
!"

Internet Application Scenarios Briefly introduce examples of Internet applications that use the System.Net classes, including server-side ASP.NET applications, peer-to-peer Windows Forms applications that act as servers and clients to send and receive data, and client applications that periodically access the network for updates.

!"

The WebRequest and WebResponse Model Introduce the WebRequest and WebResponse model. Explain how the Microsoft .NET Framework uses the Uniform Resource Identifier (URI) to identify the desired communication protocol and Internet resource. Discuss network streams as the means of obtaining and receiving Web data. Explain how to use the WebRequest class to request data from a server, invoke the request for the Internet resource, and send data through a network stream. Discuss how the WebResponse.GetResponseStream method serves as the means of obtaining a stream that contains response data from a network resource.

!"

Application Protocols Discuss the HTTP, TCP, and UDP protocol support that is provided in the .NET Framework, as well as information about using the Windows Sockets interface to implement custom protocols.

!"

Handling Errors Discuss how the WebRequest and WebResponse classes can throw system exceptions, such as InvalidArgumentException, and Web-specific exceptions, which are instances of WebException and thrown by the GetResponse method.

!"

Security Explain how an application can provide security for sending and receiving data over the Internet by using a Web proxy, Secure Sockets Layer (SSL) encryption, Internet authentication, and the NET Frameworks code access permissions.

!"

Best Practices Briefly outline the list of recommendations that will help students use the classes that are contained in System.Net more effectively.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! ! ! ! ! !

Internet Application Scenarios The WebRequest and WebResponse Model Application Protocols Handling Errors Security Best Practices

Lead-in
In this module, you will learn about the basic request/response model that is used to send and receive data over the Internet, the System.Net classes that are used to communicate with other applications, and various techniques to enhance application security and performance.

The Microsoft .NET Frameworks System.Net and System.Net.Sockets namespaces provide a layered, extensible, and managed implementation of Internet protocols that applications can use to send or receive data over the Internet. The System.Net classes provide functionality that is similar to Microsofts WinInet API. These classes provide varying levels of detail, from a generic request/response model to fine-grained control over application protocols and sockets. In particular, the System.Net classes are designed for writing scaleable, high-performance applications. An application can use the System.Net classes to communicate with any other application that supports the basic Internet protocols. However, that other application need not be a .NET application. The .NET Framework provides alternative mechanisms for inter-application communication. For example, .NET Framework remoting implements a generic mechanism for .NET Framework objects to interact with one another across application domains. In addition, the System.Web.Services namespace contains classes for applications to build and use Web Services that are based on the standard Simple Object Access Protocol (SOAP). For more information about the remoting and Web Services approaches to inter-application communication, see Module 12, Serialization, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease). After completing this module, you will be able to:
!"

Use the basic request/response model to send and receive data over the Internet. Use the System.Net classes to communicate with other applications by using the Hypertext Transfer Protocol (HTTP), Transmission Control Protocol (TCP), User Datagram Protocol (UDP), and Socket Internet protocols.

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

Internet Application Scenarios


Topic Objective
To introduce Internet application scenarios that use the System.Net classes.
!

Server-Side ASP.NET Applications


#

Lead-in
Several types of applications use the System.Net classes to send or receive data over the Internet.
!

Obtain data from back-end sources for a browser request Send and receive data by acting as servers and clients A robust implementation of HTTP 1.1, including: Pipelining, chunking, authentication, pre-authentication, encryption, proxy support, server certificate validation, and connection management

Peer-to-Peer Applications
#

Client Applications That Periodically Access the Network


#

Several types of applications use the System.Net classes to send or receive data over the Internet. The following three Internet application scenarios are examples of Internet applications that use the System.Net classes:
!"

Server-side ASP.NET applications that request data from server resources in response to a browser request. The System.Net classes are designed for writing scalable, high-performance ASP.NET middle-tier applications. The server-side ASP.NET scenario requires a robust middle-tier networking stack that can tolerate a high load. The System.Net classes specifically fulfill this important customer requirement. Such features as connection management, pipelining, Keepalive, and asynchronous operations ensure strong support for the middle tier. In addition, because the System.Net classes are part of an overall framework, integration with ASP.NET features, such as impersonation and caching, is seamless.

!"

Peer-to-peer Windows Forms applications that act as servers and clients to send and receive data. Client applications that periodically access the network for updates. The System.Net classes expose a robust implementation of the HTTP protocol. Because a large share of Internet traffic travels over the HTTP protocol, the protocols importance as an application protocol is significant. The System.Net classes support most of the HTTP 1.1 protocol features. The advanced features of HTTP 1.1 include pipelining, chunking, authentication, pre-authentication, encryption, proxy support, server certificate validation, connection management, and HTTP extensions.

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

$ The WebRequest and WebResponse Model


Topic Objective
To introduce the topics in the section.
! ! ! ! ! ! !

Lead-in
Internet applications can be classed broadly into two types: client applications that request information, and server applications that respond to information requests from clients.

Uniform Resource Identifier NetworkStream Class Creating a WebRequest Invoking a WebRequest Sending Data Receiving Data Using the WebRequest and WebResponse Model

Internet applications can be classed broadly into two types: client applications that request information, and server applications that respond to information requests from clients. The classic Internet client/server application is the World Wide Web, where people use browsers to access documents and other data that is stored on Web servers worldwide. Applications are not limited to playing either the client or server role; the familiar middle-tier application server responds to requests from clients by requesting data from another server. In this case, it is acting as both a server and a client. The client application makes a request by identifying the desired Internet resource and the communication protocol that will be used to exchange the request and response. If necessary, the client application also specifies any additional data that is required to complete the request, such as proxy location or authentication information. Authentication information includes such information as user name and password. When the request is formed, it can be sent to the server. After the server has received the request and processed the response, the response is returned to the client application. The response includes information that supplements the contents of the response, such as the type of content, which may include raw text or XML data. The .NET Framework provides classes that can be used to implement a request/response model to access Internet resources. The two principal classes are the WebRequest class, which contains a request for the resource; and the WebResponse class, which provides a container for the incoming response. In addition, the Uri class is used to contain a Uniform Resource Identifier (URI), which identifies the Internet resource that you are seeking. The NetworkStream class is used to write and read the data.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

Note A URI is a compact representation of a resource that is available to your application through the Internet. You may be more familiar with the term, URL, which stands for Uniform Resource Locator. URLs form a subset of the more general URI naming scheme. A URL identifies an Internet resource that has a Web page address. For applications that need to make simple requests for Internet resources, the WebClient class provides common methods for uploading data to or downloading data from an Internet server. WebClient relies on the WebRequest class to provide access to Internet resources; therefore, the WebClient class can use any registered pluggable protocol.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

Uniform Resource Identifier


Topic Objective
To introduce the four parts of the URI.
!

URI Contains:
# # # #

Lead-in
The .NET Framework uses the URI to identify the desired communication protocol and Internet resource.

Scheme identifier specifies protocol to be used Server identifier specifies DNS name or TCP address Path identifier specifies location on the server Optional query string provides additional request information Scheme identifier http Server identifier www.contoso.com Path identifier /whatsnew.aspx Query String ?date=today

Example: http://www.contoso.com/whatsnew.aspx?date=today
# # # #

The .NET Framework uses the URI to identify the desired communication protocol and Internet resource. The URI consists of at least three, and possibly four, parts:
!"

The scheme identifier, which identifies the communications protocol that is used by the request and response The server identifier, which consists of a Domain Name System (DNS) host name or TCP address that uniquely identifies the server on the Internet The path identifier, which locates the requested information on the server An optional query string, which passes information from the client to the server

!"

!" !"

For example, the URI http://www.contoso.com/whatsnew.aspx?date=today consists of the scheme identifier http, the server identifier www.contoso.com, the path identifier /whatsnew.aspx, and the query string ?date=today.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

NetworkStream Class
Topic Objective
To explain the function of Network streams in the .NET Framework.
!

A NetworkStream Object Provides:


# # #

A Way to Send and Receive All Types of Web Data Methods That Are Compatible with Other .NET Streams Processing of Data As It Arrives

Lead-in
When resources on the Internet are obtained by using the System.Net classes, the data that is being sent and received is represented through a Stream object.
!

System.Text.Encoding Characters from and to Bytes

// reading ASCII stream to string // reading ASCII stream to string Byte[] read = new Byte[32]; Byte[] read = new Byte[32]; int bytes = anASCIIStream1.Read(read, 0, read.Length); int bytes = anASCIIStream1.Read(read, 0, read.Length); string stringData = Encoding.ASCII.GetString(read); string stringData = Encoding.ASCII.GetString(read); // writing string to ASCII stream // writing string to ASCII stream Byte[] asciiBytes = Encoding.ASCII.GetBytes(stringData); Byte[] asciiBytes = Encoding.ASCII.GetBytes(stringData); anASCIIStream2.Write(asciiBytes, asciiBytes.Length, 0); anASCIIStream2.Write(asciiBytes, asciiBytes.Length, 0);
!

Sequential Blocks Use StreamReader and StreamWriter

When resources on the Internet are obtained by using the System.Net classes, a Stream object represents the data that is being sent and received. Streams provide:
!"

A common way to send and receive Web data. Whether the actual contents of the file are HTML, XML, or another format, an application uses Stream.Write and Stream.Read to send and receive byte data.

!"

Compatibility with streams across the .NET Framework. Streams are used throughout the .NET Framework, which provides a rich infrastructure for handling them. For example, by changing only the few lines of code that initialize the stream, you can modify an application that reads XML data from a file stream to read data from a network stream instead. The major differences between the NetworkStream class and other streams are that the NetworkStream class is not seekable, the CanSeek property always returns false, and the Seek and Position methods throw a NotSupportedException.

!"

Processing of data as it arrives. Streams provide access to data as it arrives from the Internet, rather than forcing your application to wait for an entire data set to be downloaded.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

Conversion Between Characters and Bytes


The System.Text namespace contains classes for converting blocks of characters to and from blocks of bytes. In particular, the Encoding class has methods to convert arrays and strings of Unicode characters to and from arrays of bytes, as in the following example:
// variable named anASCIIStream1 of type Stream // has been previously assigned to a Stream // containing bytes representing 7 bit ASCII character // // reading ASCII stream and converting to string Byte[] read = new Byte[32]; int bytes = anASCIIStream1.Read(read, 0, read.Length); string stringData = Encoding.ASCII.GetString(read); // ... // variable named anASCIIStream2 of type Stream // has been previously assigned to a writable Stream // // converting string and writing 7 bit ASCII characters Byte[] asciiBytes = Encoding.ASCII.GetBytes(stringData); AnASCIIStream2.Write(asciiBytes, asciiBytes.Length, 0);

Converting Data from Sequential Blocks


When the data that must be converted is only available in sequential blocks, such as data that is read from a long stream, an application may choose to use a decoder or an encoder to perform the conversion. However, you can use the StreamReader and StreamWriter classes to facilitate decoding and encoding characters, as in the following example:
// variable anASCIIStream has been previously assigned // to a Stream of ASCII bytes StreamReader sr = new StreamReader( anASCIIStream,Encoding.ASCII); int length = 1024; char[] Buffer = new char[1024]; int bytesread = 0; //Read from the stream and write data to console bytesread = sr.Read( Buffer, 0, length); while( bytesread > 0 ) { Console.Write( Buffer,0, bytesread); bytesread = sr.Read( Buffer, 0, length); } //Close the stream when finished sr.Close();

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

Creating a WebRequest
Topic Objective
To describe how client applications use the WebRequest.
!

The WebRequest Encapsulates Details of Request


#

Created by calling WebRequest.Create method Set any property values that are required Cast to access protocol-specific features

Lead-in
Client applications request data from servers by using the WebRequest class and its descendents.

WebRequest req = WebRequest req = WebRequest.Create("http://www.contoso.com/"); WebRequest.Create("http://www.contoso.com/");


#

req.Credentials = new req.Credentials = new NetworkCredential("username","password"); NetworkCredential("username","password");


#

HttpWebRequest httpReq = (HttpWebRequest) HttpWebRequest httpReq = (HttpWebRequest) WebRequest.Create("http://www.contoso.com/"); WebRequest.Create("http://www.contoso.com/"); // Turn off connection keep-alives. // Turn off connection keep-alives. httpReq.KeepAlive = false; httpReq.KeepAlive = false;

Client applications request data from servers by using the WebRequest class and its descendents. The WebRequest class encapsulates the details of the process of connecting to the server, sending the request, and receiving the response.

Calling WebRequest.Create
Applications create WebRequest instances through the static WebRequest.Create method. WebRequest.Create is a static method that creates a descendent WebRequest instance that is based on the URI scheme that is passed. For example, the following code creates an HTTP request to www.contoso.com:
WebRequest req = WebRequest.Create("http://www.contoso.com/");

Setting Required Property Values


Clients set required property values in the WebRequest instance. For example, to support authentication, you can set the Credentials property to an instance of the NetworkCredential class, as shown in the following code:
req.Credentials = new NetworkCredential("username","password");

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

Casting WebRequest Objects to HttpWebRequest


To handle HTTP protocol requests to the Internet, the .NET Framework provides an HttpWebRequest class that is derived from the WebRequest class. In most cases, the WebRequest class provides all of the properties that you need to make a request. However, if you need to access the HTTP protocolspecific properties of the request, you can typecast WebRequest objects that are created by the WebRequest.Create to HttpWebRequest, as in the following example:
HttpWebRequest httpReq = (HttpWebRequest) WebRequest.Create("http://www.contoso.com/"); // Turn off connection keep-alives. httpReq.KeepAlive = false;

Supporting Additional Protocols


The .NET Framework provides protocol-specific WebRequest and WebResponse descendants for URIs that begin with http:, https:, and file. The programmable pluggable protocols of System.Net allow applications to provide access through other protocols. To support additional protocols, you should implement protocol-specific descendants of WebRequest and WebResponse and register the descendants constructor with the WebRequest.RegisterPrefix method. For more information about supporting additional protocols, see the .NET Framework Software Developers Kit (SDK) documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 11: Internet Access

Invoking a WebRequest
Topic Objective
To explain how to invoke the request for an Internet resource by calling the GetResponse method on the WebRequest instance.
!

Request Is Made by Calling the GetResponse Method

Lead-in
After creating the WebRequest, you invoke the request for the Internet resource by calling the GetResponse method on the WebRequest instance.

WebResponse resp = req.GetResponse(); WebResponse resp = req.GetResponse();

Cast to access HTTP-specific features

HttpWebResponse httpResp = HttpWebResponse httpResp = (HttpWebResponse)httpReq.GetResponse(); (HttpWebResponse)httpReq.GetResponse(); //Get the HTTP content length returned by the server. //Get the HTTP content length returned by the server. String contentLength = String contentLength = httpResp.ContentLength.ToString(); httpResp.ContentLength.ToString();

After creating the WebRequest, you invoke the request for the Internet resource by calling the GetResponse method on the WebRequest instance. The GetResponse method is responsible for:
!"

Constructing the protocol-specific request from the properties of the WebRequest instance. Making the TCP or UDP socket connection to the server. Sending the request.

!" !"

The GetResponse method returns an instance that is derived from WebResponse that matches the instance that is derived from WebRequest, as in the following example:
WebResponse resp = req.GetResponse();

The WebResponse class is also an abstract class that defines properties and methods that are available to all applications that use pluggable protocols. WebResponse descendents are responsible for implementing these properties and methods for the underlying protocol. For example, the HttpWebResponse class implements the WebResponse class for the HTTP protocol. If you need to access the HTTP protocol-specific properties of the response, you can typecast WebResponse objects to HttpWebResponse, as in the following example:
HttpWebResponse httpResp = (HttpWebResponse)httpReq.GetResponse(); //Get the HTTP content length returned by the server. String contentLength = httpResp.ContentLength.ToString();

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

11

Sending Data
Topic Objective
To describe how requests that send data to the server are created.
!

For Requests That Send Data to the Server

Lead-in
For requests that send data to the server, such as HTTP-POST or FTP-PUT requests, the data is sent through a network stream that is provided by the WebRequest.GetRequestS tream method.

// ... // ... try try { { byte[] sendData = byte[] sendData = Encoding.ASCII.GetBytes("some data"); Encoding.ASCII.GetBytes("some data"); int sendLength = sendData.Length; int sendLength = sendData.Length; HttpWebRequest httpReq = HttpWebRequest httpReq = (HttpWebRequest) WebRequest.Create( (HttpWebRequest) WebRequest.Create( "http://www.contoso.com/"); "http://www.contoso.com/"); httpReq.Method = "POST"; httpReq.Method = "POST"; httpReq.ContentLength = sendLength; httpReq.ContentLength = sendLength; Stream sendStream = httpReq.GetRequestStream(); Stream sendStream = httpReq.GetRequestStream(); sendStream.Write(sendData,0,sendLength); sendStream.Write(sendData,0,sendLength); sendStream.Close(); sendStream.Close(); } } catch(Exception e) {//...} //... catch(Exception e) {//...} //...

For requests that send data to the server, such as HTTP-POST or FTP-PUT requests, the data is sent through a network stream that is provided by the WebRequest.GetRequestStream method. You use the resulting Stream object to write the data. When you have finished uploading, you must close the request stream with the Stream.Close method. The following example shows how to create a request that uses HTTP-POST to send data to the server:
// ... try { byte[] sendData = Encoding.ASCII.GetBytes("some data"); int sendLength = sendData.Length; HttpWebRequest httpReq = (HttpWebRequest) WebRequest.Create( "http://www.contoso.com/"); httpReq.Method = "POST"; httpReq.ContentLength = sendLength; Stream sendStream = httpReq.GetRequestStream(); sendStream.Write(sendData,0,sendLength); sendStream.Close(); } catch(Exception e) {//... } //...

After closing the stream, you can call GetResponse to ensure that the server received the data correctly.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 11: Internet Access

Receiving Data
Topic Objective
To explain how to obtain the stream that contains response data from the network.
!

Reading Response Data

Lead-in
To obtain the stream that contains response data from the network resource, use the GetResponseStream method of the WebResponse instance.

// Get the response stream. // Get the response stream. Stream respstrm = resp.GetResponseStream(); Stream respstrm = resp.GetResponseStream(); // Create a buffer to hold the response data. // Create a buffer to hold the response data. int BufferSize = 512; int BufferSize = 512; Byte[] Buffer = new Byte[BufferSize]; Byte[] Buffer = new Byte[BufferSize]; // Read the stream to access the data. // Read the stream to access the data. int bytesRead = respstrm.Read(Buffer, 0, BufferSize); int bytesRead = respstrm.Read(Buffer, 0, BufferSize); while (bytesRead > 0) { while (bytesRead > 0) { Console.Write( Console.Write( Encoding.ASCII.GetString(Buffer, 0, bytesRead)); Encoding.ASCII.GetString(Buffer, 0, bytesRead)); bytesRead = respstrm.Read(Buffer, 0, BufferSize); bytesRead = respstrm.Read(Buffer, 0, BufferSize); } } respstrm.Close(); respstrm.Close();

To obtain the stream that contains response data from the network resource, use the GetResponseStream method of the WebResponse instance, as in the following example:
// Get the response stream. Stream respstrm = resp.GetResponseStream(); // Create a buffer to hold the response data. int BufferSize = 512; Byte[] Buffer = new Byte[BufferSize]; // Read the stream to access the data. int bytesRead = respstrm.Read(Buffer, 0, BufferSize); while (bytesRead > 0) { Console.Write( Encoding.ASCII.GetString(Buffer, 0, bytesRead)); bytesRead = respstrm.Read(Buffer, 0, BufferSize); } respstrm.Close();

If your application requires only the header information that is returned in the WebResponse and ignores any returned data, then you do not need to get the response stream.

Closing Responses
After reading the data from the response, you must close any opened stream by using the Stream.Close method or close the response by using the WebResponse.Close method, as in the following example:
resp.Close();

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

13

You do not have to call the Close method on both the response stream and the WebResponse instance, but it is recommended. WebResponse.Close calls Stream.Close when it closes the response. If you do not close each response, your application will run out of connections to the server and be unable to process additional requests.

Considerations for Working with NetworkStreams


When using streams from network resources, remember the following:
!"

Because the NetworkStream class cannot change position in the stream, the CanSeek property always returns false. The Seek and Position methods throw a NotSupportedException. When you use WebRequest and WebResponse, stream instances that are created by calling GetResponseStream are read-only, and stream instances that are created by calling GetRequestStream are write-only. The call to GetResponse may block if network resources are not available. You should consider using an asynchronous request with the BeginGetResponse and EndGetResponse methods.

!"

!"

!"

The call to GetRequestStream may block while the connection to the server is created. You should consider using an asynchronous request for the stream with the BeginGetRequestStream and EndGetRequestStream methods. Asynchronous operations are beyond the scope of this course.

!"

You can use the StreamReader class to make the task of encoding easier. The following code example uses a StreamReader to read an ASCIIencoded stream from a WebResponse instance. The creation of the request is not shown.
// Create a response object. WebResponse response = request.GetResponse(); // Get a readable stream from the server. StreamReader sr = new StreamReader( response.GetResponseStream(), Encoding.ASCII); // Use the stream. Remember when you are through // with the stream to close //... sr.Close();

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 11: Internet Access

Using the WebRequest and WebResponse Model


Topic Objective
To provide an example of the WebRequest and WebResponse model.
//... //... WebRequest wReq = WebRequest.Create WebRequest wReq = WebRequest.Create ("http://localhost/postinfo.html"); ("http://localhost/postinfo.html"); WebResponse wResp = wReq.GetResponse(); WebResponse wResp = wReq.GetResponse(); // Get a readable stream from the server // Get a readable stream from the server StreamReader sr = new StreamReader( StreamReader sr = new StreamReader( wResp.GetResponseStream(),Encoding.ASCII); wResp.GetResponseStream(),Encoding.ASCII); int length = 1024; int length = 1024; char[] Buffer = new char[1024]; char[] Buffer = new char[1024]; int bytesread = 0; int bytesread = 0; //Read from the stream and write data to console //Read from the stream and write data to console bytesread = sr.Read( Buffer, 0, length); bytesread = sr.Read( Buffer, 0, length); while( bytesread > 0 ) { while( bytesread > 0 ) { Console.Write( Buffer,0, bytesread); Console.Write( Buffer,0, bytesread); bytesread = sr.Read( Buffer, 0, length); bytesread = sr.Read( Buffer, 0, length); } } //Close the stream when finished //Close the stream when finished sr.Close(); sr.Close(); //... //...

Lead-in
You will now see an example of the use of the WebRequest and WebResponse model as discussed in this section.

The following code example fully demonstrates the use of the WebRequest and WebResponse model as discussed in this section:
using using using using System; System.Net; System.IO; System.Text;

class App { public static void Main(string[] args) { try { WebRequest wReq = WebRequest.Create ("http://localhost/postinfo.html"); WebResponse wResp = wReq.GetResponse(); // Get a readable stream from the server StreamReader sr = new StreamReader( wResp.GetResponseStream(),Encoding.ASCII); int length = 1024; char[] Buffer = new char[1024]; int bytesread = 0; //Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access


//Read from the stream and write data to console bytesread = sr.Read( Buffer, 0, length); while( bytesread > 0 ) { Console.Write( Buffer,0, bytesread); bytesread = sr.Read( Buffer, 0, length); } //Close the stream when finished sr.Close(); } catch(Exception e) { Console.WriteLine( "\r\nThe request URI could not be found or was! malformed:\n {0}", e.ToString()); } } }

15

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 11: Internet Access

$ Application Protocols
Topic Objective
To introduce the topics in the section.
! ! ! !

Lead-in
The .NET Framework supports application protocols that are currently in common use on the Internet.

HTTP Internet Domain Name System TCP and UDP Sockets

The .NET Framework supports application protocols that are currently in common use on the Internet. This section provides information about using the HTTP, TCP, and UDP protocol support that is provided in the .NET Framework, as well as information about using the Windows Sockets interface to implement custom protocols.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

17

HTTP
Topic Objective
To describe the support that the .NET Framework provides for the HTTP protocol.
!

Classes That Provide HTTP and HTTPS Protocols


#

Lead-in
With the HttpWebRequest and HttpWebResponse classes, the .NET Framework provides comprehensive support for the HTTP protocol, which makes up the majority of all Internet traffic.
! !

HttpWebRequest and HttpWebResponse

Support Most HTTP 1.1 features HTTP Redirects Automatically if AllowAutoRedirect Property Is true (the Default) Use ServicePoint, ServicePointManager, and ConnectGroupName Classes to Manage Connections

With the HttpWebRequest and HttpWebResponse classes, the .NET Framework provides comprehensive support for the HTTP protocol, which makes up the majority of all Internet traffic.

Classes for the HTTP and HTTPS Protocols


The HttpWebRequest and HttpWebResponse classes are derived from the WebRequest and WebResponse classes, as was described in Creating a WebRequest in this module. HttpWebRequest and HttpWebResponse are returned by default whenever the static method WebRequest.Create encounters a URI that begins with http or https. In most cases, the WebRequest and WebResponse classes provide all that is necessary to make the request, but if you need access to the HTTP-specific features that are exposed as properties, you can typecast these classes to HttpWebRequest or HttpWebResponse, as demonstrated in Creating a WebRequest in this module. Note Do not use the HttpWebRequest constructor. Use the WebRequest.Create method to initialize new HttpWebRequest instances. If the scheme for the URI is http:// or https://, Create returns an HttpWebRequest instance.

Support for HTTP 1.1 Features


The HttpWebRequest and HttpWebResponse classes encapsulate a standard HTTP request/response transaction and provide access to common HTTP headers. These classes also support most HTTP 1.1 features, including pipelining, chunking, authentication, pre-authentication, encryption, proxy support, server certificate validation, and connection management. Custom headers and headers that are not provided through properties can be stored in and accessed through the Headers property.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 11: Internet Access

Support for HTTP Redirects


You can make your application follow HTTP redirects automatically by setting the AllowAutoRedirect property to true, which is the default value. The application redirects requests, and the ResponseURI property of HttpWebResponse contains the actual Internet resource that responds to the request. If you set AllowAutoRedirect to false, your application must be able to handle redirects as HTTP protocol errors. Applications receive HTTP protocol errors by catching a WebException with the value of the Status property set to WebExceptionStatus.ProtocolError. The Response property contains the WebResponse that is sent by the server and indicates the actual HTTP error that is encountered.

Managing Internet Connections


Applications that use HTTP to connect to data resources can use the .NET Frameworks ServicePoint and ServicePointManager classes to manage the number of connections to the Internet and to optimize scale and performance. The number of connections between a client and server can have a dramatic impact on application throughput. You can use ConnectGroupName to form connection grouping that associates specific requests within a single application to a defined connection pool. You may have to use this technique with a middle-tier application that connects to a back-end server on behalf of a user and uses an authentication protocol that supports delegation, such as Kerberos, or by a middle-tier application that supplies its own credentials. For more information about classes that are used to manage connections and their methods, see the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

19

Internet Domain Name System


Topic Objective
To explain how to use the Dns class to retrieve information about a host.
!

Dns Class Retrieves Data About a Host from DNS


#

Lead-in
The Dns class is a static class that retrieves information about a specific host from the Internet Domain Name System.

GetHostByName query for www.contoso.com

IPHostEntry hostInfo = IPHostEntry hostInfo = Dns.GetHostByName("www.contoso.com"); Dns.GetHostByName("www.contoso.com");


#

Resolve query for www.contoso.com

IPHostEntry hostInfo = IPHostEntry hostInfo = Dns.Resolve("www.contoso.com"); Dns.Resolve("www.contoso.com");

The Dns class is a static class that retrieves information about a specific host from the Internet Domain Name System (DNS). The host information from a GetHostByName query is returned in an instance of the IPHostEntry class. If the specified host has more than one entry in the DNS database, IPHostEntry contains multiple Internet Protocol (IP) addresses and aliases. The following example queries the DNS database for information about a host that is called www.contoso.com:
IPHostEntry hostInfo = Dns.GetHostByName("www.contoso.com");

The Resolve method queries a DNS server for the IP address that is associated with a host name, such as www.contoso.com, or for an IP address in dottedquad notation, such as 192.168.1.2. When the host name is a DNS-style host name that is associated with multiple IP addresses, only the first IP address that resolves to that host name is returned, as in the following example:
IPHostEntry hostInfo = Dns.Resolve("www.contoso.com");

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 11: Internet Access

TCP and UDP


Topic Objective
To explain how to use the TcpClient and TcpListener classes to request data from an Internet resource and to monitor TCP ports.
!

TCP Client Connecting to a Server/Listener

Lead-in
Applications can use TCP and UDP services with the TcpClient, TcpListener, and UdpClient classes.

TcpClient tcpc = new TcpClient(serverURI, 13); TcpClient tcpc = new TcpClient(serverURI, 13); Stream s = tcpc.GetStream(); Stream s = tcpc.GetStream(); Byte[] read = new Byte[32]; Byte[] read = new Byte[32]; int bytes = s.Read(read, 0, read.Length); int bytes = s.Read(read, 0, read.Length); String strInData = Encoding.ASCII.GetString(read); String strInData = Encoding.ASCII.GetString(read);
!

TCP Server/Listener Monitors Port for Clients

TcpListener tcpl = new TcpListener(13); TcpListener tcpl = new TcpListener(13); tcpl.Start(); tcpl.Start(); while (!done) { while (!done) { // Accept will block until someone connects // Accept will block until someone connects Socket s = tcpl.AcceptSocket(); Socket s = tcpl.AcceptSocket(); //Code to handle request goes here //Code to handle request goes here } } tcpl.Stop(); tcpl.Stop();

Applications can use TCP and UDP services with the TcpClient, TcpListener, and UdpClient classes. These classes, which are built on top of the Socket class, represent the data that is sent and received from the network as streams. These classes also take care of the details of creating a connection.

Using the TcpClient Class


You use the TcpClient class to request data from an Internet resource that uses TCP. The methods and properties of TcpClient abstract the details for creating a Socket instance that requests and receives data through TCP. The connection to the Internet is represented as a stream; therefore data can be read and written in a standard manner. The following code demonstrates how to set up a TcpClient object to connect to a server on TCP port 13:
TcpClient tcpc = new TcpClient(serverURI, 13); Stream s = tcpc.GetStream(); Byte[] read = new Byte[32]; int bytes = s.Read(read, 0, read.Length); String strInData = Encoding.ASCII.GetString(read);

Using the TcpListener Class


You use a TcpListener object to monitor a TCP port for incoming requests and then create a Socket instance that manages the connection to the client. The Start method enables listening, and the Stop method disables listening on the port. The AcceptSocket method accepts incoming connection requests and creates the socket that will handle the request.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

21

The following code demonstrates how to set up a TcpListener object to monitor TCP port 13:
TcpListener tcpl = new TcpListener(13); // listen on port 13 tcpl.Start(); while (!done) { // Accept will block until someone connects Socket s = tcpl.AcceptSocket(); //Code to handle request goes here } tcpl.Stop();

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 11: Internet Access

Sockets
Topic Objective
To describe the Socket class and provide an example of how the Socket class can be used to send data to an HTTP server and to receive the response.
! ! !

System.Net Classes Are Built on System.Net.Sockets System.Net.Sockets Are Based on the WinSock32 API See Example in Student Notes

Lead-in
The System.Net.Sockets namespace contains an implementation of the Windows Sockets interface.

The System.Net.Sockets namespace contains an implementation of the Windows Sockets interface. All other network access classes in the System.Net namespace are built on top of this implementation of sockets. The .NET Frameworks Socket class is a managed code version of the socket services that are provided by the WinSock32 API. If you are familiar with the Winsock API, you should be comfortable using the Socket class to develop applications. In most cases, the Socket class methods simply marshal data into their native Microsoft Win32 counterparts and handle necessary security checks.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

23

The following example shows how the Socket class can be used to send data to an HTTP server and receive the response:
using using using using using System; System.Net; System.Net.Sockets; System.IO; System.Text;

class App { public static void Main(string[] args) { DoSocketGet("localhost"); } public static string DoSocketGet(string server) { //Set up variables and String to write to the server Encoding ASCII = Encoding.ASCII; string Get = "GET / HTTP/1.1\r\nHost: " + server + "\r\nConnection: Close\r\n\r\n"; Byte[] ByteGet = ASCII.GetBytes(Get); Byte[] RecvBytes = new Byte[256]; String strRetPage = ""; // IPAddress and IPEndPoint represent the endpoint that // will receive the request IPHostEntry hostEntry = Dns.Resolve(server); IPEndPoint EPhost = new IPEndPoint(hostEntry.AddressList[0], 80); //Create the Socket for sending data over TCP Socket mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp ); // Connect to host using IPEndPoint try { mySocket.Connect(EPhost); // Sent the GET text to the host mySocket.Send(ByteGet, ByteGet.Length, 0); // Receive the page, loop until all received Int32 bytes = mySocket.Receive(RecvBytes, RecvBytes.Length, 0); strRetPage = "Default HTML page on " + server + ":\r\n"; strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes); //Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 11: Internet Access


while (bytes > 0) { bytes = mySocket.Receive(RecvBytes, RecvBytes.Length, 0); strRetPage = strRetPage + ASCII.GetString(RecvBytes, 0, bytes); } } catch (Exception e) { Console.WriteLine("Exception {0}",e.ToString()); } return strRetPage; } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

25

Handling Errors
Topic Objective
To explain how the Status property is used to determine if an error has occurred.
!

A WebException Can Be Thrown by GetResponse


# #

Has Status property, value from WebExceptionStatus If WebExceptionStatus.ProtocolError, then WebResponse contains protocol error information

Lead-in
The WebRequest and WebResponse classes throw system exceptions and Web-specific exceptions, which are instances of WebException and thrown by the GetResponse method.

try try { { // ... Create a request, get response and process stream. } // ... Create a request, get response and process stream. } catch (WebException webExcp) catch (WebException webExcp) { { Console.WriteLine("A WebException has been caught"); Console.WriteLine("A WebException has been caught"); Console.WriteLine(webExcp.ToString()); Console.WriteLine(webExcp.ToString()); WebExceptionStatus status = webExcp.Status; WebExceptionStatus status = webExcp.Status; if (status == WebExceptionStatus.ProtocolError) { if (status == WebExceptionStatus.ProtocolError) { Console.Write( Console.Write( "The server returned protocol error "); "The server returned protocol error "); Console.WriteLine(webExcp.Response.ToString()); Console.WriteLine(webExcp.Response.ToString()); } } } } catch (Exception e) catch (Exception e) {// Code to catch other exceptions goes here.} {// Code to catch other exceptions goes here.}

The WebRequest and WebResponse classes throw system exceptions, such as InvalidArgumentException, and Web-specific exceptions, which are instances of WebException and thrown by the GetResponse method. Each WebException includes a Status property that contains a value from the WebExceptionStatus class. You can examine the Status property to determine the particular error that has occurred and take the proper steps to resolve the error. The following table describes some of the possible values for the Status property. For a complete list of values, see the .NET Framework SDK documentation.
Value ConnectFailure ConnectionClosed KeepAliveFailure NameResolutionFailure ProtocolError ReceiveFailure RequestCanceled SecureChannelFailure SendFailure Description The remote service could not be contacted at the transport level. The connection was closed prematurely. The server closed a connection made with the Keep-alive header set. The name service could not resolve the host name. The response received from the server was complete but indicated an error at the protocol level. A complete response was not received from the remote server. The request was canceled. An error occurred in a secure channel link. A complete request could not be sent to the remote server.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 11: Internet Access (continued) Value ServerProtocolViolation Success Timeout TrustFailure Description The server response was not a valid HTTP response. No error was encountered. No response was received within the time-out set for the request. A server certificate could not be validated.

When the Status property is WebExceptionStatus.ProtocolError, a WebResponse that contains the response from the server is available. You can examine this response to determine the actual source of the protocol error. The following example shows how to catch a WebException; the invalid URL argument in the WebRequest.Create call will throw an exception:
using using using using System; System.Net; System.IO; System.Text;

class App { public static void Main(string[] args) { try { // Create a request instance // Note invalid URL will throw exception WebRequest myRequest = WebRequest.Create("http://localhost."); // Get the response. WebResponse myResponse = myRequest.GetResponse(); //Get a readable stream from the server. StreamReader sr = new StreamReader( myResponse.GetResponseStream(), Encoding.ASCII); int length = 1024; char [] Buffer = new char[1024]; int bytesread = 0; //Read from the stream and write data to Console. bytesread = sr.Read( Buffer, 0, length); while( bytesread > 0 ) { Console.Write( Buffer, 0, bytesread); bytesread = sr.Read( Buffer, 0, length); } sr.Close(); myResponse.Close(); } //Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access


catch (WebException webExcp) { Console.WriteLine("A WebException has been caught"); // Write out the WebException message. Console.WriteLine(webExcp.ToString()); // Get the WebException status code. WebExceptionStatus status = webExcp.Status; // If status is WebExceptionStatus.ProtocolError, // there has been a protocol error and a // WebResponse should exist. // Display the protocol error. if (status == WebExceptionStatus.ProtocolError) { Console.Write( "The server returned protocol error "); Console.WriteLine(webExcp.Response.ToString()); } } catch (Exception e) { // Code to catch other exceptions goes here. } } }

27

Applications that use the Socket class throw instances of SocketException when errors occur on the Windows socket. The TcpClient, TcpListener, and UdpClient classes are built on top of the Socket class and also throw instances of SocketException. When a SocketException is thrown, the Socket class sets the ErrorCode property to the last operating system socket error that occurred.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

28

Module 11: Internet Access

$ Security
Topic Objective
To introduce the topics in the section.
! ! ! !

Lead-in
Your application can provide security for sending and receiving data over the Internet by using a Web proxy, SSL encryption, Internet authentication, and the NET Frameworks code access permissions.

Web Proxy Secure Sockets Layer Internet Authentication Permissions

Your application can provide security for sending and receiving data over the Internet by using a Web proxy, Secure Sockets Layer (SSL) encryption, Internet authentication, and the NET Frameworks code access permissions.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

29

Web Proxy
Topic Objective
To show how to use a Web proxy to communicate with the Internet.
!

Global Proxy for All Web Requests


#

Proxy named webproxy using port 80

Lead-in
If your Web site uses a proxy to provide access to the Internet, you must configure a proxy instance to enable your application to communicate with the Web proxy.

WebProxy proxyObject = new WebProxy( WebProxy proxyObject = new WebProxy( "http://webproxy:80/"); "http://webproxy:80/"); GlobalProxySelection.Select = proxyObject; GlobalProxySelection.Select = proxyObject;
!

Overriding the Global Proxy Setting


#

Request uses proxy named alternateproxy and port 80

WebRequest req = WebRequest.Create( WebRequest req = WebRequest.Create( "http://www.contoso.com/"); "http://www.contoso.com/"); req.Proxy = new WebProxy( req.Proxy = new WebProxy( "http://alternateproxy:80/"); "http://alternateproxy:80/");

If your Web site uses a proxy to provide access to the Internet, you must configure a proxy instance to enable your application to communicate with the Web proxy.

Creating a Global Proxy Instance


The following example shows how to create a global proxy instance that enables any WebRequest to use a proxy to communicate with the Internet. The example assumes that the proxy server is named webproxy and that it communicates on port 80, the standard HTTP port.
WebProxy proxyObject = new WebProxy("http://webproxy:80/"); GlobalProxySelection.Select = proxyObject;

Overriding the Global Proxy Selection


You can override the global proxy selection by assigning an instance that implements the IWebProxy interface to the Proxy property of the WebRequest. The following code sends a WebRequest to http://www.contoso.com. The WebRequest overrides the global proxy selection with a proxy server that is named alternateproxy on port 80.
WebRequest req = WebRequest.Create("http://www.contoso.com/"); req.Proxy = new WebProxy("http://alternateproxy:80/");

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

30

Module 11: Internet Access

Secure Sockets Layer


Topic Objective
To explain how SSL is used for secure network communication.
!

SSL Is Used Automatically If the URI Begins with https

Lead-in
The WebRequest and WebResponse classes use SSL automatically. String MyURI = "https://www.contoso.com/"; String MyURI = "https://www.contoso.com/"; WebRequest wReq = WebRequest.Create(MyURI); WebRequest wReq = WebRequest.Create(MyURI);

The WebRequest and WebResponse classes use SSL automatically. The WebRequest object decides to use SSL on the basis of the URI that it is given. If the URI begins with https:, SSL is used. If the URI begins with http:, SSL is not used. The following example illustrates the use of SSL:
String MyURI = "https://www.contoso.com/"; WebRequest wReq = WebRequest.Create(MyURI);

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

31

Internet Authentication
Topic Objective
To introduce the client authentication mechanisms that are supported by the System.Net classes.
!

.NET Supports Various Kinds of Authentication


#

Lead-in
The System.Net classes support a variety of client authentication mechanisms, including the standard Internet authentication methods: basic, digest, negotiate, NTLM, and Kerberos authentication, and custom methods that you can create.

Basic, digest, negotiate, NTLM, and Kerberos authentication Users can also create their own authentication NetworkCredential for a single Internet resource CredentialCache for multiple Internet resources

Credentials Stored in Classes


# #

! !

Authentication Managed by the AuthenticationManager Some Schemes Allow Pre-Authentication to Save Time

The System.Net classes support a variety of client authentication mechanisms, including the standard Internet authentication methods: basic, digest, negotiate, NTLM, and Kerberos authentication, and custom methods that you can create.

Classes and Interfaces Used for Authentication


Authentication credentials are stored in the NetworkCredential and CredentialCache classes, which implement the ICredentialLookup interface. When one of these classes is queried for credentials, it returns an instance of the NetworkCredential class. The AuthenticationManager class manages the authentication process, while an authentication module class that implements the IAuthenticationModule interface performs the actual authentication process. You must register a custom authentication module with the AuthenticationManager before it can be used. Modules for the basic, digest, negotiate, NTLM, and Kerberos authentication methods are registered by default.

The NetworkCredential Class


The NetworkCredential class stores a set of credentials, which is associated with a single Internet resource and that is identified by a URI, and returns them in response to any call to the GetCredential method. The NetworkCredential class is typically used by applications that access a limited number of Internet resources or by applications that use the same set of credentials in all cases.

The CredentialCache Class


The CredentialCache class stores a collection of credentials for various Internet resources. When the GetCredential method is called, CredentialCache returns the proper set of credentials, as determined by the URI of the Internet resource and the requested authentication scheme. Because the CredentialCache class stores all of the credentials and provides them as requested, applications that use a variety of Internet resources with different authentication schemes benefit from using the CredentialCache class.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

32

Module 11: Internet Access

The Authentication Process


When an Internet resource requests authentication, the WebRequest.GetResponse method sends the WebRequest and the request for credentials to the AuthenticationManager. The request is then authenticated according to the following procedure: 1. The AuthenticationManager calls the Authenticate method on each of the registered authentication modules in the order that they were registered. 2. The AuthenticationManager uses the first module that does not return null to carry out the authentication process. The details of the process vary depending on the type of authentication module involved. 3. When the authentication process is complete, the authentication module returns an Authorization instance to the WebRequest that contains the information that is needed to access the Internet resource. Some authentication schemes can authenticate a user without first making a request for a resource. An application can save time by pre-authenticating the user with the resource, thus eliminating at least one roundtrip to the server. Alternatively, the application can perform authentication during program startup to be more responsive to the user later. Authentication schemes that can use pre-authentication set the CanPreAuthenticate property to true.

Basic Authentication
The System.Net implementation of basic and digest authentication complies with RFC2617, HTTP Authentication: Basic and Digest Authentication, which is available on the World Wide Web Consortium (W3C) Web site at http://www.w3c.org To use basic and digest authentication, an application must provide a user name and password in the Credentials property of the WebRequest object that it uses to request data from the Internet, as shown in the following example:
String MyURI = "http://www.contoso.com/"; WebRequest wReq = WebRequest.Create(MyURI); wReq.Credentials = new NetworkCredential( "username", "password");

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

33

NTLM and Kerberos Authentication


Default NTLM authentication and Kerberos authentication use the Microsoft Windows NT user credentials that are associated with the calling application to attempt authentication with the server. When using non-default NTLM authentication, the application sets the authentication type to NTLM and uses a NetworkCredential object to pass the username, password, and domain to the host, as in the following example:
String MyURI = "http://www.contoso.com/"; WebRequest wReq = WebRequest.Create(MyURI); wReq.Credentials = new NetworkCredential("username", "password", "domain");

Applications that need to connect to Internet services by using the credentials of the application user can do so with the users default credentials, as in the following example:
String MyURI = "http://www.contoso.com/"; WebRequest wReq = WebRequest.Create(MyURI); wReq.Credentials = CredentialCache.DefaultCredentials;

The negotiate authentication module determines whether the remote server is using NTLM or Kerberos authentication and sends the appropriate response. Note NTLM authentication does not work through a proxy server.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

34

Module 11: Internet Access

Permissions
Topic Objective
To explain which permission classes best suit which application types.
!

WebPermissions
#

Lead-in
The WebPermissions and SocketPermissions classes provide Internet security for applications that use System.Net.

Controls an application's right to request data from a URI or to serve a URI to the Internet Controls an application's right to accept data on a local port or to contact applications WebRequest and its descendents use WebPermissions Socket-level access uses SocketPermissions Accept application can answer an incoming connection Connect application can initiate a connection

SocketPermissions
#

Choose Permission Class Based on Application Use


# #

Both Classes Support Two Kinds of Permissions


# #

The WebPermissions and SocketPermissions classes provide Internet security for applications that use System.Net. The WebPermissions class controls an applications right to request data from a URI or to serve a URI to the Internet. The SocketPermissions class controls an applications right to accept data on a local port or to contact applications through a transport protocol at another address that is based on the host, port number, and transport protocol. You should choose the permission class on the basis of your application type. Applications that use WebRequest and its descendents should use the WebPermissions class to manage permissions. Applications that use socketlevel access should use the SocketPermissions class to manage permissions. WebPermissions and SocketPermissions define two permissions: accept and connect. Accept grants the application the right to answer an incoming connection from another party. Connect grants the application the right to initiate a connection to another party. For WebPermissions, accept means that an application can export a particular URI anywhere on the Internet. Connect means that an application can access that URI, whether it is remote or local. For SocketPermissions, accept means that an application can accept incoming connections on a local transport address. Connect means that an application can connect to a remote, or potentially local, transport address.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

35

Best Practices
Topic Objective
To introduce best practices that will help students use the System.Net classes more effectively.
!

When Possible, Use WebRequest and WebResponse, Instead of Protocol-Specific Subclasses For Better Performance, Use Asynchronous Methods Tune Performance by Adjusting the Number of Connections
#

Lead-in
The following recommendations will help you use the classes that are contained in System.Net more effectively.

! !

ConnectionLimit property in the ServicePoint instance

When Possible, Use TcpClient or UdpClient, Instead of Writing Directly to a Socket Use the CredentialCache Class If Credentials Are Required

The following recommendations will help you use the classes that are contained in System.Net more effectively:
!"

Whenever possible, use WebRequest and WebResponse, instead of typecasting to descendent classes. Applications that use WebRequest and WebResponse can take advantage of new Internet protocols without extensive code changes.

!"

When writing ASP.NET applications that run on a server that uses the System.Net classes, it is often better, from a performance standpoint, to use the asynchronous methods for GetResponse and GetResponseStream. Set the ConnectionLimit property in the ServicePoint instance for your application. The number of connections opened to an Internet resource can have a significant impact on network performance and throughput. By default, System.Net uses two connections per application for each host. Setting the ConnectionLimit property in the ServicePoint instance for your application can increase this number.

!"

!"

When writing socket-level protocols, try to use the TcpClient or UdpClient classes, instead of writing directly to a socket. The TcpClient and UdpClient classes encapsulate the creation of TCP and UDP sockets without requiring you to handle the details of the connection.

!"

When accessing sites that require credentials, use the CredentialCache class to create a cache of credentials, rather than supplying them with every request. The CredentialCache class will search the cache to find the appropriate credential to present with a request, thus relieving you of the responsibility of creating and presenting credentials based on the URI.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

36

Module 11: Internet Access

Lab 11: Creating a DateTime Client/Server Application


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will create a client application that uses the System.Net.Sockets .TcpClient class to connect to and obtain date and time information from a server. You will also create a server application that uses the System.Net.Sockets.TcpLi stener class to accept requests from and provide date and time information to clients.

Objectives
After completing this lab, you will be able to:
!"

Create a client application that uses the System.Net.Sockets.TcpClient class to connect to and obtain date and time information from a server. Create a server application that uses the System.Net.Sockets.TcpListener class to accept requests from and provide date and time information to clients.

!"

Lab Setup
Only solution files are associated with this lab. The solution files for this lab are in the folder <install folder>\Labs\Lab11\Solution.

Scenario
In this lab, you will create two Microsoft Visual Studio .NET console applications: DateTimeClient and DateTimeServer. The DateTimeClient application will make a TCP connection to the DateTimeServer application and obtain a stream that contains date and time information. The DateTimeClient will read the stream and convert the streams ASCII data into a string that is then output to the console.

Estimated time to complete this lab: 45 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

37

Exercise 1 Creating the DateTime Server


In this exercise, you will create a server application that will provide date and time information to clients through TCP.

!" create the server application To


1. In Visual Studio.NET, create a new C# console application project named DateTimeServer in <install folder>\Labs\Lab11. 2. Rename the starting C# source file Datetimeserver.cs. 3. Add the following using statements:
using System.Net; using System.Net.Sockets; using System.Text;

4. Rename the wizard generated Class1 to Server. 5. Modify the Main method to: a. Instantiate a TcpListener object to listen on port 13. b. Start the TcpListener object. c. Write out the following message to the console:
Waiting for clients to connect Press Ctrl+c to Quit...

d. Enter an infinite loop that will: i. Accept TCP client connections using the AcceptSocket method. ii. Call a DateTime method to get the current date and time. iii. Create a string that consists of the short version of the date, followed by the long version of the time. iv. Convert the string to an ASCII-encoded byte array. v. Send this byte array to the TCP client. vi. Write out to the console a message that contains the string that was just sent. 6. Build the server application.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

38

Module 11: Internet Access

Exercise 2 Creating the DateTime Client


In this exercise, you will create a client application. The client application takes as its runtime argument the name of the computer on which the server is running. The client connects to the server to obtain date and time information through TCP. The client then displays the date and time information on the console.

!" create the client application To


1. In Visual Studio.NET, create a new C# console application project named DateTimeClient in <install folder>\Labs\Lab11. 2. Rename the starting C# source file Datetimeclient.cs. 3. Add the following using statements:
using using using using System.Net; System.Net.Sockets; System.IO; System.Text;

4. Rename the wizard generated Class1 to Client. 5. Make the static Main method capable of handling runtime-supplied arguments. 6. In the Main method, add code to: a. Create a TcpClient object. b. Create a byte array object of size 32 bytes. c. Check the number of runtime arguments. If the number of arguments is not one, print out an error message to the console, and exit. The message should state:
Please specify a server name in the command line

d. In a try/catch block, verify that the named server computer exists by calling the GetHostByName method of the Dns class. Catch any SocketException exceptions and output a message that states that the named server could not be found to the console. The message should include the exceptions data. Then exit the application. e. In a try/catch block do the following steps: i. Connect to the named server using port 13. ii. Get the stream. iii. Read all of the bytes in the stream into the byte array that you created in step 4b, and store the number of bytes that are read in an integer. iv. Convert the ASCII-encoded byte array into a string. v. Write out to the console a message that states the number of bytes received and the current date and time string retrieved from the server. vi. Close the TcpClient object. vii. If an Exception exception is thrown, print out an error message to the console and exit.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

39

f. Write out to the console the following message: Press ENTER to exit. g. Do a read from the console to wait for the ENTER key and exit the application. 7. Build the client application.

!" test the client and server applications To


1. Ensure that there are no server applications running on the machine using port 13, for example, other instances of the server application. 2. Run the server application in a console window or in the Visual Studio.NET debugger. 3. Run the client application in another console window or in another Visual Studio.NET debugger. Do not specify any runtime arguments. 4. Note that the client application returns with the proper error message, as follows:
Please specify a server name in the command line

5. Run the client application as directed in step 2 with a runtime argument that contains a nonexistent server name. For example, assuming that there is no computer named foo on the network, enter the following text in a console window:
datetimeclient foo

6. Note that the client application returns with the proper error message, for example:
Cannot find server: foo

7. Run the client application as directed in step 2 with a runtime argument that contains the name of the computer on which the Datetimeserver application is running. If the server application is running on your current computer, specify the local computer as follows:
datetimeclient localhost

8. Note that the client application outputs the number of bytes received and the current date and time string retrieved from the server.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

40

Module 11: Internet Access

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! ! ! ! ! !

Internet Application Scenarios The WebRequest and WebResponse Model Application Protocols Handling Errors Security Best Practices

Lead-in
The review questions cover some of the key concepts taught in the module.

1. Name the four parts of the following URI: http://www.microsoft.com/default.htm?foo=bar Scheme identifier Server identifier Path identifier Query String http www.Microsoft.com /default.htm ?foo=bar

2. Write the line of code that creates a WebRequest to the URI in question 1.
WebRequest req = WebRequest.Create ("http://www.microsoft.com/default.htm?foo=bar");

3. Write the line of code that gets a WebResponse from the WebRequest in question 2.
WebResponse resp = req.GetResponse();

4. Write the line of code that gets a Stream from the WebResponse in question 3.
Stream respstrm = resp.GetResponseStream();

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 11: Internet Access

41

5. Name the type of Web-specific exceptions that are thrown by the GetResponse method. WebException

6. State how a WebRequest can be made to use the Secure Socket Layer (SSL) protocol. URI begins with https.

7. Name at least three authentication methods that are supported by the .NET Framework. Basic Digest Negotiate NTLM Kerberos

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

THIS PAGE INTENTIONALLY LEFT BLANK

Module 12: Serialization

Contents Overview Serialization Scenarios Serialization Attributes Object Graph Serialization Process Serialization Example Deserialization Example Custom Serialization Custom Serialization Example Security Issues Lab 12: Serialization Review 1 2 4 5 7 9 10 12 14 17 18 27

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

iii

Instructor Notes Module 12


Presentation: 30 Minutes Lab: 45 Minutes After completing this module, students will be able to: Write an application that serializes and deserializes an object graph by using either a binary or Simple Object Access Protocol (SOAP) XML format.

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_12.ppt

Preparation Tasks
To prepare for this module, you should:
!" !"

Read all of the materials for this module. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 12: Serialization

Module Strategy
Use the following strategy to present this module:
!"

Serialization Scenarios Discuss briefly how serialization is used in scenarios such as persisting inmemory objects to disk and in remoting. Mention the Microsoft .NET Frameworks support for serialization and deserialization as an introduction to the rest of the module.

!"

Serialization Attributes Explain how to mark a class with serialization attributes in C# by using the Serializable attribute. Also cover the NonSerialized attribute.

!"

Object Graph Use the diagram on the Object Graph slide to discuss the object graph concept and the algorithm that is used to serialize or deserialize an object graph.

!"

Serialization Process Introduce the classes that are used in the serialization process. Serialization Example Discuss the code example on the Serialization Example slide in which default serialization is performed on a graph of objects, whose root is an ArrayList, and the serialized stream is written to a FileStream in binary format.

!"

!"

Deserialization Example Use the preceding serialization example to show how to create a clone of the graph by deserializing it.

!"

Custom Serialization Discuss when to use custom serialization and the implementation details of using the ISerializable interface to perform custom serialization and deserialization.

!"

Custom Serialization Example Show how to provide custom serialization for a class named ISerializableExample.

!"

Security Issues Because the serialization engine handles both the public and private state of the objects that are passed to it, emphasize that streams with private data should be treated carefully, and that some form of encryption should be used for sensitive data, before that data is transmitted over the wire or persisted to disk.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! ! ! ! ! ! ! ! !

Serialization Scenarios Serialization Attributes Object Graph Serialization Process Serialization Example Deserialization Example Custom Serialization Custom Serialization Example Security Issues

Lead-in
In this module, you will learn about serialization and learn how to write an application that serializes and deserializes an object graph by using a binary or SOAP XML format.

Serialization is the process of converting a graph of objects into a linear sequence of bytes. That sequence of bytes can be sent elsewhere, for example, to a remote computer, and be deserialized, thereby making a clone in the remote memory of the original graph of objects. After completing this module, you will be able to: Write an application that serializes and deserializes an object graph by using either a binary or Simple Object Access Protocol (SOAP) XML format.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

Serialization Scenarios
Topic Objective
To show how serialization is used.
!

Lead-in
Serialization is used in some very common scenarios, such as persisting a graph of objects to disk or to objects in another process.

Persistence
#

Store and retrieve a graph of objects to and from a file Pass by value arguments that are transmitted between processes

Remoting
#

Serialization is used in some very common scenarios, such as persisting a graph of objects to disk or to objects in another process. The Microsoft .NET Framework provides support for serialization and deserialization.

Persistence
Consider a simple single-user desktop application, such as a two-dimensional drafting package that is built by using object-oriented techniques. In such an application, a drawing is composed of different kinds of graphical objects of various types. The application represents the drawing as a graph of in-memory objects. One object represents the root of the entire picture. For example, a simple round table could be represented by a graph that consists of a root object that is an instance of a circle class. This instance of the circle class has four children that are each instances of a line class. To save the entire drawing to a disk file so the drawing can be restored after rebooting the computer, you could force each class to implement a serialize and corresponding deserialize method. However, this approach is a potentially burdensome task for the application programmer.

Serialization in the .NET Framework


The .NET Framework common language runtime reduces the amount of work that is involved in serialization. At run time, the common language runtime maintains metadata that allows serialization code to discover the types and values of all fields and properties that make up any object. Using the common language runtime, an application requires only a few lines of code to serialize a object, such as the drawing described in the preceding paragraphs, and write it to a file, or to deserialize such a file into an in-memory graph of objects.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

Remoting
In distributed computing, objects in one process may need to communicate with objects in another process. In the .NET Framework, the term remoting is typically used to refer to the process in which an object invokes a method in another object that is not in the same application domain. If the remote method takes as one of its arguments an object that lies at the root of a graph of objects, and if all of the objects in the graph are marked as remote-by-value, you must serialize a copy of the object graph and pass the graph to the remote object. The remote object must then deserialize the argument into an in-memory graph of objects. For more information about remoting, see Module 13, Remoting and Web Services, in Course 2349A, Programming the Microsoft .NET Framework with C# (Prerelease).

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

Serialization Attributes
Topic Objective
To explain how to mark a class with serialization attributes in C#.
!

To Mark a Class, Use Serializable Attribute

Lead-in
If you are writing a class, you should be aware of serialization.

[Serializable] public class MyClass {} [Serializable] public class MyClass {}


!

To Skip Specified Members, Use NonSerialized Attribute

[Serializable] public class MyClass { [Serializable] public class MyClass { [NonSerialized] int _cashSize; [NonSerialized] int _cashSize; //... //... } }
!

To Provide Custom Serialization, Implement ISerializable

If you are writing a class, you should be aware of serialization. The common language runtimes serialization services are built with the assumption that a type is not serializable unless the type is specifically marked as serializable. In the simplest case, all you need to do is mark a class as serializable because the runtime metadata understands everything about each objects layout in memory, and its field and property definitions. To mark a type as serializable in C#, you use the Serializable attribute, which is a reserved custom attribute. All fields in classes with this attribute are serialized, even private fields. In the following example, MyClass is marked as serializable:
[Serializable] public class MyClass {}

For slightly more complex classes that have state that is invalid to serialize, the runtime provides support for marking those fields and properties as transient. For example, the following code uses the NonSerialized attribute to ensure that the _cashSize member of MyClass is not serialized:
[Serializable] public class MyClass { [NonSerialized] int _cashSize; //... }

The small set of classes that need to participate in their own serialization and deserialization can provide a custom implementation of the ISerializable interface. For more information about custom serialization, see Custom Serialization in this module.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

Object Graph
Topic Objective
To define an object graph and explain its function.

3 4 Cat

Dog 7 Duck 1 Mouse

Lead-in
An object graph is a set of objects that share a set of references to each other.

Horse

Duck

An object graph is a set of objects with references to each other. Serialization must provide a way to represent the links between the graphs objects in the serialized stream that is created in the serialization process.

Understanding Object Graphs


Serialization of an object graph must provide a way to represent the links between the graphs objects in the serialized stream that it creates. The value that is held in the field of the in-memory object, which links to another object, is essentially a 32-bit address. This address has meaning only in the owner address space and may change during garbage collection. Therefore, serialization must allocate a unique number to each object in the stream. The illustration in the slide shows a graph of animal objects. Each object is represented as a box with its identification number inside the box and its class name to the right of the box. You can represent the graph of objects that is shown in this illustration with a serialized stream, as in the following example:
Dog, 3, ref4, ref7, ref1 || Cat, 4, ref9 || Duck, 7 || Mouse, 1, ref9, ref2 || Horse, 9, ref4 || Duck, 2

The order in which you stream out the objects does not matter, nor does it matter what numbers you assign to the objects. What does matter is that no two objects are assigned the same number. The object numbers are significant only within a serialized stream. They are simply a way to represent the graph topology and to allow you to reconstruct a copy of that graph, perhaps on another computer.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

Tracking Object References


An algorithm that visits objects one at a time clearly must keep track of which objects it has already visited, for example, by using an internal list. Without due care, the algorithm may incorrectly serialize or deserialize an object graph. For example, in the object graph in the illustration, to avoid entering an infinite loop, you must detect the cycle in the graph that occurs because of the mutual references between Cat 4 and Horse 9. During serialization, you must note that the Cat 4 that is linked to by Dog 3 is the same Cat 4 that is linked to by Horse 9 to ensure that deserialization will result in both Dog 3 and Horse 9 referring to the same Cat 4 object and not to two different copies.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

Serialization Process
Topic Objective
To introduce the classes that are used in the serialization process.
!

Classes Used by the Default Serialization Process


# #

ObjectIDGenerator generates IDs for objects ObjectManager tracks objects as they are being deserialized FileStream, MemoryStream, NetStream Writes or reads data in a specified format to the output or input streams Runtime provides BinaryFormatter and SoapFormatter

Lead-in
The process of serializing an object graph involves identifying the individual objects in the graph and the relationships between them.

Examples of Classes Used with Serialized Streams


#

Formatter Class
#

The process of serializing an object graph involves identifying the individual objects in the graph and the relationships between them.

Classes Used by the Default Serialization Process


To create and track object ID numbers, serialization uses several classes, as follows:
!"

ObjectIDGenerator The ObjectIDGenerator class generates IDs for objects. It keeps track of objects that have already been seen, so when you ask for the ID of an object, the ObjectIDGenerator knows whether to return the existing ID, or to generate, and remember, a new ID.

!"

ObjectManager The ObjectManager class keeps track of objects as they are being deserialized. During deserialization, queries are made to the ObjectManager to determine whether a reference to an object that is in the serialized stream refers to an object that has already been deserialized or to an object that has not yet been deserialized. A reference to an object that has already been deserialized is called a backward reference. A reference to an object that has not yet been serialized is called a forward reference.

Both the ObjectIDGenerator and ObjectManager classes are pluggable, so you can build your own alternatives. Note During deserialization, fields are returned in the order in which they are returned from reflection. Reflection does not guarantee that it will follow metadata ordering. You can serialize to many different kinds of streams, for example, to a FileStream, a MemoryStream, or a NetStream. The serialized streams format is determined by the formatter object that you instantiate.
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

The .NET Framework runtime provides the following formatter classes:


!"

BinaryFormatter The BinaryFormatter class is used for a compact binary representation. SoapFormatter The SoapFormatter class is used for an XML representation.

!"

Because formatters are pluggable, you can also build your own formatters.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

Serialization Example
Topic Objective
To provide an example of serialization of an object graph. class SerializeExample{ class SerializeExample{ public static void Main(String[] args) { public static void Main(String[] args) { // create the object graph // create the object graph ArrayList l = new ArrayList(); ArrayList l = new ArrayList(); for (int x=0; x< 100; x++) { for (int x=0; x< 100; x++) { l.Add (x); l.Add (x); } } // create the filestream // create the filestream FileStream s = File.Create("foo.bin"); FileStream s = File.Create("foo.bin"); // create the BinaryFormatter // create the BinaryFormatter BinaryFormatter b = new BinaryFormatter(); BinaryFormatter b = new BinaryFormatter(); // serialize the graph to the stream // serialize the graph to the stream b.Serialize(s, l); b.Serialize(s, l); s.Close(); s.Close(); } }

Lead-in
This code sample shows how to perform default serialization of a graph of objects, whose root is an ArrayList.

} }

The following code sample shows how to perform default serialization of a graph of objects, whose root is an ArrayList. The serialized stream is written to a FileStream in binary format.
using using using using using System; System.IO; System.Collections; System.Runtime.Serialization; System.Runtime.Serialization.Formatters.Binary;

class SerializeExample { public static void Main(String[] args) { // create the object graph ArrayList l = new ArrayList(); for (int x=0; x< 100; x++) { l.Add (x); } // create the filestream FileStream s = File.Create("foo.bin"); // create the BinaryFormatter BinaryFormatter b = new BinaryFormatter(); // serialize the graph to the stream b.Serialize(s, l); s.Close(); } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 12: Serialization

Deserialization Example
Topic Objective
To show how to create a clone of the graph by deserializing it. class DeSerialize class DeSerialize { { public static void Main(String[] args) public static void Main(String[] args) { { // open the filestream // open the filestream FileStream s = File.OpenRead("foo.bin"); FileStream s = File.OpenRead("foo.bin"); // create the formatter // create the formatter BinaryFormatter b = new BinaryFormatter(); BinaryFormatter b = new BinaryFormatter(); // deserialize // deserialize ArrayList p = (ArrayList) b.Deserialize(s); ArrayList p = (ArrayList) b.Deserialize(s); s.Close(); s.Close(); // print out the new object graph // print out the new object graph // see module text for PrintValues code // see module text for PrintValues code PrintValues(p); PrintValues(p);

Lead-in
The preceding Serialization Example shows how to perform default serialization of a graph of objects, whose root is an ArrayList, with a serialized stream that is written to a FileStream in binary format.

} }

The preceding Serialization Example shows how to perform default serialization of a graph of objects, whose root is an ArrayList, with a serialized stream that is written to a FileStream in binary format. The following code sample shows how to create a clone of the graph by deserializing it. The root of the clone graph is called p.
using using using using using System; System.IO; System.Collections; System.Runtime.Serialization; System.Runtime.Serialization.Formatters.Binary;

class DeSerialize { public static void Main(String[] args) { // open the filestream FileStream s = File.OpenRead("foo.bin"); // create the formatter BinaryFormatter b = new BinaryFormatter(); // deserialize ArrayList p = (ArrayList) b.Deserialize(s); s.Close(); // print out the new object graph PrintValues(p); } //Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization


public static void PrintValues( IEnumerable myList ) { System.Collections.IEnumerator myEnumerator = myList.GetEnumerator(); while ( myEnumerator.MoveNext() ) Console.WriteLine( "{0}", myEnumerator.Current ); } }

11

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 12: Serialization

Custom Serialization
Topic Objective
To explain what is required to implement ISerializable for performing custom serialization.
!

Customize Serialization by Implementing ISerializable:


# #

When some of the data is not valid after deserialization When some of the data must be obtained by calculation GetObjectData method, called during serialization, which returns a PropertyBag of type SerializationInfo PropertyBag, which contains the type of the object being serialized and the name/object pairs for the values being serialized A constructor, called during deserialization, which uses SerializationInfo to reconstitute the state of the object

Lead-in
This module has so far discussed the default serialization process. However, you may also want to customize the way data from a given object is serialized.

ISerializable Requires:
#

This module has so far discussed the default serialization process. However, you may also want to customize the way that data from a given object is serialized. Custom serialization can be useful when some of the data that is associated with an object is no longer valid after deserialization. You may want to use custom serialization when working with pointers or hashcodes, or when you want to create data through calculations or other means that allow you to reconstruct the full state of the object during deserialization. To perform custom serialization, you should implement the ISerializable interface on the given object.

Implementation Details Required by ISerializable


To implement the ISerializable interface, you implement the GetObjectData method on your object and add a constructor that takes a SerializationInfo and a StreamingContext, as shown in Custom Serialization Example in this module. When GetObjectData is called during serialization, you are responsible for populating a SerializationInfo object. A SerializationInfo object is a PropertyBag that contains the type of the object that is being serialized and the name/object pairs for the values that are being serialized. The Formatter emits the data out onto the wire in the method required by its particular format. You are free to serialize as few or as many fields as you want, but the data that is transmitted must be sufficient to reconstitute the entire state of the object. If the base object of the current class implements ISerializable, it is usually correct to call the base objects ISerializable.GetObjectData and add any additional fields that are required for serializing the derived class to the returned SerializationInfo.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

13

Deserialization
Deserialization occurs during the call to the classs constructor. If you need to create custom deserialization of an object, you use the objects SerializationInfo, which has been populated with the type of the object and the name/object pairs that were transmitted over the stream. You are responsible for completely reconstituting the state of the object from this information. If the base class also implements ISerializable, you are responsible for calling the base classs constructor. The serialization infrastructure will delay the call on this constructor until the entire SerializationInfo has been completed. If, for example, the SerializationInfo that is transmitted references objects A, B, and C, the SerializationInfo that is passed to the constructor will have been populated with references to objects A, B, and C. However, there is no guarantee that any of the objects that are referenced by A, B, or C has been completed. Because there is no guarantee that any of the objects that are referenced by A, B, or C have been completed, you cannot safely call any code on A, B, or C that may require the objects to which they refer. For some objects, this code may include code as simple as GetHashCode. If your code requires you to perform any execution that is based on the value of data that is contained in the objects that are referenced, it is usually best to cache the SerializationInfo and then implement IDeserializationCallback.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 12: Serialization

Custom Serialization Example


Topic Objective
To provide an example of custom serialization.
[Serializable] public class ExampleFoo : ISerializable [Serializable] public class ExampleFoo : ISerializable { { public int i, j, k; public int i, j, k; public ExampleFoo() {} public ExampleFoo() {} internal ExampleFoo(SerializationInfo si, internal ExampleFoo(SerializationInfo si, StreamingContext context) { StreamingContext context) { //Restore our scalar values. //Restore our scalar values. i = si.GetInt32("i"); i = si.GetInt32("i"); j = si.GetInt32("j"); j = si.GetInt32("j"); k = si.GetInt32("k"); k = si.GetInt32("k"); } } public void GetObjectData(SerializationInfo si, public void GetObjectData(SerializationInfo si, StreamingContext context) { StreamingContext context) { //SerializationInfo - essentially a property bag //SerializationInfo - essentially a property bag //Add our three scalar values; //Add our three scalar values; si.AddValue("i", i); si.AddValue("i", i); si.AddValue("j", j); si.AddValue("j", j); si.AddValue("k", k); si.AddValue("k", k); Type t = this.GetType(); Type t = this.GetType(); si.AddValue("TypeObj", t); si.AddValue("TypeObj", t); } } } }

Lead-in
This example shows how to provide custom serialization for a class named ISerializableExample.

The following example shows how to provide custom serialization for a class:
using using using using using System; System.IO; System.Runtime.Serialization; System.Runtime.Serialization.Formatters; System.Runtime.Serialization.Formatters.Soap;

public class Sample { public static void Main() { ToFile(); FromFile(); } //Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization


public static void ToFile() { Console.WriteLine("ToFile"); ExampleFoo fooOut = new ExampleFoo(); fooOut.i = 1; fooOut.j = 20; fooOut.k = 50; Console.WriteLine("i: {0}", fooOut.i); Console.WriteLine("j: {0}", fooOut.j); Console.WriteLine("k: {0}", fooOut.k); IFormatter objFormatterToStream = new SoapFormatter(); Stream toStream = new FileStream("myFoo.xml", FileMode.Create, FileAccess.Write, FileShare.None); objFormatterToStream.Serialize(toStream, fooOut); toStream.Close(); }

15

public static void FromFile() { Console.WriteLine("FromFile"); //Then you can read it back in with code like this: IFormatter objFormatterFromStream = new SoapFormatter(); Stream fromStream = new FileStream("myFoo.xml", FileMode.Open, FileAccess.Read, FileShare.Read); ExampleFoo fooIn = (ExampleFoo) objFormatterFromStream.Deserialize(fromStream); fromStream.Close(); Console.WriteLine("i: {0}", fooIn.i); Console.WriteLine("j: {0}", fooIn.j); Console.WriteLine("k: {0}", fooIn.k); } }

[Serializable] public class ExampleFoo : ISerializable { public int i, j, k; public ExampleFoo() { } internal ExampleFoo(SerializationInfo si, StreamingContext context) { //Restore our scalar values. i = si.GetInt32("i"); j = si.GetInt32("j"); k = si.GetInt32("k"); } //Code continued next page
BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 12: Serialization


public void GetObjectData(SerializationInfo si, StreamingContext context) { //SerializationInfo is essentially a property bag. //Add our three scalar values; si.AddValue("i", i); si.AddValue("j", j); si.AddValue("k", k); Type t = this.GetType(); si.AddValue("TypeObj", t); } }

Outputs:
ToFile i: 1 j: 20 k: 50 FromFile i: 1 j: 20 k: 50

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

17

Security Issues
Topic Objective
To alert students to the need for security when serializing objects.
!

Serialization Handles an Objects Private Data


#

Lead-in
The serialization engine handles both the public and private state of the objects that are passed to it.

If private data is sensitive, consider encrypting the stream before transmitting or saving to a disk

The serialization engine handles both the public and private state of the objects that are passed to it. When serializing an object to a stream, you must remember that the stream now contains the public and private data of the object. If the private data is sensitive, you should treat the stream with particular care. For example, the stream should not be transmitted over the wire or persisted to disk without some form of encryption.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 12: Serialization

Lab 12: Serialization


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will write a client/server application that uses serialization.

Objectives
After completing this lab, you will be able to: Create an application that uses serialization as it is implemented by the .NET Framework, to persist an object graph to and from a disk file in both binary and SOAP XML format.

Lab Setup
Starter and solution files are associated with this lab. The starter files are in the folder <install folder>\Labs\Lab12\Starter, and the solution files are in the folder <install folder>\Labs\Lab12\Solution.

Scenario
In this lab, you will create a Microsoft Visual Studio .NET console application that uses the common language runtimes ability to serialize an object graph in memory to disk. You will create binary and SOAP formatter implementations of the application. In the first exercise, you will create a singly-linked linked list, which you will fill with values and serialize to a file on disk. You will then deserialize the list from the file on disk, thus restoring the list to an object graph in memory. During deserialization, the elements within the list are swapped multiple times. In the second exercise, you will modify the application to demonstrate the ability of the .NET Frameworks serialization mechanism to handle object graphs that contain multiple references to the same object and that contain objects that have mutual references, which can create cycles in the graph.

Estimated time to complete this lab: 45 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

19

Exercise 1 Creating the Basic Serialization Application


In this exercise, you will modify the Serialization application to provide methods to serialize and deserialize a linked list.

!" create the basic Serialization application in binary format To


1. In the <install folder>\Labs\Lab12\Starter directory, open the Serialization project in Visual Studio .NET and examine the Serialize.cs and LinkedList.cs source files. 2. In Serialize.cs, locate the SaveListToDisk method, and add code to: a. Create a Stream object that is initialized to a file named Linkedlist.bin by using the static File.Create method. b. Create a new BinaryFormatter object. c. Invoke the method of the BinaryFormatter that serializes the LinkedList parameter to the stream. d. Close the file. 3. In Serialize.cs, locate the LoadListFromDisk method and add code to: a. Create a Stream object that is initialized to a file named Linkedlist.bin by using the static File.OpenRead method. b. Create a new BinaryFormatter object. c. Invoke the method of the BinaryFormatter that deserializes the stream into a LinkedList named list2. d. Close the file. e. Output the contents of list2 to console by calling the LinkedList method Draw(). f. Return list2. 4. Build the Serialization application. 5. Step through the application in the Visual Studio .NET debugger, and note that due to the random swapping your output may vary slightly from the following:

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 12: Serialization


Entering Scope 1 Creating and filling List .. List: 1 2 3 4 5 6 7 8 9 Serializing LinkedList to file .. Leaving Scope 1 Entering Scope 2 Deserializing LinkedList from binary file .. List: 1 2 3 4 5 6 7 8 9 Swapping Entries Swapping 1 and 2 Swapping 3 and 4 Swapping 5 and 6 Swapping 7 and 8 List: 2 1 4 3 6 5 8 7 9 Serializing LinkedList to file .. Leaving Scope 2 Entering Scope 3 Deserializing LinkedList from binary file .. List: 2 1 4 3 6 5 8 7 9 Swapping Random Entries Swapping 2 and 8 Swapping 4 and 3 Swapping 4 and 3 Swapping 6 and 5 Swapping 1 and 4 Swapping 1 and 8 Swapping 2 and 4 Swapping 3 and 5 Swapping 7 and 2 Swapping 5 and 4 Swapping 6 and 2 Swapping 9 and 5 Swapping 1 and 7 Swapping 7 and 8 Swapping 8 and 2 List: 2 1 7 4 3 8 9 6 5 Serializing LinkedList to file .. Leaving Scope 3 Entering Scope 4 Deserializing LinkedList from binary file .. List: 2 1 7 4 3 8 9 6 5 Removing Entries Removing 1 Removing 2 Removing 3 List: 7 4 8 9 6 5 Serializing LinkedList to file .. Leaving Scope 4

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

21

Note You can open a binary file using Visual Studio .NET by running Microsoft Windows Explorer, Explorer.exe, and navigating to the binary files icon. Then either right-click on the icon and choose Open With Microsoft Visual Studio .NET, or drag and drop the icon into a running Visual Studio .NET applications left-hand File View pane. 6. Using Visual Studio .NET, open and visually examine the contents of the Linkedlist.bin file in the bin\Debug subdirectory, and note the serialized list datas format, structure, and size.

!" create the basic Serialization application in SOAP format To


1. Add code to the SaveListToDisk and LoadListFromDisk methods to use the SoapFormatter to write to and read the LinkedList parameter to and from a file named Linkedlist.soap. 2. Build and execute the application, and confirm that the console output remains correct. 3. Using Visual Studio .NET, open and visually examine the contents of the Linkedlist.soap file in the bin\Debug subdirectory, and note the serialized list datas format and size. Compare this list datas format, structure, and size to the Linkedlist.bin list datas format, structure, and size.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 12: Serialization

Exercise 2 Handling Complex Object Graphs


In this exercise, you will modify the Serialization application to create and manipulate an object graph that has multiple references to the same object and has reference cycles.

!" create the complex Serialization application in SOAP format To


1. In Serialize.cs, locate the Ser class and add a static method named SaveArrayToDisk that returns a void and that takes as its single argument an array of type Node. Within SaveArrayToDisk, add code to: a. Iterate through the array of nodes, and, for each node, print out the arrays index, the nodes value, and the value of the Node object in the nodes NextNode field. b. Write out a message to the console that states that the application is serializing the array to a file. c. Create a stream object that is initialized with the file named Array.soap by using the static File.Create method. d. Create a SoapFormatter object. e. Serialize the node array to the file. f. Close the file. 2. In the Ser class, add a static method named LoadArrayFromDisk that takes no arguments and returns an array of type Node. Within LoadArrayFromDisk, add code to: a. Write out a message to the console that states that the application is deserializing an array from the file. b. Create a stream object that is initialized with the file named Array.soap by using the static File.OpenRead method. c. Create a SoapFormatter object. d. Using the SoapFormatter object, deserialize the stream into an array of type Node. e. Close the file. f. Iterate through the array of nodes, and, for each node, print out the arrays index, the nodes value, and the value of the Node object in the nodes NextNode field. g. Return the array of type Node.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

23

3. In the Ser class add a static public method named Scope5 that takes no arguments and returns void. Within Scope5, add code to: a. Create two objects of type Node named n0 and n1 that are initialized to values 0 and 1 respectively. b. Write out a message to the console that states that the application is entering Scope5 and creating a graph cycle. c. Assign n1 to the NextNode field of n0. d. Assign n0 to the NextNode field of n1. e. Create an array of type Node that is initialized to contain references to the three objects: n0, n1, and n0. Note that index 0 and 2 refer to the same object. f. Call the SaveArrayToDisk method and pass in the array of type Node. g. Write out a message to the console that states that the application is leaving Scope5. 4. In the Ser class, add a static public method named Scope6 that takes no arguments and returns void. Within Scope6, add code to: a. Write out a message to the console that states that the application is entering Scope6 and creating a graph cycle. b. Assign to a variable named nodes of type array of Node the array that is returned by the LoadArrayFromDisk method. The array references the objects: n0, n1, and n0 that were created in step 1. Note that index 0 and 2 refer to the same object. c. Write out a message to the console that states that the value of n0 is changing to 42 and that this change should result in a change in the value in both locations in the array. d. Assign the integer 42 to the Value field of nodes[0]. e. Write out a message to the console that states that the arrays structure should be preserved during serialization and deserialization. f. Call SaveArrayToDisk to persist nodes to the disk. g. Assign to a variable named nodes2 of type array of Node the array that is returned by the LoadArrayFromDisk method. h. Write out a message to the console that states that the value of n0 is being incremented. i. Increment by 1 the value of the first element of nodes2. j. Call SaveArrayToDisk, and pass nodes2. k. Write out a message to the console that states that the application is leaving Scope6. 5. In the Main method of Ser, and after the call to the Scope4 method, add calls to Scope5 and Scope6. 6. Build the Serialization application. 7. Step through the application in the Visual Studio .NET debugger, and note console output similar to the following output:

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 12: Serialization


Entering Scope 1 Creating and filling List .. List: 1 2 3 4 5 6 7 8 9 Serializing LinkedList to file .. Leaving Scope 1 Entering Scope 2 Deserializing LinkedList from soap file .. Deserializing LinkedList from binary file .. List: 1 2 3 4 5 6 7 8 9 Swapping Entries Swapping 1 and 2 Swapping 3 and 4 Swapping 5 and 6 Swapping 7 and 8 List: 2 1 4 3 6 5 8 7 9 Serializing LinkedList to file .. Leaving Scope 2 Entering Scope 3 Deserializing LinkedList from soap file .. Deserializing LinkedList from binary file .. List: 2 1 4 3 6 5 8 7 9 Swapping Random Entries Swapping 8 and 7 Swapping 7 and 5 Swapping 6 and 5 Swapping 2 and 1 Swapping 1 and 8 Swapping 4 and 2 Swapping 2 and 3 Swapping 3 and 5 Swapping 9 and 4 Swapping 9 and 4 Swapping 6 and 8 Swapping 2 and 4 Swapping 2 and 1 Swapping 9 and 7 Swapping 1 and 5 List: 6 5 1 4 3 9 8 2 7 Serializing LinkedList to file .. Leaving Scope 3 Entering Scope 4 Deserializing LinkedList from soap file .. Deserializing LinkedList from binary file .. List: 6 5 1 4 3 9 8 2 7 Removing Entries Removing 1 Removing 2 Removing 3 List: 6 5 4 9 8 7 Serializing LinkedList to file .. Leaving Scope 4

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

25

Entering Scope 5 Creating a circular reference: n0's NextNode is n1 and n1's NextNode is n0 Also adding in a third node, n2, that is another reference to n0 Node 0 Value: 0 Value of NextNode Ref: 1 Node 1 Value: 1 Value of NextNode Ref: 0 Node 2 Value: 0 Value of NextNode Ref: 1 Serializing Array to file .. Leaving Scope 5 Entering Scope 6 Deserializing Array from file .. Node 0 Value: 0 Value of NextNode Ref: 1 Node 1 Value: 1 Value of NextNode Ref: 0 Node 2 Value: 0 Value of NextNode Ref: 1 changing value of node n0 to 42 should change value in both locations in array array's structure should be preserved during serialization and deserialization

Node 0 Value: 42 Value of NextNode Ref: 1 Node 1 Value: 1 Value of NextNode Ref: 42 Node 2 Value: 42 Value of NextNode Ref: 1 Serializing Array to file .. Deserializing Array from file .. Node 0 Value: 42 Value of NextNode Ref: 1 Node 1 Value: 1 Value of NextNode Ref: 42 Node 2 Value: 42 Value of NextNode Ref: 1 incrementing value of node n0 Node 0 Value: 43 Value of NextNode Ref: 1 Node 1 Value: 1 Value of NextNode Ref: 43 Node 2 Value: 43 Value of NextNode Ref: 1 Serializing Array to file .. Leaving Scope 6

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 12: Serialization

8. Using Visual Studio .NET, open and visually examine the Array.soap file in the bin\Debug subdirectory, and note the serialized array datas format, structure, and size.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 12: Serialization

27

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! ! ! ! ! ! ! ! !

Serialization Scenarios Serialization Attributes Object Graph Serialization Process Serialization Example Deserialization Example Custom Serialization Custom Serialization Example Security Issues

Lead-in
The review questions cover some of the key concepts taught in the module.

1. Declare a serializable class named Foo with two integer fields F1 and F2 in which F2 is transient and should not be serialized.
[Serializable] public class Foo { int F1; [NonSerialized] int F2;

2. Name and describe the two kinds of formatters that the .NET Framework provides. BinaryFormatter for a compact binary SoapFormatter for XML representation

3. Describe what a class should do to provide custom serialization. The class should inherit from the ISerializable interface, implement the interfaces GetObjectData method, and provide a constructor that takes SerializationInfo and StreamingContext parameters.

4. What kind of data that is not normally accessible by clients can be made visible by serialization? Private object state

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

THIS PAGE INTENTIONALLY LEFT BLANK

Module 13: Remoting and Web Services


Contents Overview Remoting Remoting Configuration Files Lab 13.1: Building an Order-Processing Application by Using Remoted Servers Web Services Lab 13.2: Using a Web Service Review 1 2 18 27 35 47 52

This course is based on the prerelease Beta 2 version of Microsoft Visual Studio .NET. Content in the final release of the course may be different from the content included in this prerelease version. All labs in the course are to be completed with the Beta 2 version of Visual Studio .NET.

Information in this document, including URL and other Internet Web site references, is subject to change without notice. Unless otherwise noted, the example companies, organizations, products, domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious, and no association with any real company, organization, product, domain name, e-mail address, logo, person, place or event is intended or should be inferred. Complying with all applicable copyright laws is the responsibility of the user. Without limiting the rights under copyright, no part of this document may be reproduced, stored in or introduced into a retrieval system, or transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or otherwise), or for any purpose, without the express written permission of Microsoft Corporation. Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual property rights covering subject matter in this document. Except as expressly provided in any written license agreement from Microsoft, the furnishing of this document does not give you any license to these patents, trademarks, copyrights, or other intellectual property. 2001 Microsoft Corporation. All rights reserved. Microsoft, MS-DOS, Windows, Windows NT, ActiveX, IntelliMirror, JScript, MSDN, MSN, PowerPoint, SQL Server, Visual Basic, Visual C++, Visual C#, Visual FoxPro, Visual Studio, Win32, and Windows Media are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries. The names of actual companies and products mentioned herein may be the trademarks of their respective owners.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

iii

Instructor Notes Module 13


Presentation: 120 Minutes Lab: 100 Minutes After completing this module, students will be able to:
!" !"

Write and configure distributed applications that use .NET Remoting. Create a Web Service by using Microsoft Visual Studio .NET and ASP.NET. Consume a Web Service by using the Web Services Description Language tool (Wsdl.exe).

!"

Materials and Preparation


This section provides the materials and preparation tasks that you need to teach this module.

Required Materials
To teach this module, you need the following materials: Microsoft PowerPoint file 2349A_13.ppt

Preparation Tasks
To prepare for this module, you should:
!" !" !"

Read all of the materials for this module. Practice the demonstrations. Complete the lab.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

iv

Module 13: Remoting and Web Services

Demonstrations
This section provides demonstration procedures that will not fit in the margin notes or are not appropriate for the student notes.

Remoting
In this demonstration, you will show students how a client application uses .NET Remoting to make a method call on an object in a server application. The code for this demonstration is contained in one project and is located in <install folder>\Democode\Mod13\Demo13.1. In addition, the code for the individual demonstration is provided in the student notes.

Using Visual Studio .NET to Create a Web Service


In this demonstration, you will show students how to use Visual Studio .NET to create a Web Service. The code for this demonstration is contained in one project and is located in <install folder>\Democode\Mod13\Demo13.2. In addition, the code for the individual demonstration is provided in the student notes. In both of the preceding demonstrations, use the debugger to step through the code while you point out features.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

Module Strategy
Use the following strategy to present this module:
!"

Remoting Use the diagram on the Remoting Overview slide to introduce the services that are provided by the Microsoft .NET Framework for use with remoting. You will cover each of these services in more detail in the subsequent slides in this section. Explain how channels and formatters are used to transmit data. Discuss how the remoting framework supports server-side and client-side activation of remote objects and describe the differences between server-side and clientside activation. Explain how to control the lifetime of client-activated remote objects by using a leasing mechanism. Discuss how objects are marshaled in .NET Remoting. Explain how to register and activate a remote object from the server side and the client side. Conclude this section with a brief discussion of client compilation techniques.

!"

Remote Configuration Files Discuss the use of configuration files in remoting. Do not spend time on the .NET Remoting configuration file format; instead refer students to the .NET Framework Software Developers Guide (SDK) documentation. Because the module is long, conclude this part of the lecture and instruct students to do Lab 13.1.

!"

Web Services Explain how to use Visual Studio .NET to implement an ASP.NET Web Service and how to access the Web Service from a Web browser and a client application. Use the Using Visual Studio .NET to Create a Web Service demonstration to illustrate the concepts that are covered in this section. Introduce the Web Service discovery process and the tools that are available for discovery.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

Overview
Topic Objective
To provide an overview of the module topics and objectives.
! ! !

Remoting Remoting Configuration Files Web Services

Lead-in
In this module, you will learn about distributed applications that use .NET Remoting.

Microsoft .NET Remoting provides a framework that allows objects to interact across remoting boundaries, for example, across application domains (AppDomain). Web Services is a term for communication that uses industry-standard HTTP and Simple Object Access Protocol (SOAP) protocols. You can implement Web Services by using remoting and by using ASP.NET. After completing this module, you will be able to:
!" !"

Write and configure distributed applications that use .NET Remoting. Create a Web Service by using Microsoft Visual Studio .NET and ASP.NET. Consume a Web Service by using the Web Services Description Language tool (Wsdl.exe).

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

# Remoting
Topic Objective
To provide an overview of the topics covered in this section.
! ! ! ! ! ! ! !

Remoting Overview Channels and Formatters Activation and Proxies Lease-Based Lifetime Object Marshaling Server-Side Client-Side Client Compilation Techniques

Lead-in
This section shows how .NET Remoting supports communication in various scenarios.

.NET Remoting supports communication in the following scenarios:


!" !" !"

Between objects in different application domains In different processes On different computers

The common language runtime remoting infrastructure provides a rich set of classes that enable you to ignore most of the complexities of deploying and managing remote objects. Even with applications that run against different runtime environments, the process of calling methods on remote objects is almost identical to the process of calling local methods.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

Remoting Overview
Topic Objective
To provide an overview of .NET Remoting.

Lead-in
The .NET Framework provides several services that are used in remoting.

Client AppDomain
Client Object Server Proxy Formatter

Server AppDomain
Formatter Server Object

Channel

Channel

Remoting Boundary

The .NET Framework provides several services that are used in remoting:
!"

Communication channels that are responsible for transporting messages to and from remote applications Formatters that encode and decode messages before they are transported by the channel Proxies that forward remote method calls to the proper object Remote object activation and lifetime support

!"

!" !"

Note Because the .NET context mechanism is beyond the scope of this course, this module does not cover remoting calls between contexts.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

Channels and Formatters


Topic Objective
To explain how channels and formatters are used to transmit data.
! !

Channels Transport Messages To and From Remote Objects Client Selects a Channel That Is Registered on the Server
$

Lead-in
Channels are used to transport messages to and from remote objects. Formatters are used to encode and serialize data into messages before transmission over a channel.
$

Before calling a remote object, the client registers the channel Channels are registered on a per application domain basis One computer cannot have multiple channels listening to same port HTTP Channel default: SOAP protocol to transport XML messages TCP Channel default:TCP protocol to transport binary messages Faster than HTTP SOAP Web Services but not as open

.NET Provides Implementation of HTTP and TCP Channels


$ $

Example: Programmatic Registration of TCP Channel on Port 8085

using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; using System.Runtime.Remoting.Channels.Tcp; TcpChannel chan = new TcpChannel(8085); TcpChannel chan = new TcpChannel(8085); ChannelServices.RegisterChannel(chan); ChannelServices.RegisterChannel(chan);

Channels are used to transport messages to and from remote objects. When a client calls a method on a remote object, the parameters, as well as other details that are related to the call, are transported through the channel to the remote object. Any results from the call are returned back to the client in the same way. Formatters are used to encode and serialize data into messages before they are transmitted over a channel.

Channel Selection
Because a client can use any of the channels that are registered on the server to communicate with a remote object, you can select the channels that best suit your needs. You can also customize any existing channel or build new ones that use different communication protocols. Channel selection is subject to the following rules:
!"

Channels must be registered before objects are registered. At least one channel must be registered with the remoting framework before a remote object can be called. Channels are registered on a per application domain basis. A single process may contain multiple application domains. When a process dies, all channels that it registers are automatically destroyed.

!"

!"

It is illegal to register a channel that listens on the same port on which another channel is currently listening. Though channels are registered on a per application domain basis, different application domains on one computer cannot register the same channel that listens on the same port.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

Clients can communicate with a remote object by using any registered channel. The remoting framework ensures that the remote object is connected to the proper channel when a client attempts to connect to it. The client is responsible for specifying a channel before it attempts to communicate with a remote object. To specify a channel, you can use a .NET Remoting configuration file, or you can call the RegisterChannel method on the ChannelServices class. The .NET Framework provides support for HTTP, TCP, and SMTP channels. Because .NET Remoting channels are pluggable, you can write and plug in additional channels with unique transport and encoding requirements.

Formatters Used to Encode and Decode Messages


Each channel provides a default formatter. However you can specify the formatter that you wish to use. Note A Uniform Resource Identifier (URI) is a compact representation of a resource that is available to your application through the Internet. You may be more familiar with the term, URL, which stands for Uniform Resource Locator. URLs form a subset of the more general URI naming scheme. A URL identifies an Internet resource that has a Web page address.

HTTP Channel
By default, the HTTP channel uses the SOAP protocol to transport messages to and from remote objects. All messages are passed through the SOAP formatter, where the message is changed into XML and serialized, and the required SOAP headers are added to the stream. Alternatively, you can specify the binary formatter, which results in a binary data stream. In either case, the data stream is then transported to the target URI by using the HTTP protocol. You can create industry-standard Web Services by using the HTTP channel with the default SOAP formatter.

TCP Channel
By default, the TCP channel uses a binary formatter to serialize all messages to a binary stream and transports the stream to the target URI by using the TCP protocol. Alternatively, you can specify the SOAP formatter, which results in an XML data stream. You can obtain better performance by using the TCP channel with the default binary formatter than you can by using Web Services.

Code Example
The following code example shows how to programmatically register a TCP Channel on port 8085 by using ChannelServices.RegisterChannel:
using System; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Tcp; //... TcpChannel chan = new TcpChannel(8085); ChannelServices.RegisterChannel(chan); //...

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

Activation and Proxies


Topic Objective
To show how the remoting framework supports serverside and client-side activation of remote objects and to describe the differences between serverside and client-side activation.
!

Before Using a Remote Object, the Client Must Activate It


$

By calling new, Activator.CreateInstance, or Activator.GetObject Proxy represents remote object in clients AppDomain Proxy forwards clients calls, and returns results and exceptions Single call object handles only one request (stateless) Singleton object services multiple clients and requests (stateful) State maintained between method calls for specific client instance

Activation Returns Proxy Used by Client to Access Remote Object


$ $

Lead-in
The remoting framework supports server-side and client-side activation of remote objects.

Server-Side Activation Automatic Instantiation by Server


$ $

Client-Side Activation Instantiation by Explicit Client Call


$

The remoting framework supports server-side and client-side activation of remote objects. Server-side activation means that when a client attempts to access the object, the object is instantiated on the server automatically. Client-side activation, on the other hand, means that the object is instantiated in response to a deliberate activation request from a client. You can select the best activation model to control the instantiation and lifetime of a remote object.

Methods of Remote Object Activation


Before a client can use a remote object, the remote object must be activated, and the client must obtain a proxy to access the remote object. You can activate a remote object by calling new or by calling the following methods of the Activator class:
!"

Activator.CreateInstance Used to create an object instance Activator.GetObject Normally used to connect to an object that is already running at a specified URI

!"

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

The Role of Proxies in Remote Object Interaction


When a client activates a remote object, the client obtains a proxy to the class instance on the server. Any interaction with a remote object occurs by reference through the proxy. The proxy object acts as a representative of the remote object and ensures that all calls that are made on the proxy are forwarded to the correct remote object instance. All methods that are called on the proxy are automatically forwarded to the remote class, and any results are returned to the client. From the clients perspective, this process is identical to the process of making a local call. Any exceptions that are thrown by the remote object are automatically returned to the client. Because those exceptions are returned to the client, the client can use normal try/catch blocks around sections of code to trap and handle exceptions.

Server-Side Activation
Server-side activation supports single call and singleton modes of activation.

Single Call Objects


A single call object services only one request. Single call objects are useful in scenarios in which:
!" !" !"

The overhead of creating an object is not significant. Objects are configured in a load-balanced fashion. State information is usually not needed between calls.

Because single call objects cannot hold state information between method calls, they are sometimes referred to as stateless objects.

Singleton Objects
A singleton object services multiple clients and multiple requests. Therefore, a singleton object can store state information between client invocations. Singleton objects are useful when you want to share data explicitly between clients and method invocations, and when the overhead of creating and maintaining objects is substantial. Because singleton objects can maintain their state over a prolonged period of time, they are sometimes referred to as stateful objects.

Client-Side Activation
Client-activated objects are activated on a request from the client. This method of activating server objects is similar to the classic COM coclass activation. The activation process is as follows: 1. When the client requests a server object, an activation request message is sent to the remote application. 2. The server then creates an instance of the requested class and returns an ObjRef object to the client application that invoked it. 3. A proxy is then created on the client side by using the ObjRef object.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

A client-activated object can store state information between method calls for its specific client. However, state information is not shared between multiple client-activated objects. Each request for a remote object instance returns a proxy to an independent instance of the server type. A useful function of client-activated objects is that constructor arguments can be passed by the local application to the constructor of the object in the remote application.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

Lease-Based Lifetime
Topic Objective
To explain how using a leasing mechanism can extend the lifetime of clientactivated remote objects.
!

A Leasing Mechanism Controls the Lifetime of a ClientActivated Remote Object An Objects Lease Time Can Be Extended When an Objects Lease Time Reaches Zero
$ $ $

Lead-in
You can control the lifetime of client-activated remote objects by using a leasing mechanism.

! !

The object is disconnected from remoting infrastructure The object may be garbage-collected A lease provides an alternative to reference counting

You can control the lifetime of client-activated remote objects by using a leasing mechanism. When an object is first created, it is given a lease time. When the lease time of the object reaches zero, the object is disconnected from the remoting infrastructure. After the references to the object from within the objects application domain have been freed, the object may be collected when the next garbage collection occurs. You can extend the lease on an object by using a number of mechanisms. For more information about extending the lease on an object, see Lease-Based Lifetime Concepts in the .NET Framework Software Developers Kit (SDK) documentation. You can use leases to manage the lifetime of remote objects as an alternative to reference counting, which tends to be complex and inefficient over unreliable network connections. A potential disadvantage of leasing is that the lifetime of a remote object may be extended for longer than is required. However, the advantages of reducing network traffic that is devoted to reference counting and the pinging of clients outweigh the disadvantage of the extended lifetimes of remote objects.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

10

Module 13: Remoting and Web Services

Object Marshaling
Topic Objective
To explain how objects are marshaled in .NET Remoting.
!

Lead-in
Because calls to a remote object can cause other objects to be passed across a remoting boundary, you should understand how objects are marshaled in .NET Remoting.
!

Objects Instantiated Remotely Are Returned by Reference and Accessed by the Client Through a Proxy Remote Call Parameters, Return Values, and Fields Can Be:
$

Marshal-by-value objects A copy of the object is passed from one AppDomain to another - Value types and classes that are serializable Marshal-by-reference objects A reference to the object is passed from one AppDomain to another - Classes that derive from the System.MarshalByRefObject class Not-marshaled objects Objects suitable for local use only - Any class that is not Marshal-By-Value or Marshal-By-Reference

Because calls to a remote object can cause other objects to be passed across a remoting boundary, you should understand how objects are marshaled in .NET Remoting. Inside the remoting boundary of the caller, for example, inside a single application domain, objects are passed by reference, and primitive data types are passed by value. Application domains are hard boundaries. Applications running in different application domains share no information, no global variables, and no static fields on classes. As mentioned in Remoting in this module, .NET Remoting is used to communicate between objects in different application domains. All objects that are instantiated remotely are returned by reference. When a client instantiates a remote object, it receives a proxy to the class instance on the server. All methods that are called on the proxy are automatically forwarded to the remote class, and any results are returned to the client. The following examples show scenarios where objects are passed across remoting boundaries because of calls to remote objects: The following scenarios are examples where objects are passed across a remoting boundary because of calls to remote objects:
!"

Object parameters in a method call, such as myObj in:


public int myRemoteMethod (MyRemoteObject myObj)

!"

Object return values of method calls, such as MyRemoteObject instances in:


public MyRemoteObject myRemoteMethod(String myString)

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services


!"

11

Objects that result from property or field access of a remote object, such as instances that are accessed in the myNestedObject field of myObj in:
myObj.myNestedObject

All objects in the .NET Framework fall into three general remoting categories: marshal-by-value, marshal-by-reference, and not-marshaled.

Marshal-By-Value Objects
Marshal-by-value objects include value types and classes that are serializable. A copy of such marshal-by-value objects is passed from one application domain to another. You should use marshal-by-value objects when you need to move the complete state of the object with the execution to the target application domain for performance or processing purposes. In many scenarios, marshal-by-value objects reduce boundary crossing, such as network, process, and application domain roundtrips. Marshal-by-value objects have no distributed identity, and no proxy is ever created to reference them, as shown in the following example:
[Serializable] class Foo1A { //. . . }

To participate in its own serialization when it is marshaled across application domain boundaries, an object can expose the ISerializable interface, as in the following example:
using System.Runtime.Serialization; //... [Serializable] class Foo1B : ISerializable { //. . . }

Marshal-By-Reference Objects
References to marshal-by-reference objects are made when the object reference (ObjRef) is passed from one application to another. When the object reference arrives in the remote application, it is converted to a proxy back to the original object. The original object remains in the application domain in which it was created. A marshal-by-reference objects class must derive from the System.MarshalByRefObject class. Use marshal-by-reference objects when an objects state should remain in the application domain in which it was created and when only references to that object should be marshaled at the time that the object is remoted. For example, make a file object, whose internal representation contains a field that is an OS handle, application domain-bound. In this case, the OS handle would not be useful or appropriate in another application domain, process, or computer.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

12

Module 13: Remoting and Web Services

All operations on a marshal-by-reference object are appropriately indirected so that the common language runtime can intercept and forward them. This indirection applies to fields, properties, and methods of marshal-by-reference objects. For this reason, the performance overhead of marshal-by-reference objects is greater than the performance overhead of marshal-by-value objects. The following example declares a class Foo2 that is marshal-by-reference:
class Foo2 : MarshalByRefObject { //. . . }

Not-Marshaled Objects
Not-marshaled objects are the default for all objects that do not derive from System.MarshalByRefObject and that do not have the [Serializable] custom attribute. The use of not-marshaled objects is appropriate when an object should not leave the application domain because the object was designed for local use only, as in the following example:
class Foo3 { //. . . }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

13

Server-Side
Topic Objective
To explain how to register and activate a remote object from the server side.
! !

Register the Channel Register Remote Objects by Using:


$

Lead-in
Remote objects must be registered with the remoting framework before clients can access them.

The RegisterWellKnownServiceType call

RemotingConfiguration.RegisterWellKnownServiceType( RemotingConfiguration.RegisterWellKnownServiceType( typeof(HelloServer), typeof(HelloServer), "SayHello", "SayHello", WellKnownObjectMode.SingleCall); WellKnownObjectMode.SingleCall);


$

Or a configuration file

RemotingConfiguration.Configure("MyHello.exe.config"); RemotingConfiguration.Configure("MyHello.exe.config");

All remote objects must be registered with the remoting framework before clients can access them. Object registration is normally performed by a hosting application that starts up, registers one or more channels with ChannelServices, registers one or more remote objects with RemotingServices, and then waits until it is terminated. Note The registered channels and objects are available only while the process that registered them is alive. When the process terminates, all channels and objects that are registered by this process are automatically removed from the remoting services where they were registered. The following information is required when you register a remote object with the remoting framework:
!" !" !"

The type name of the remote object The object URI that clients will use to locate the object For server-side activation, the object mode that is required The object mode can be single call or singleton.

Methods of Remote Object Registration


You can register a remote object by calling RemotingConfiguration.RegisterWellKnownServiceType, and passing the information that is described in the preceding list as parameters, or by storing that information in a configuration file and then calling RemotingConfiguration.Configure and passing the name of the configuration file as a parameter. RegisterWellKnownServiceType and Configure perform the same function, but Configure is more convenient to use because the contents of the configuration file can be altered without recompiling the host application.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

14

Module 13: Remoting and Web Services

RegisterWellKnownServiceType
The following example code shows how to register the HelloServer class as a SingleCall remote object by using the RegisterWellKnownServiceType method.
RemotingConfiguration.RegisterWellKnownServiceType( typeof(RemotingSamples.HelloServer), "SayHello", WellKnownObjectMode.SingleCall);

In the preceding example, RemotingSamples.HelloServer is the name of the class, and SayHello is the object URI.

Configuration File
The following example code shows how to register the HelloServer class as a SingleCall remote object by using the Configure method:
RemotingConfiguration.Configure("MyHello.exe.config");

In the preceding example, the configuration file, MyHello.exe.config stores the same registration information that is stored in the parameters of the preceding RegisterWellKnownServiceType method. The format of the .NET Remoting configuration file is described in Remoting Configuration Files in this module. When the remote object in the preceding example is registered, the remoting framework creates an object reference and then extracts the required metadata about the object from the assembly. The objects required metadata, the URI, and the assembly name are then stored in the object reference, which is filed in a remoting framework table that is used for tracking registered remote objects. Note The remote object itself is not instantiated by the registration process. Instantiation occurs only when a client attempts to call a method on the object or activates the object from the client side.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

15

Client-Side
Topic Objective
To explain how to register and activate a remote object from the client side.
!

Register the Channel

ChannelServices.RegisterChannel(new TcpChannel()); ChannelServices.RegisterChannel(new TcpChannel());


!

Lead-in
On the client side, a client registers the channel and activates the remote object. Activate Remote Object by Using:
$

Activator.GetObject

HelloServer obj = (HelloServer)Activator.GetObject( HelloServer obj = (HelloServer)Activator.GetObject( typeof(RemotingSamples.HelloServer), typeof(RemotingSamples.HelloServer), "tcp://localhost:8085/SayHello"); "tcp://localhost:8085/SayHello");
$

new and a configuration file

RemotingConfiguration.Configure("MyHello.exe.config"); RemotingConfiguration.Configure("MyHello.exe.config"); HelloServer obj = new HelloServer(); HelloServer obj = new HelloServer();

On the client side, a client registers the channel and activates the remote object.

Registering the Channel


A client must first register the channel by calling ChannelServices.RegisterChannel. As previously mentioned in Server-Side in this module, the server must first have registered the selected channel. The following code example shows how to register a TCP Channel:
ChannelServices.RegisterChannel(new TcpChannel());

Important You do not specify a port number when you register the client channel.

Activating Remote Objects


After the client registers the channel, it can then activate the remote object by using GetObject or the new operator. It is important to note that the object is not instantiated when either of these calls is made. Actually, no network calls are generated at all. The remoting framework obtains enough information from the metadata to create the proxy without connecting to the remote object. A network connection is only established when the client calls a method on the proxy. When the call arrives at the server, the remoting framework extracts the URI from the message, examines the remoting framework tables to locate the reference for the object that matches the URI, and then instantiates the object if necessary, forwarding the method call to the object. If the object is registered as SingleCall, it is destroyed after the method call is completed. For each method that is called, a new instance of the object is created.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

16

Module 13: Remoting and Web Services

The only difference between GetObject and new is that GetObject allows you to specify a URI as a parameter, while new obtains the URI from the configuration file. You can use CreateInstance or new for client-activated objects. Both CreateInstance and new allow you to instantiate an object by using constructors with parameters. The lifetime of client-activated objects is controlled by the leasing service that is provided by the remoting framework.

Using Activator.GetObject
The following example code shows how to obtain a server-activated object by using Activator.GetObject:
HelloServer obj = (HelloServer)Activator.GetObject( typeof(RemotingSamples.HelloServer), "tcp://localhost:8085/SayHello");

In the preceding example, "tcp://localhost:8085/SayHello" specifies that a connection should be made to the remote object at the SayHello endpoint by using TCP on port 8085.

Using the new Operator


To use the new operator, you must load a configuration file with the remote objects information. For example, for a file called MyHello.exe.config, you load the configuration file as follows:
RemotingConfiguration.Configure("MyHello.exe.config");

Once the configuration file has been loaded, the client can activate the object as follows:
HelloServer obj = new HelloServer();

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

17

Client Compilation Techniques


Topic Objective
To explain how type information is provided to the compiler.
!

Lead-in
When compiling the client code, the compiler requires type information about the HelloServer class.
!

When the Client Is Compiled, the Compiler Needs Server Class Data Class Information Can Be Provided by:
$ $

A reference to the assembly where the class is stored Splitting the remote object into an implementation class and an interface type Using Wsdl.exe to extract the required metadata directly from the endpoint

When compiling the client code, the compiler requires type information about the HelloServer class. This type information is discussed in the preceding topic. You can provide type information in one of the following ways:
!"

Provide a reference to the assembly in which the HelloServer class is stored. Providing a reference is useful when the client and server components are developed at the same site.

!"

Split the remote object into an implementation class and an interface type, and use the interface as a reference when compiling the client. Splitting the remote object into an implementation class and an interface type is useful when the client and server components are not developed at the same site. The interface or interfaces can be compiled to a DLL and shipped to the client sites when necessary. According to COM guidelines, you should avoid changing the published interface.

!"

Use the Web Services Description Language tool (Wsdl.exe) to extract the required metadata directly from the endpoint. The Web Services Description Language tool lets you connect to the endpoint that is provided, extract the metadata, and generate source code that can then be used to compile the client. The Web Services Description Language tool is useful when client and server components are developed at different sites and when no interface classes are available. To use the Web Services Description Language tool, simply point the tool at a remote URI and generate the required metadata.

Note The Web Service Utility extracts only metadata and does not generate the source for the remote object.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

18

Module 13: Remoting and Web Services

Remoting Configuration Files


Topic Objective
To explain how to configure objects with configuration files for use in remoting.
!

Configure Method on RemotingConfiguration An Application Configuration File is an XML Document $ Configuration files are case-sensitive. $ Can be specified on a machine or on an application level. Application level configuration takes priority over machine level configuration. For more information see Remoting Configuration File Format in the .NET Framework SDK documentation.

Lead-in
Programmatic registration is a simple process, but it is not practical for use in reallife situations where large numbers of remote objects must be managed on a corporate network.

RemotingConfiguration.Configure(foo.exe.config); RemotingConfiguration.Configure(foo.exe.config);
!

Programmatic registration is a simple process, but it is not practical for use in real-life situations where large numbers of remote objects must be managed on a corporate network. Remoting configuration solves this problem by using a configuration file, a simple mechanism, to register an object. To configure an object with a configuration file, call the Configure method on RemotingConfiguration, as shown in the following example:
using System; using System.IO; using System.Runtime.Remoting; public class MyHost { public static void Main(String[] args) { if (args.Length == 0) { // Perform a default configuration, throw an exception // or display usage information to the user } else { RemotingConfiguration.Configure (args[0]); } // The program should pause here till the // registered objects are no longer required } }

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

19

The Configure method loads the configuration file into memory, parses the contents, and calls the relevant methods to register the channels and objects that are described in the file. You can also use configuration files to store such settings as binding policy and security. The name of the configuration file includes the full module name and the extension, with .config appended to that extension. For example, the configuration file name for Foo.exe is Foo.exe.config. Although .NET Remoting does not mandate how you name a configuration file, you should use the naming convention that is described in the preceding paragraph to ensure that specific security and binding policies are picked up when an application is executed. The Configurecall on RemotingConfiguration only reads the relevant sections in the configuration file that apply to remoting, while the rest of the information is ignored. An application configuration file is an XML document that contains sections for various feature areas. The general format is a follows: Note Configuration files are case-sensitive.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

20

Module 13: Remoting and Web Services


<configuration> <system.runtime.remoting> <application> <lifetime> <!--Default lifetime information for all --> <!--objects in the application. Individual --> <!--service objects can customize these --> </lifetime> <service> <!--Specifies one or more remote objects provided by --> <!--this service. These can be client-activated --> <!--as well as server-activated --> </service> <client url = http://someserver/endpoint1 <!--Specifies a remote object this client used --> <!--One or more clients can be specified --> </client> <client url = "http://someserver/endpoint2" </client> <SOAPinterop> <!--Specify type, assembly and XML information --> <!--to use deserializing data from SOAP endpoints --> </SOAPinterop> <channels> <!--List all channels the client or service require.--> <!-Individual clients or services can customize the --> <!-machine level settings --> </channels> </application> <channels> <!--Provide a list of the channel and sink providers.--> <!--This data will normally be provided on a machine --> <!--level in the machine configuration file --> </channels> <channelSinkProviders> <clientProviders> <!one or more client providers --> </clientProviders> <serverProviders> <!one or more server providers --> </serverProviders> </channelSinkProviders> </system.runtime.remoting> </configuration>

All configuration information can be specified on a machine or on an application level. Application level configuration takes priority over machine level configuration. For more information about the .NET Remoting configuration file format, see Remoting Configuration File Format in the .NET Framework SDK documentation.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

21

Demonstration: Remoting
Topic Objective
To demonstrate how a client application uses .NET Remoting to make a method call on an object in a server application.

Lead-in
This demonstration shows how a client application uses .NET Remoting to make a method call on an object in a server application.

This demonstration shows how a client application can use .NET Remoting to make a method call on an object in a server application. Delivery Tip
Although this demonstration includes detailed instructions, this is not a guided practice. Present the demonstration and suggest that the students try the demonstration for themselves later.

Important Before running the application, ensure that all currently running server applications that may be using the same port number have been closed. Running more than one server that uses the same port number will generate an error.

Server-Side
The following sample code is the server source code, which is named Server.cs:

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

22

Module 13: Remoting and Web Services


using using using using using System; System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp; System.Runtime.Remoting.Channels.Http;

namespace RemotingSamples { public class HelloServer : MarshalByRefObject { public int callCounter = 0; public static int Main(string [] args) { TcpChannel chan1 = new TcpChannel(8085); HttpChannel chan2 = new HttpChannel(8086); ChannelServices.RegisterChannel(chan1); ChannelServices.RegisterChannel(chan2); /* RemotingConfiguration.RegisterWellKnownServiceType ( typeof(HelloServer), "SayHello", WellKnownObjectMode.Singleton ); */ //Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services


RemotingConfiguration.RegisterWellKnownServiceType( typeof(HelloServer), "SayHello", WellKnownObjectMode.SingleCall );

23

System.Console.WriteLine("Press Enter key to exit"); System.Console.ReadLine(); return 0; } public HelloServer() { Console.WriteLine("HelloServer activated"); } public String HelloMethod(String name, out int counter) { counter = ++callCounter; Console.WriteLine( "Server Hello.HelloMethod : {0} Counter :{1}", name, callCounter); return "Hi there " + name; } } }

The RemotingSamples.HelloServer class is derived from MarshalByRefObject, so HelloServer is remotable. When the server is started, you create and register a TCP channel that listens for clients to connect on port 8085 and an HTTP channel that listens for clients to connect on port 8086. You also register the remote object with the remoting framework by calling RegisterWellKnownServiceType. The parameters for this call include the following:
!"

The full type of the object that is being registered, such as RemotingSamples.HelloServer in the preceding example The name of the endpoint where the object will be published To connect to the object, clients must know the name of the endpoint. Any string can be used. In the preceding example, you use SayHello. You can also connect to remote objects through ASP.NET. In the preceding example, if you were connecting to remote objects through ASP.NET, the endpoint would be RemotingSamples/HelloServer.soap.

!"

!"

The object mode, which can be SingleCall or Singleton In the preceding example, you initially specify SingleCall. The object mode specifies the lifetime of the object when it is activated on the server. In the case of SingleCall objects, a new instance of the class is created for each call that is made from a client, even if the same client calls the same method more than once. Singleton objects, on the other hand, are created only once, and all clients communicate with the same object.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

24

Module 13: Remoting and Web Services

Client-Side
The following sample code is the client source code, which is named Client.cs:
using using using using using using System; System.Runtime.Remoting; System.Runtime.Remoting.Channels; System.Runtime.Remoting.Channels.Tcp; System.Runtime.Remoting.Channels.Http; System.IO;

namespace RemotingSamples { public class Client { public static int Main(string [] args) { int counter; TcpChannel chan1 = new TcpChannel(); ChannelServices.RegisterChannel(chan1); HelloServer obj1 = (HelloServer)Activator.GetObject( typeof(RemotingSamples.HelloServer), "tcp://localhost:8085/SayHello"); if (obj1 == null) { System.Console.WriteLine( "Could not locate TCP server"); return 1; }

HttpChannel chan2 = new HttpChannel(); ChannelServices.RegisterChannel(chan2); HelloServer obj2 =(HelloServer)Activator.GetObject( typeof(RemotingSamples.HelloServer), "http://localhost:8086/SayHello"); if (obj2 == null) { System.Console.WriteLine( "Could not locate HTTP server"); return 1; } //Code continued next page

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services


try { Console.WriteLine( "Client1 TCP HelloMethod {0} Counter {1}", obj1.HelloMethod("Caveman", out counter), counter); Console.WriteLine( "Client2 HTTP HelloMethod {0} Counter {1}", obj2.HelloMethod("Caveman", out counter), counter); } catch (IOException ioExcep) { Console.WriteLine("Remote IO Error" + "\nException:\n" + ioExcep.ToString()); return 1; } return 0; } } }

25

When the client starts up, it registers a TCP channel and an HTTP channel and proceeds to activate an object on each channel by calling the GetObject method on the Activator class. The parameters for this call are the type of the name of the class that you need to activate, RemotingSamples.HelloServer, and the endpoint URI. For the clients TCP connection, the URI is simply tcp://localhost:8085/SayHello For the clients HTTP connection, the URI is http://localhost:8086/SayHello Important The URI includes the protocol, computer name, and port number, as well as the endpoint. If the server is deployed on a host that is named Sunshine, clients can connect to the server that is using TCP by specifying tcp://sunshine:8085/SayHello When you run the client, it locates and connects to the server, retrieves a proxy for the remote objects, and calls the HelloMethod on the remote objects, passing the string Caveman as a parameter and the counter as an out parameter. The server returns Hi there Caveman and the count of the number of times that the server objects method has been called.

Building and Executing the Server and Client


To build the server and the client in the same directory, enter the following command at the command prompt:
csc server.cs csc /r:server.exe client.cs

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

26

Module 13: Remoting and Web Services

To execute the application, start the server application from a console window, and then start the client application from another console window. Note The counter values on the two client calls should have the same value because the server objects activation mode is SingleCall.

Changing the Activation Mode


To change the servers activation mode from SingleCall to Singleton, change the RegisterWellKnownServiceType call in the server as follows:
RemotingConfiguration.RegisterWellKnownServiceType( typeof(HelloServer), "SayHello", WellKnownObjectMode.Singleton);

Rebuild and execute as in the preceding example. Note the counter values on both calls. They should increase after each call.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

27

Lab 13.1: Building an Order-Processing Application by Using Remoted Servers


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will create a Web Service hosted in a .NET executable file, create a TCP server, and create a client that uses .NET Remoting to access a Web Service and a TCP server.

Objectives
After completing this lab, you will be able to:
!" !" !"

Create a Web Service hosted in a .NET executable file. Create a TCP server. Create a client that uses .NET Remoting to access both a Web Service and a TCP server.

Lab Setup
Only solution files are associated with this lab. The solution files for this lab are in the folder <install folder>\Labs\Lab13.1\Solution.

Scenario
This lab is based on a scenario of a simple distributed order-processing application, in which a customer specifies a customer ID and an item number for an item that the customer wants to purchase, and the application processes the order. The order processing involves authenticating the customers ID and arranging order fulfillment, that is to say, having the ordered item sent to the customer.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

28

Module 13: Remoting and Web Services

In this lab, you will create a distributed solution that uses .NET Remoting. You will use .NET Remoting support of SOAP over HTTP to create a server application that exports an authenticate method as an open standards-based Web Service. You will also use .NET Remoting support of TCP with binary formatting to create a remote order fulfillment server application that trades off the advantages of the open standards-based flexible Web Services protocol for improved performance. In addition, you will create a simple test client to exercise these servers. Because the focus of this lab is on .NET Remoting, the functionality that is specific to authentication and fulfillment will be minimal.

Estimated time to complete this lab: 50 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

29

Exercise 1 Creating an Authentication Web Service


In this exercise, you will create a Web Service that provides simple authentication. Simple authentication will consist of using a random-number generator to authenticate the user successfully 50 percent of the time.

!" Create the Authentication Server To


1. Using the editor of your choice, create a C# source file named Authenticate.cs, and save it in the Lab13.1 directory. 2. To simplify coding, add using statements to import the namespaces System, System.Runtime.Remoting, System.Runtime.Remoting.Channels, and System.Runtime.Remoting.Channels.Http. 3. Specify the namespace Lab13, and in it, create a class named AServer that is marshal-by-reference. 4. Add a field named aRandom to hold a reference to a random-number generator object of class System.Random. 5. In the Main method of AServer: a. Create and register a channel that supports the protocol and format for a Web Service. Specify port 8086. b. Invoke the RemotingConfiguration.RegisterWellKnownServiceType method to register the authentication server whose full type name is Lab13.AServer, and whose endpoint is DoAuthentication. To retain the objects state, that is to say, the random-number generator object, over multiple client calls, the well-known objects mode should be stateful. c. Print to the console a message that tells the user to press any key so the server exits. The program should wait for this user action before continuing. 6. Add a constructor that creates a new instance of the Random class, assigns it to the field that was created in step 4, and prints a message to the console that states that AServer is running.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

30

Module 13: Remoting and Web Services

7. Add a public method named Authenticate that takes a customer ID of type int and returns a bool value. a. Assign to a variable named aRandomNumber of type double a random number that is equal to 0 and is less than 1, by using the following code:
double aRandomNumber = aRandom.NextDouble();

b. Using the value from step a, assign to a variable of type bool named passed the value true for 50 percent of the time and the value false for 50 percent of the time. c. Print to the console a message that identifies the customer and states whether the customer is authenticated on the basis of the value of passed. d. Return passed. 8. In a console window, build Authenticate.exe.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

31

Exercise 2 Creating a Fulfillment Server


In this exercise, you will create a server that provides simple order fulfillment functionality by using TCP and a binary format to provide fast communication. Simple fulfillment will consist of using a random-number generator to successfully fulfill the order 50 percent of the time.

!" Create the Fulfillment Server To


1. Using the editor of your choice, create a C# source file that is named Fulfillment.cs, and save it in the Lab13.1 directory. 2. To simplify coding, add using statements to import the namespaces System, System.Runtime.Remoting, System.Runtime.Remoting.Channels, and System.Runtime.Remoting.Channels.Tcp. 3. Specify the namespace Lab13, and in it, create a class named FServer that is marshal-by-reference. 4. Add a field named aRandom to hold a reference to a random-number generator object of class System.Random. 5. In the Main method of FServer: a. Create and register a channel that uses the TCP protocol and binary formatting. Specify port 8085. Note You cannot have two channels on one computer that are using the same port number; therefore you cannot use port 8086. b. Invoke the RemotingConfiguration.RegisterWellKnownServiceType method to register the fulfillment server whose full type name is Lab13.FServer, and whose endpoint is DoFulfillment. To retain the objects state, that is to say, the random-number generator object, over multiple client calls, the well-known objects mode should be stateful. c. Print to the console a message that tells the user to press any key so the server exits. The program should wait for this user action before continuing. 6. Add a constructor that creates a new instance of the Random class, assigns it to the field that was created in step 4, and prints a message to the console that states that FServer is running.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

32

Module 13: Remoting and Web Services

7. Add a public method named Fulfill that takes a customer ID of type int, an item number of type int, and returns a bool value. a. Assign to a variable named aRandomNumber of type double a random number that is equal to 0 and less than 1, by using the following code:
double aRandomNumber = aRandom.NextDouble();

b. Using the value from step a, assign to a variable of type bool named shipped the value true for 50 percent of the time and the value false for 50 percent of the time. c. Print to the console a message that identifies the customer and the item number and states whether the item was shipped on the basis of the value of shipped. d. Return shipped. 8. In a console window, build Fulfillment.exe.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

33

Exercise 3 Creating a Test Client


In this exercise, you will create a test client application to test the orderprocessing servers. The client calls the authentication Web Service. If the user is authenticated, the client calls the order fulfillment server.

!" create the test client To


1. Using the editor of your choice , create a C# source file named Testclient.cs, and save it in the Lab13.1 directory. 2. To simplify coding, add using statements to import the namespaces System, System.Runtime.Remoting, System.Runtime.Remoting.Channels, System.Runtime.Remoting.Channels.Http, System.Runtime.Remoting.Channels.Tcp, and System.IO. 3. Specify the namespace Lab13, and in it, create a class named TestClient. In subsequent steps of this exercise, you will code the Main method. 4. In the Main method of TestClient: Create and register an HTTP channel and a TCP channel. 5. Invoke the Activator.GetObject method to create an AServer instance of type Lab13.AServer named aServer at the following URL:
http://localhost:8086/DoAuthentication

6. Invoke the Activator.GetObject method to create an FServer instance of type Lab13.FServer named fServer at the URL:
tcp://localhost:8085/DoFulfillment

7. In the try section of a try/catch block: a. Invoke the Authenticate method of the aServer object, and use 1234 as the customers ID. Print a message with the result to the console. b. If authentication passes, call the fServer objects Fulfill method. Use 1234 as the customers ID and 5678 as the item number. Print a message with the result to the console. 8. In the catch section of the try/catch block: a. Catch any exceptions of type IOException, and print out their content. b. Return a value of 1. 9. In a console window, build Testclient.exe. Important Do not forget to reference Authenticate.exe, and Fulfillment.exe in the command line.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

34

Module 13: Remoting and Web Services

10. Test the order system. a. Ensure that no server application is running and listening on ports 8085 and 8086. b. Open two separate console windows. In one window, run Fulfillment.exe, and in the other window, run Authenticate.exe. c. Open a third console window and repeatedly run Testclient.exe. The console output will vary because the random-number generator values cause authentication and fulfillment to succeed or fail 50 percent of the time. A typical series of test client invocations would produce output similar to the following:
>testclient Authentication Server Customer 1234 Authorization: False >testclient Authentication Server Customer 1234 Authorization: False >testclient Authentication Server Customer 1234 Authorization: False >testclient Authentication Server Customer 1234 Authorization: True Fulfillment Server Customer 1234 Item Number 5678 Shipped: False >testclient Authentication Server Customer 1234 Authorization: True Fulfillment Server Customer 1234 Item Number 5678 Shipped: False >testclient Authentication Server Customer 1234 Authorization: True Fulfillment Server Customer 1234 Item Number 5678 Shipped: True

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

35

# Web Services
Topic Objective
To provide an overview of the topics covered in this section.
! ! ! !

ASP.NET Web Services Overview ASP.NET Features Consuming a Web Service Web Service Discovery

Lead-in
In this section, you will learn how to use Visual Studio .NET to implement an ASP.NET Web Service and how to access the Web Service from a Web browser and a client application.

Web Services can be provided by and accessed from applications that reside in a variety of hosts. Hosts include, but are not limited to, ASP.NET, Microsoft Internet Explorer, executable files, Microsoft Windows NT Server, and Microsoft Windows 2000 Component Services, also known as COM+ Services. In the preceding sections, you have learned how to use .NET Remoting to create executable files that host Web Services by simply using the default HTTP channel with SOAP formatting. In this section, you will learn how to use Visual Studio .NET to implement an ASP.NET Web Service and how to access this Web Service from both a Web browser and a client application.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

36

Module 13: Remoting and Web Services

ASP.NET Web Services Overview


Topic Objective
To provide an overview of ASP.NET Web Services.
! !

ASP.NET Files with .asmx Extensions Are Web Services Example of HelloWorld .asmx File

Lead-in
ASP.NET provides support for Web Services with the .asmx file, which is a text file that is similar to an .aspx file.

<%@ WebService Language="C#" Class="HelloWorld" %> <%@ WebService Language="C#" Class="HelloWorld" %> using System; using System; using System.Web.Services; using System.Web.Services; public class HelloWorld : WebService { public class HelloWorld : WebService { [WebMethod] public String SayHelloWorld() { [WebMethod] public String SayHelloWorld() { return "Hello World"; return "Hello World"; } } } }
!

If File Is Placed on Server Foo Inside a Virtual Directory Bar


$

Access service by using: Access WSDL of service by using:

http://Foo/Bar/HelloWorld.asmx http://Foo/Bar/HelloWorld.asmx
$

http://Foo/Bar/HelloWorld.asmx?wsdl http://Foo/Bar/HelloWorld.asmx?wsdl

This section introduces some of the basic features of ASP.NET that enable developers to host and use Web Services. The Internet is quickly evolving from its present stage where Web sites simply deliver user interface (UI) pages to Web browsers to a next generation of programmable Web sites that directly link organizations, applications, services, and devices. These programmable Web sites are more than passively accessed sites: They are reusable, intelligent Web Services.

Using .asmx Files


ASP.NET provides support for Web Services with the .asmx file. An .asmx file is a text file that is similar to an .aspx file. An .asmx file can be part of an ASP.NET application that includes .aspx files. Like .aspx files, .asmx files are automatically compiled by the ASP.NET runtime when a request to the service is made. Subsequent requests are serviced by a cached pre-compiled type object. Like .aspx files, .asmx files are then URI-addressable.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

37

Delivery Tip
You can demonstrate the SayHelloWorld service by cutting and pasting the HelloWorld.asmx code into Notepad and saving it as a file named HelloWorld.asmx in the source directory for an existing IIS virtual directory. You then enter the appropriate URL in the Internet Explorer Address bar. To make the Address bar visible, click the View menu, point to Toolbars, and then click Address Bar.

The following example shows the code that is contained in the HelloWorld.asmx file. It is a simple example of a ASP.NET-hosted Web Service.
<%@ WebService Language="C#" Class="HelloWorld" %> using System; using System.Web.Services; public class HelloWorld : WebService { [WebMethod] public String SayHelloWorld() { return "Hello World"; } }

The HelloWorld.asmx file starts with an ASP.NET directive, WebService, and sets the language to C#. You can also set the language to Microsoft Visual Basic. The class HelloWorld contains the Web Service and therefore is derived from the base class WebService in the System.Web.Services namespace. All of the methods that will be accessible as part of the service must have the custom attribute, [WebMethod], in front of their signatures. In the preceding example, the SayHelloWorld method is the services only method.

Using a Virtual Directory


To create an ASP.NET application, you can use an existing virtual directory or create a new one. For example, if you installed Windows 2000 Server and Internet Information Server (IIS) on a computer, that computer probably now has the directory C:\InetPub\WWWRoot. To configure IIS, click Start, point to Programs, click Administrative Tools, and then click Internet Services Manager. In the Internet Services Manager, you can create a new virtual directory or promote an existing directory.
!"

To create a new virtual directory, right-click an existing directory, and click New. To promote an existing directory, right-click a virtual directory, and click Properties and set the Local Path.

!"

If you place the HelloWorld.asmx file on a server called Foo inside a virtual directory called Bar, you can use a URL in Internet Explorer to test the application. For example, if you enter http://Foo/Bar/HelloWorld.asmx in the Address bar, the resulting page shows the public methods for this Web Service and the protocols, such as SOAP or HTTP GET, that you can use to invoke these methods. The public methods for the Web Service are marked with the [WebMethod] attribute. The Web Services Description Language XML file for this service is produced when you enter http://Foo/Bar/HelloWorld.asmx?WSDL in the Internet Explorer Address bar. This WSDL file is important and can be used by clients to access the service.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

38

Module 13: Remoting and Web Services

ASP.NET Features
Topic Objective
To explain how to create a Web Service by exposing a .NET class that inherits from the WebService class, and to introduce advanced ASP.NET features.
!

ASP.NET Can Expose Web Services Defined in a .NET Class

Lead-in
In ASP.NET, you can create a Web Service by simply exposing a .NET class that inherits from the WebService class.

$ Class derives from WebService, method attribute [WebMethod] namespace MyNameSpace { namespace MyNameSpace { public class HelloWorld : WebService { public class HelloWorld : WebService { [WebMethod] public String SayHelloWorld() { [WebMethod] public String SayHelloWorld() { return "Hello World"; } return "Hello World"; } } } } } $ Class source file is compiled into a library DLL and placed in \Bin

csc /out:bin\helloworld.dll /t:library helloworld.cs csc /out:bin\helloworld.dll /t:library helloworld.cs


$

The .asmx file contains a single line that names the class

<%@ WebService Class="MyNameSpace.HelloWorld" %> <%@ WebService Class="MyNameSpace.HelloWorld" %>


!

Advanced ASP.NET Features


$

Data sets, Global.asax, Session and Application objects, pattern matching

In ASP.NET, you can create a Web Service by simply exposing a .NET class that inherits from the WebService class. You compile the classs source file into a library DLL and place this DLL in the ASP.NET applications \Bin subdirectory. You then create in the ASP.NET applications directory an .asmx file that contains only the following single line of code:
<%@ WebService Class="<namespace>.<classname>" %>

The HelloWorld.cs source code defines a HelloWorld service with an exported SayHelloWorld method in the MyNameSpace namespace, as shown in the following example:
using System; using System.Web.Services; namespace MyNameSpace { public class HelloWorld : WebService { [WebMethod] public String SayHelloWorld() { return "Hello World"; } } }

To compile this HelloWorld.cs file in the ASP.NET application directory, you enter the following command:
>csc /out:bin\helloworld.dll /t:library helloworld.cs

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

39

You then create the file named HelloWorld.asmx in the ASP.NET application directory. HelloWorld.asmx contains the following single line of code:
<%@ WebService Class="MyNameSpace.HelloWorld" %>

The only methods that are exposed from a service are those class methods that are flagged with a [WebMethod] custom attribute. Without this attribute, the method is not exposed from the service. Not exposing a method from a service is useful when you want to hide implementation details that are called by public Web Service methods or when the WebService class is also used in local applications. Note A local application can use any public method, but only [WebMethod] methods are remotely accessible through SOAP.

Advanced ASP.NET Features


ASP.NET is also useful for building complex Web Services. Advanced ASP.NET features include:
!"

Data sets Data sets are a powerful new XML-based technique to represent disconnected data. Data sets can be returned from a Web Service method. Because Data sets can store complex information and relationships in an intelligent structure, they enable you to take full advantage of Web Services. When you expose Data sets through a service, you can limit the database connections to your data server.

!"

Global.asax file The Global.asax file adds application-level logic and event-handling code to Web applications.

!"

Session and Application objects You can use ASP.NET intrinsics, such as the Session and Application objects, to manage an ASP.NET applications state.

!"

Text Pattern Matching Text Pattern Matching is a technology that can be used to address any URI that returns text as if it were a Web Service.

Further discussion of these and other advanced ASP.NET features is beyond the scope of this course.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

40

Module 13: Remoting and Web Services

Demonstration: Using Visual Studio .NET to Create a Web Service


Topic Objective
To demonstrate how to use Visual Studio .NET to create a Web Service.

Lead-in
In this demonstration, you will learn how to create a service called MathService that has a single method named SalesTax.

In this section, you have learned how to create a Web Service by using ASP.NET. Visual Studio .NET provides an even easier way to build ASP.NEThosted Web Services. In this demonstration, you will see how to create a service called MathService that has a single method named SalesTax. The SalesTax method takes two parameters: The first parameter represents the sales amount; and the second parameter represents the fractional sales tax rate. For example, a sales tax rate of 8.5 percent is represented as .085. SalesTax returns a total amount that is equal to the sales amount plus the sales tax.

!" create a service called MathService that has a single method named To
SalesTax Delivery Tip
Although this demonstration includes detailed instructions, it is not a guided practice. Present the demonstration and suggest that students try the demonstration for themselves later.

1. Start Visual Studio, and create a new project. a. In the New Project dialog box, select Visual C# Projects as the type. b. Select ASP.NET Web Service as the template. You may need to scroll down to see Web Service. c. Set the Name field to MathService. d. Set the Location field to http://<machinename>. 2. On the View menu, click Code. Because the Web Service in this demonstration is simple, you can work on the code directly. For more complex Web Services, you can use the Service1.asmx.cs Design palette that is displayed when you create a new project of type Web Service. The Service1.asmx.cs Design palette enables the drag-and-drop operation of rapid application development that can make complex services easier to set up. 3. In the Service1 class, examine the HelloWorld method in the commentedout WEB SERVICE EXAMPLE.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

41

4. In Service1.asmx.cs, implement the SalesTax method by inserting the following code after the comments for the HelloWorld method. You should leave the HelloWorld code commented out.
[WebMethod] public float SalesTax( float salesAmount, float fractionalTaxRate) { return salesAmount + (salesAmount * fractionalTaxRate); }

5. On the Build menu, click Build to create the Web Service. 6. Use Internet Explorer to access the Web Service at the following URL:
http://localhost/MathService/Service1.asmx

Tip To use Internet Explorer to view a Web Service from within the Visual Studio environment, right-click the .asmx file in the Solution Explorer window, and click View in Browser. 7. In the Internet Explorer page that is returned in step 6, click on the link for the Service1 operation labeled SalesTax. 8. In the Internet Explorer page that is returned in step 7, enter some parameters, and click Invoke to verify that the correct value is returned and displayed in SOAP/XML format. 9. Use Internet Explorer to access and verify that the Web Services description is obtained from the following URL:
http://localhost/MathService/Service1.asmx?wsdl

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

42

Module 13: Remoting and Web Services

Consuming a Web Service


Topic Objective
To explain how Web Services are consumed and how to use the Web Services Description Language tool.
!

To Consume a Web Service, Use Wsdl.exe

$ Identify the object or service URI to be used http://localhost/MathService/Service1.asmx http://localhost/MathService/Service1.asmx $

Run Wsdl.exe on the services URI

Lead-in
In addition to providing technology that enables you to create Web Services, the .NET Framework provides a sophisticated set of tools and code to consume Web Services.

wsdl http://localhost/MathService/Service1.asmx?wsdl wsdl http://localhost/MathService/Service1.asmx?wsdl


$ Write the client code that calls the remote object Service1 salesTaxService = new Service1(); Service1 salesTaxService = new Service1(); float totalAmount = salesTaxService.SalesTax( float totalAmount = salesTaxService.SalesTax( amount,taxRate); amount,taxRate); $

Build the client and proxy code

csc salestaxclient.cs service1.cs csc salestaxclient.cs service1.cs

In addition to providing technology that enables you to create Web Services, the .NET Framework provides a sophisticated set of tools and code to consume Web Services. Consuming a Web Service means accessing it as a client. Because Web Services are based on open protocols, such as SOAP and HTTP, this client technology can also be used to consume Web Services that are not built by using the .NET Framework.

Using the Web Services Description Language Tool


The .NET Framework SDK provides a tool that is called the Web Services Description Language tool (Wsdl.exe). You can use this tool to download the WSDL description of a Web Service and create a proxy class that addresses this service. For Web Services that are created by using ASP.NET, the proxy class is similar to the class that is defined in the .asmx file. However, the proxy class contains only methods with the [WebMethod] custom attribute. An application that wants to use a Web Service creates an instance of the services proxy class and invokes the services methods as it would with any local object. You compile and build your code with this proxy class included. Alternatively, you can use features of the Visual Studio environment to build applications that consume Web Services. These Visual Studio features are beyond the scope of this course.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

43

The following process shows how to create a simple application that uses the Web Service that is created in the Using Visual Studio to Create a Web Service demonstration in this module. Delivery Tip
The use of the Web Services Description Language tool (Wsdl.exe) is covered in detail because the students will need this information to do Lab 13.2, Using a Web Service. If you feel that students may benefit from a full demonstration, you can demonstrate the steps here.

!" use the Service1 Web Service To


1. Identify the object and the service that should be used. The Salestaxclient application will use the SalesTax method of the Service1 service whose URL is:
http://localhost/MathService/Service1.asmx

Note Typically a client uses a Web Service that is located on a remote computer. If Service1 were located in a MathService virtual directory on a Web server named foo, the URL for the service would be:
http://foo/MathService/Service1.asmx

2. Run the WSDL tool, Wsdl.exe, and point it at the URL where the server object is located. You can request that the Web Service Utility retrieves the schema and, from it, generates a source file that contains a proxy for the services class. 3. To generate a proxy for the Service1 class in a file named Service1.cs, enter the following command:
wsdl http://localhost/MathService/service1.asmx?wsdl

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

44

Module 13: Remoting and Web Services

The proxy, Service1.cs, contains the following code:


//... using using using using System.Xml.Serialization; System; System.Web.Services.Protocols; System.Web.Services;

[System.Web.Services.WebServiceBindingAttribute! (Name="Service1Soap", Namespace="http://tempuri.org/")] public class Service1 : System.Web.Services.Protocols.SoapHttpClientProtocol { //... public Service1() { this.Url = "http://localhost/mathservice/service1.asmx"; } //... [System.Web.Services.Protocols.SoapDocumentMethodAttribute ! ("http://tempuri.org/SalesTax", Use=System.Web.Services.Description.SoapBindingUse.Literal, ParameterStyle= System.Web.Services.Protocols.SoapParameterStyle.Wrapped)] public System.Single SalesTax(System.Single salesAmount, System.Single fractionalTaxRate) { object[] results = this.Invoke("SalesTax", new object[] {salesAmount, fractionalTaxRate}); return ((System.Single)(results[0])); } //...

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

45

4. Write the client code that calls the remote object. This code is contained in Salestaxclient.cs, as follows:
using System; public class Class1 { public Class1() {} public static int Main(string[] args) { Console.WriteLine("Enter Sales Amount:"); float amount = Single.Parse(Console.ReadLine()); Console.WriteLine( "Enter Fractional Sales Tax Rate:"); float taxRate = Single.Parse(Console.ReadLine()); Service1 salesTaxService = new Service1(); float totalAmount = salesTaxService.SalesTax(amount,taxRate); Console.WriteLine( "Total: {0}",totalAmount.ToString()); return 0; } }

5. Build the client executable file by using the client code and proxy code. You must include references to the assemblies that are used by the client and proxy code. 6. To build Salestaxclient.exe, enter the following command:
csc salestaxclient.cs service1.cs

7. Run the client, and enter parameters as prompted. Running Salestaxclient.exe produces output that should be similar to the following:
salestaxclient Enter Sales Amount: 100 Enter Fractional Sales Tax Rate: .08 Total: 108

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

46

Module 13: Remoting and Web Services

Web Service Discovery


Topic Objective
To introduce the Web Service discovery process and the tools that are available for discovery.
!

Discovery The Process of Locating and Interrogating Web Service Descriptions Discovery Services Are Evolving and Changing Rapidly Disco Microsofts Web Services Discovery Tool
$

! !

Lead-in
Web Service discovery is the process of dynamically locating and interrogating Web Service descriptions, which is a preliminary step for accessing a Web Service.

Disco file is an XML document that links to descriptions of Web Services Disco file is currently created and used by Visual Studio Open framework for describing services, discovering businesses, and integrating business services that use the Internet Cross-industry support and platform independence For more information, see http://www.uddi.org

Universal Description, Discovery, and Integration Project


$

$ $

Web Service discovery is the process of dynamically locating and interrogating Web Service descriptions, which is a preliminary step for accessing a Web Service. The discovery process allows a Web Service client that may not know the Web Services URI to locate a Web Service, to determine the capabilities of that Web Service, and to properly interact with it. Web Service discovery is currently evolving, and the information that is presented in this topic is subject to change.

DiscoMicrosofts Web Services Discovery Tool


In the current version of the .NET Framework, you can enable programmatic discovery when a Web Service publishes a file with a .disco extension. Disco is Microsofts Web Services discovery tool. A .disco file is an XML document that contains links to other resources that describe the Web Service. Currently, when you create an ASP.NET-hosted Web Service with Visual Studio, .disco files are automatically generated and used. For more information about Disco, see the Visual Studio .NET and .NET Framework SDK documentation.

Universal Description, Discovery, and Integration


The Universal Description, Discovery and Integration (UDDI) project is a cross-industry project that is dedicated to creating a platform-independent, open framework for describing Web Services, discovering businesses, and integrating business services that use the Internet. The project is driven by all of the major platform and software providers, and marketplace operators and ebusiness leaders. For more information about UDDI, see the UDDI Web site at http://www.uddi.org/

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

47

Lab 13.2: Using a Web Service


Topic Objective
To introduce the lab.

Lead-in
In this lab, you will access a Web Service by creating a proxy using the Web Services Description Language tool.

Objectives
After completing this lab, you will be able to: Access a Web Service by creating a proxy using the Web Services Description Language tool.

Lab Setup
Starter and solution files are associated with this lab. The starter files are in the folder <install folder>\Labs\Lab13.2\Starter. The solution files for this lab are in the folder <install folder>\Labs\Lab13.2\Solution.

Scenario
This lab is similar to the scenario used in Lab 13.1, Building an OrderProcessing Application by Using Remoted Servers. That scenario was based on a simple distributed order-processing application, in which a customer specifies a customer ID and an item number for an item that the customer wants to purchase, and the application processes the order. The order processing involves authenticating the customers ID and arranging order fulfillment, that is to say, having the ordered item sent to the customer. This lab extends Lab 13.1 by having the client application calculate the cost of the ordered item. Your client will use a Web Service to calculate the items cost including sales tax. This scenario simulates the case where you do not have access to the Web Services source code or assembly.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

48

Module 13: Remoting and Web Services

You will build a MathService Web Service to calculate the total cost of an item given the pretax cost and fractional tax rate. You will then use the Web Services Description Language tool (Wsdl.exe) to access and create a .NET proxy class for this Web Service. Then you will build a client called Testclient2.exe that uses this proxy to access the Web Services Service1.SalesTax method to calculate the cost of the ordered item.

Estimated time to complete this lab: 50 minutes

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

49

Exercise 1 Creating the Web Service Proxy


In this exercise, you will create the MathService Web Service and use the Web Services Description Language tool (Wsdl.exe) to create a proxy class to this Web Service.

!" create the MathService Web Service using Visual Studio .NET To
Follow the steps presented in Demonstration: Using Visual Studio .NET to Create a Web Service in this module.

!" create the Web Service proxy To


In a console window, from the Lab 13.2 Starter directory, create a proxy to the authentication Web Service named Service1.cs by running the following command:
wsdl http://localhost/MathService/service1.asmx?wsdl

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

50

Module 13: Remoting and Web Services

Exercise 2 Creating the Test Client


In this exercise, you will create a test client. The client calls the authentication server. If the user is authenticated, then the client calls the order fulfillment server. If the order is fulfilled, then the client calls the MathService Web Service to calculate the total cost including sales tax. For simplicity, the client will assume that all items cost $100 and that the sales tax rate is always 0.1.

!" create the test client To


1. Use the editor of your choice to examine the C# source file that is named Testclient2.cs located in the Lab13.2 Starter directory. 2. Add code to Testclient2.cs after the following command that outputs the results from calling the fulfillment service:
Console.WriteLine( "Fulfillment Server Customer 1234 Item Number 5678 Shipped: {0}", shipped.ToString() );

The code should check the status of fulfillment. If shipped is true, then perform the following steps: a. Instantiate a new Service1 object named salesTaxService. b. Call the salesTaxService.SalesTax method, passing 100.0F as its first argument and 0.1F as its second argument. c. Print out to the console the returned total cost value. 3. Build Testclient2.exe as follows: a. Reference System.Runtime.Remoting.dll, System.Web.Services.dll, Fulfillment.exe, and Authenticate.exe. b. Specify the C# source files, Service1.cs and Testclient2.cs. c. Specify that the output file should be named Testclient2.exe. 4. Test the order fulfillment system, by performing the following steps: a. In a console window, from the Lab 13.2 Starter directory, run Authenticate.exe. b. In a second console window, from the Lab 13.2 Starter directory, run Fulfillment.exe. c. In a third console window, repeatedly run Testclient2.exe. The console output will vary because the random-number generator values cause authentication and fulfillment to succeed or fail 50 percent of the time.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

51

A typical series of test client invocations would produce output similar to the following:
>testclient2 Authentication Server Customer 1234 Authorization: True Fulfillment Server Customer 1234 Item Number 5678! Shipped: True Total Cost: 110 >testclient2 Authentication Server Customer 1234 Authorization: True Fulfillment Server Customer 1234 Item Number 5678! Shipped: False

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

52

Module 13: Remoting and Web Services

Review
Topic Objective
To reinforce module objectives by reviewing key points.
! ! !

Remoting Remoting Configuration Files Web Services

Lead-in
The review questions cover some of the key concepts taught in the module.

1. Can two application domains that are on the same computer each have a channel that listens on the same port number? Ports are a machine-wide resource; therefore, on one computer, it is illegal to register multiple channels that listen on the same port number, even if the channels are registered in different application domains.

2. What is the purpose of a proxy? The proxy object acts as a representative of the remote object and ensures that all calls that are made on the proxy are forwarded to the correct remote object instance. All methods that are called on the proxy are automatically forwarded to the remote class, and any results are returned to the client.

3. Can a remotely instantiated object be returned by value? No. All objects that are instantiated remotely are returned by reference.

4. What determines whether a remotely instantiated objects parameters and return values are passed by reference or by value? Objects whose classes are marked with the SerializableAttribute are marshal-by-value, and objects that inherit from System.MarshalByRefObject are marshal-by-reference.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

Module 13: Remoting and Web Services

53

5. What file extension is typically used by Microsofts ASP.NET-hosted Web Services? ASP.NET provides support for Web Services with the .asmx file.

6. In ASP.NET, how do you specify that a service is defined in a prebuilt assembly, and where should that assemblys DLL be located in relation to the ASP.NET application? The .asmx file should contain the single line: <%@ WebService Class="<namespace>.<classname>" %> The assembly library DLL should be in the applications \Bin subdirectory.

7. How can a client invoke a Web Service that is not implemented by using the .NET Framework or in which the Web Services assembly or source code is not available? The Web Services Description Language tool (Wsdl.exe) can be used to read the WSDL description of a Web Service and create a proxy class. The client can use the proxy class to invoke the methods of the Web Service.

BETA MATERIALS FOR MICROSOFT CERTIFIED TRAINER PREPARATION PURPOSES ONLY

THIS PAGE INTENTIONALLY LEFT BLANK

Vous aimerez peut-être aussi