MOC 2349B - Programming With the Microsoft.net Framework Microsoft Visual C .NET
MOC 2349B - Programming With the Microsoft.net Framework Microsoft Visual C .NET
Delivery Guide
Course Number: 2349B
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Contents
Introduction
Introduction..............................................................................................................1
Course Materials ......................................................................................................2
Prerequisites.............................................................................................................3
Course Outline .........................................................................................................4
Microsoft Certified Professional Program ...............................................................9
Facilities.................................................................................................................11
Module 1: Overview of the Microsoft .NET Framework
Overview..................................................................................................................1
Overview of the Microsoft .NET Framework..........................................................2
Overview of Namespaces ......................................................................................13
Review ...................................................................................................................17
Module 2: Introduction to a Managed Execution Environment
Overview..................................................................................................................1
Writing a .NET Application.....................................................................................2
Compiling and Running a .NET Application.........................................................11
Lab 2: Building a Simple .NET Application..........................................................29
Review ...................................................................................................................32
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..........................................................................14
Lab 3.2: Creating a Simple Console-Based Client.................................................19
Demonstration: Creating a Windows Forms Client ...............................................22
Creating an ASP.NET Client .................................................................................27
Lab 3.3: Calling a Component Through an ASP.NET Page..................................36
Review ...................................................................................................................40
Module 4: Deployment and Versioning
Overview..................................................................................................................1
Introduction to Application Deployment .................................................................2
Application Deployment Scenarios .........................................................................7
Related Topics and Tools.......................................................................................31
Lab 4: Packaging and Deployment ........................................................................37
Review ...................................................................................................................42
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.............................................................................25
Lab 5: Building Simple Types ...............................................................................39
Review ...................................................................................................................44
iv Programming with the Microsoft® .NET Framework (Microsoft Visual C#™ .NET)
Optional Modules
Description
The goal of this five day 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 (ISVs) 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 experienced professional developers and have a basic
understanding of the C# language.
Students can meet the C# language prerequisite 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 Microsoft 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 specific programming scenarios.
! Use the .NET Framework class library to efficiently create and manage
strings, arrays, collections, and enumerators.
viii Programming with the Microsoft® .NET Framework (Microsoft Visual C#™ .NET)
! 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.
! 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 through XML Web services and Object
Remoting.
Programming with the Microsoft® .NET Framework (Microsoft Visual C#™ .NET) ix
Course Timing
This section provides estimated course timings for all of the modules, labs, and
breaks in Course 2349B, Programming with the Microsoft .NET Framework
(Microsoft Visual C#™ .NET). Your timing may vary.
Day 1
Start End Module
9:00 9:30 Introduction
9:30 10:00 Module 1: Overview of the Microsoft .NET Framework
10:00 10:15 Break
10:15 11:00 Module 2: Introduction to a Managed Execution Environment
11:00 11:15 Lab 2: Building a Simple .NET Application
11:15 11:45 Module 3: Working with Components
11:45 12:00 Lab 3.1: Creating a .NET Framework Component
12:00 1:00 Lunch
1:00 1:15 Module 3: Working with Components (continued)
1:15 1:30 Lab 3.2: Creating a Simple Console-Based Client
1:30 2:00 Module 3: Working with Components (continued)
2:00 2:30 Lab 3.3: Calling a Component Through an ASP .NET Page
2:30 2:45 Break
2:45 4:15 Module 4: Deployment and Versioning
Day 2
Start End Module
9:00 9:50 Lab 4: Packaging and Deployment
9:50 10:00 Break
10:00 11:30 Module 5: Common Type System
11:30 12:30 Lunch
12:30 1:15 Lab 5: Building Simple Types
1:15 2:30 Module 6: Working with Types
2:30 2:45 Break
2:45 3:30 Lab 6: Working with Types
3:30 4:00 Module 7: Strings, Arrays, and Collections
x Programming with the Microsoft® .NET Framework (Microsoft Visual C#™ .NET)
Day 3
Start End Module
9:00 10:30 Module 7: Strings, Arrays, and Collections (continued)
10:30 10:45 Break
10:45 11:45 Lab 7: Working with Strings, Enumerators, and Collections
11:45 12:45 Lunch
12:45 2:00 Module 8: Delegates and Events
2:00 2:15 Break
2:15 3:30 Lab 8: Creating a Simple Chat Server
3:30 4:00 Module 9: Memory and Resource Management
Day 4
Start End Module
9:00 10:30 Module 9: Memory and Resource Management (continued)
10:30 10:45 Break
10:45 11:45 Lab 9: Memory and Resource Management
11:45 12:45 Lunch
12:45 1:30 Module 10: Data Streams and Files
1:30 2:15 Lab 10: Files
2:15 2:30 Break
2:30 3:30 Module 11: Internet Access
3:30 4:15 Lab 11: Creating a DateTime Client/Server Application
Day 5
Start End Module
9:00 9:30 Module 12: Serialization
9:30 10:15 Lab 12: Serialization
10:15 10:30 Break
10:30 11:30 Module 13: Remoting and Web Services
11:30 12:30 Lunch
12:30 1:20 Lab 13.1: Building an Order-Processing Application by Using
Remoted Servers
1:20 2:20 Module 13: Remoting and Web Services (continued)
2:20 2:35 Break
2:35 3:30 Lab 13.2: Using an XML Web Service
Programming with the Microsoft® .NET Framework (Microsoft Visual C#™ .NET) xi
Document Conventions
The following conventions are used in course materials to distinguish elements
of the text.
Convention Use
Contents
Introduction 1
Course Materials 2
Prerequisites 3
Course Outline 4
Microsoft Certified Professional Program 9
Facilities 11
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Introduction iii
Instructor Notes
Presentation: The Introduction module provides students with an overview of the course
30 Minutes content, materials, and logistics for Course 2349B, Programming with the
Microsoft® .NET Framework (Microsoft Visual C#™ .NET).
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 2349B, Programming with the Microsoft .NET Framework
(Microsoft Visual C# .NET)
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.
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.
Providing reasonably complete coverage of the Microsoft .NET Framework
within a five day class is a challenging undertaking. The thirteen modules
that encompass Course 2349B, Programming with the Microsoft.NET
Framework (Microsoft Visual C# .NET), will provide most students with a
common baseline for working with the .NET Framework.
Note For more information about customizing this course see the Optional
Course Presentation Strategies section in this module.
! Setup
Provide the students with any necessary setup information for the course.
! 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.
Introduction v
Course Customization
The thirteen modules that make up the five day Course 2349B, Programming
with the Microsoft .NET Framework (Microsoft Visual C# .NET), will provide
most students with a common baseline for working with the .NET Framework.
In addition to the first thirteen modules that make up the five days of material,
the course contains four optional modules, thus providing you with the
opportunity for customization.
You are not required to cover the optional modules as part of Course 2349B,
Programming with the Microsoft .NET Framework (Microsoft Visual C# .NET).
The decision about whether to cover the optional modules has been left entirely
to you, the instructor, as you will need to consider the circumstances of each
class separately, including student levels and preferences, and any requirements
of an individual Microsoft Certified Technical Education Center (Microsoft
CTEC).
However, as part of the course materials, your students will receive all
seventeen modules. While Modules 14 through 17 are considered optional, you
should be prepared to discuss what you plan to cover during the course
introduction. If you only intend to cover the first thirteen modules that make up
the official five days of course delivery of Course 2349B, Programming with
the Microsoft .NET Framework (Microsoft Visual C# .NET), then state that
clearly and suggest that the optional modules may be used as additional self-
study. Alternatively, you may want to discuss covering one or more of the
optional modules if there is sufficient interest in those topics. You will then
need to consider with your students what module(s) you may safely leave out in
order to accommodate the optional module(s).
For example, an alternative approach for more advanced students who already
have a basic understanding of .NET Framework applications and the Microsoft
Visual C#™ .NET object model would be to omit Modules 2 through 6 and
teach Modules 7 through 17.
vi Introduction
Course Flow
As a general guideline, modules may be grouped accordingly, as shown in the
following table.
Module Course Flow
Course Timing
This section provides estimated course timings for all of the modules, labs, and
breaks in Course 2349B, Programming with the Microsoft .NET Framework
(Microsoft Visual C# .NET). The following schedule options are provided as a
guide to help with ideas about how to organize your class if you decide to
customize the course.
Option 1
The following schedule is an estimate of the course timing if you choose to
teach Modules 1 through 13. This is the basic approach for students needing
additional instruction regarding Visual C# .NET and the .NET Framework
approach to assemblies, packaging and the object model. If you do not intend to
customize Course 2349B, Programming with the Microsoft .NET Framework
(Microsoft Visual C# .NET), this is the approach you should use. Your timing
may vary.
Day 1
Start End Module
9:00 9:30 Introduction
9:30 10:00 Module 1: Overview of the Microsoft .NET Framework
10:00 10:15 Break
10:15 11:00 Module 2: Introduction to a Managed Execution Environment
11:00 11:15 Lab 2: Building a Simple .NET Application
11:15 11:45 Module 3: Working with Components
11:45 12:00 Lab 3.1: Creating a .NET Framework Component
12:00 1:00 Lunch
1:00 1:15 Module 3: Working with Components (continued)
1:15 1:30 Lab 3.2: Creating a Simple Console-Based Client
1:30 2:00 Module 3: Working with Components (continued)
2:00 2:30 Lab 3.3: Calling a Component Through an ASP .NET Page
2:30 2:45 Break
2:45 4:15 Module 4: Deployment and Versioning
Day 2
Start End Module
9:00 9:50 Lab 4: Packaging and Deployment
9:50 10:00 Break
10:00 11:30 Module 5: Common Type System
11:30 12:30 Lunch
12:30 1:15 Lab 5: Building Simple Types
1:15 2:30 Module 6: Working with Types
2:30 2:45 Break
2:45 3:30 Lab 6: Working with Types
3:30 4:00 Module 7: Strings, Arrays, and Collections
viii Introduction
Day 3
Start End Module
9:00 10:30 Module 7: Strings, Arrays, and Collections (continued)
10:30 10:45 Break
10:45 11:45 Lab 7: Working with Strings, Enumerators, and Collections
11:45 12:45 Lunch
12:45 2:00 Module 8: Delegates and Events
2:00 2:15 Break
2:15 3:30 Lab 8: Creating a Simple Chat Server
3:30 4:00 Module 9: Memory and Resource Management
Day 4
Start End Module
9:00 10:30 Module 9: Memory and Resource Management (continued)
10:30 10:45 Break
10:45 11:45 Lab 9: Memory and Resource Management
11:45 12:45 Lunch
12:45 1:30 Module 10: Data Streams and Files
1:30 2:15 Lab 10: Files
2:15 2:30 Break
2:30 3:30 Module 11: Internet Access
3:30 4:15 Lab 11: Creating a DateTime Client/Server Application
Day 5
Start End Module
9:00 9:30 Module 12: Serialization
9:30 10:15 Lab 12: Serialization
10:15 10:30 Break
10:30 11:30 Module 13: Remoting and Web Services
11:30 12:30 Lunch
12:30 1:20 Lab 13.1: Building an Order-Processing Application by Using
Remoted Servers
1:20 2:20 Module 13: Remoting and Web Services (continued)
2:20 2:35 Break
2:35 3:30 Lab 13.2: Using an XML Web Service
Introduction ix
Option 2
The following schedule is an estimate of the course timing if you choose to
teach Module 1 followed by Modules 7 through 17. This approach would serve
more advanced students who already have a solid understanding of Visual C#
.NET and the .NET Framework approach to assemblies, packaging and the
object model. Your timing may vary.
Day 1
Start End Module
9:00 9:30 Introduction
9:30 10:00 Module 1: Overview of the Microsoft .NET Framework
10:00 10:15 Break
10:15 11:45 Module 7: Strings, Arrays, and Collections
11:45 12:45 Lunch
12:45 1:15 Module 7: Strings, Arrays, and Collections (continued)
1:15 2:15 Lab 7: Working with Strings, Enumerators, and Collections
2:15 2:30 Break
2:30 3:55 Module 8: Delegates and Events
3:55 4:15 Break
4:15 5:15 Lab 8: Creating a Simple Chat Server
Day 2
Start End Module
9:00 10:30 Module 9: Memory and Resource Management
10:30 10:45 Break
10:45 11:20 Module 9: Memory and Resource Management (continued)
11:20 11:50 Lab 9: Memory and Resource Management
11:50 1:00 Lunch
1:00 1:30 Lab 9: Memory and Resource Management (continued)
1:30 2:15 Module 10: Data Streams and Files
2:15 3:00 Lab 10: Files
3:00 3:15 Break
3:15 4:15 Module 11: Internet Access
4:15 5:00 Lab 11: Creating a DateTime Client/Server Application
x Introduction
Day 3
Start End Module
9:00 9:30 Module 12: Serialization
9:30 10:15 Lab 12: Serialization
10:15 10:30 Break
10:30 11:30 Module 13: Remoting and XML Web Services
11:30 12:30 Lunch
12:30 1:20 Lab 13.1: Building an Order-Processing Application by Using
Remoted Servers
1:20 2:20 Module 13: Remoting and XML Web Services (continued)
2:20 2:35 Break
2:35 3:30 Lab 13.2: Using an XML Web Service
Day 4
Start End Module
9:00 10:15 Module 14: Threading and Asynchronous Programming
10:15 10:30 Break
10:30 11:45 Module 14: Threading and Asynchronous Programming
(continued)
11:45 12:45 Lunch
12:45 1:45 Lab 14: Working with Multithreaded Applications
1:45 2:00 Break
2:00 2:45 Module 15: Interoperating Between Managed and Unmanaged
Code
2:45 3:15 Lab 15.1: Calling Win32 APIs
3:15 3:30 Break
3:30 4:15 Module 15: Interoperating Between Managed and Unmanaged
Code (continued)
4:15 4:45 Lab 15.2: Calling COM Objects
Day 5
Start End Module
9:00 10:30 Module 16: Using Microsoft ADO.NET to Access Data
10:30 10:45 Break
10:45 11:15 Module 16: Using Microsoft ADO.NET to Access Data
(continued)
11:15 12:15 Lab 16: Using ADO.NET to Access Data
12:15 1:15 Lunch
1:15 2:15 Module 17: Attributes
2:15 2:30 Break
2:30 3:15 Lab 17: Defining and Using Attributes
Introduction xi
Other Options
The standard approach could be further customized by substituting one or more
of Modules 7 through 13 with Modules 14 through 17. In addition, a more
advanced option of delivery would be to extend the course by offering all
seventeen modules. However, the decision to offer this delivery option would
need to be reached in accordance with the policies and business requirements of
individual Microsoft Certified Technical Education Centers (Microsoft
CTECs).
The following table lists the times for individual labs and modules.
Lecture Time Lab Time Lecture and Lab
Module Title (only) (only) Time (combined)
Introduction
Topic Objective
To introduce yourself,
establish credibility, meet ! Name
students, and set student
expectations for the course. ! Company Affiliation
Lead-in ! Title/Function
Good morning. Welcome to
Course 2349B, ! Job Responsibility
Programming with the
Microsoft .NET Framework ! Programming Experience
(Microsoft Visual C# .NET).
! .NET Framework Experience
My name is...
! Expectations for the Course
Course Materials
Topic Objective
To identify and describe the
course materials.
! Name Card
Lead-in
We have provided ! Student Workbook
everything you need for this
course. You will find the ! Student Materials Compact Disc
following materials at your
desk... ! Course Evaluation
Describe the contents of the The following materials are included with your kit:
student workbook and the
Student Materials compact ! Name card. Write your name on both sides of the name card.
disc. ! Student workbook. The student workbook contains the material covered in
class, in addition to the hands-on lab exercises.
Have students write their
names on both sides of the ! Student Materials compact disc. The Student Materials compact disc
name card. contains the Web page that provides you with links to resources pertaining
to this course, including additional readings, review and lab answers, lab
Tell students where they files, multimedia presentations, and course-related Web sites.
can send comments with
feedback on the course.
Note To open the Web page, insert the Student Materials compact disc into
Delivery Tip the CD-ROM drive, and then in the root directory of the compact disc,
Demonstrate how to open double-click Autorun.exe or Default.htm.
the Web page provided on
the Student Materials
compact disc. On the ! Course evaluation. To provide feedback on the course, training facility, and
Trainer Materials compact instructor, you will have the opportunity to complete an online evaluation
disc, double-click near the end of the course.
Autorun.exe or
To provide additional comments or inquire about the Microsoft Certified
Default.htm in the
StudentCD folder.
Professional program, send e-mail to [email protected].
Introduction 3
Prerequisites
Topic Objective
To present and describe the
prerequisites for this course.
! Proficiency in the C++ or Java Programming Languages
Lead-in
The following prerequisite ! A basic understanding of the C# Language
knowledge is needed for this
course.
Course Outline
Topic Objective
To provide an overview of
each module and what
students will learn. ! Module 1: Overview of the Microsoft .NET Framework
Lead-in ! Module 2: Introduction to a Managed Execution
In this course, we will Environment
cover...
! Module 3: Working with Components
! Module 4: Deployment and Versioning
! Module 5: Common Type System
! Module 6: Working with Types
Briefly describe each Module 1, “Overview of the Microsoft .NET Framework,” defines terminology
module. specific to the Microsoft® .NET Framework and describes its key features and
benefits. This module also discusses the namespaces taught in this course.
As you describe each There will be minimal lecture and no lab. After completing this module, you
module, acknowledge any will be able to list the major elements of the .NET Framework.
information that will meet
the student expectations Module 2, “Introduction to a Managed Execution Environment,” introduces the
that you recorded earlier. 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
Microsoft Visual 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 Microsoft
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.
Introduction 5
http://www.microsoft.com/traincert/
MCSA on Microsoft The Microsoft Certified Systems Administrator (MCSA) certification is designed for
Windows 2000 professionals who implement, manage, and troubleshoot existing network and system
environments based on Microsoft Windows 2000 platforms, including the Windows
.NET Server family. Implementation responsibilities include installing and configuring
parts of the systems. Management responsibilities include administering and supporting
the systems.
MCSE on Microsoft The Microsoft Certified Systems Engineer (MCSE) credential is the premier
Windows 2000 certification for professionals who analyze the business requirements and design
and implement the infrastructure for business solutions based on the Microsoft
Windows 2000 platform and Microsoft server software, including the Windows .NET
Server family. Implementation responsibilities include installing, configuring, and
troubleshooting network systems.
MCSD The Microsoft Certified Solution Developer (MCSD) credential is the premier
certification for professionals who design and develop leading-edge business solutions
with Microsoft development tools, technologies, platforms, and the Microsoft Windows
DNA architecture. The types of applications MCSDs can develop include desktop
applications and multi-user, Web-based, N-tier, and transaction-based applications. The
credential covers job tasks ranging from analyzing business requirements to maintaining
solutions.
10 Introduction
(continued)
Certification Description
MCDBA on Microsoft The Microsoft Certified Database Administrator (MCDBA) credential is the premier
SQL Server 2000 certification for professionals who implement and administer Microsoft SQL Server™
databases. The certification is appropriate for individuals who derive physical database
designs, develop logical data models, create physical databases, create data services by
using Transact-SQL, manage and maintain databases, configure and manage security,
monitor and optimize databases, and install and configure SQL Server.
MCP The Microsoft Certified Professional (MCP) credential is for individuals who have the
skills to successfully implement a Microsoft product or technology as part of a business
solution in an organization. Hands-on experience with the product is necessary to
successfully achieve certification.
MCT Microsoft Certified Trainers (MCTs) demonstrate the instructional and technical skills
that qualify them to deliver Microsoft Official Curriculum through Microsoft Certified
Technical Education Centers (Microsoft CTECs).
Certification Requirements
The certification requirements differ for each certification category and are
specific to the products and job functions addressed by the certification. To
become a Microsoft Certified Professional, you must pass rigorous certification
exams that provide a valid and reliable measure of technical proficiency and
expertise.
For More Information See the Microsoft Training and Certification Web site at
http://www.microsoft.com/traincert.
You can also send e-mail to [email protected] if you have specific
certification questions.
Facilities
Topic Objective
To inform students of class Class Hours
logistics and rules for the
training site.
Building Hours Phones
Lead-in
Before we start, let’s go over
the class logistics.
Parking Messages
Meals Recycling
Overview 1
Overview of the Microsoft .NET Framework 2
Overview of Namespaces 13
Review 17
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 1: Overview of the Microsoft .NET Framework iii
Instructor Notes
Presentation: This module provides students with an overview of the Microsoft® .NET
30 Minutes Framework. It defines some of the terminology that is specific to the .NET
Framework and describes the key features and benefits of the .NET Framework.
Lab:
00 Minutes 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.
Required Materials
To teach this module, you need the Microsoft PowerPoint® file 2349B_01.ppt.
Preparation Tasks
To prepare for this module, you should read all of the materials for this module.
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 Microsoft Visual C#™ to teach the .NET Framework. Only
minimal coverage of XML Web services, user interfaces, ADO.NET, and
ASP.NET is provided. Other courses will cover these technologies in more
detail. In addition, ADO.NET is covered more fully in Module 16, “Using
Microsoft ADO.NET to Access Data,” in Course 2349B, Programming with
the Microsoft .NET Framework (Microsoft Visual C# .NET).
! 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 2349B,
Programming with the Microsoft .NET Framework (Microsoft Visual C#
.NET). 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).
Module 1: Overview of the Microsoft .NET Framework v
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Overview of the Microsoft .NET Framework
Lead-in ! Overview of Namespaces
In this module, you will be
introduced to the .NET
Framework. You will then
learn about the namespaces
and which modules teach
certain namespaces.
COM+
Message
(Transactions, Partitions, IIS WMI
Queuing
Object Pooling)
Win32
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 Microsoft 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.
ADO.NET
ADO.NET is the next generation of Microsoft 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).
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
Module 1: Overview of the Microsoft .NET Framework 5
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.
Class loader Manages metadata, and the loading and layout of classes.
Microsoft Intermediate Language Converts MSIL to native code on a just-in-time basis.
(MSIL) to native compiler
Code manager Manages code execution.
Garbage collection Provides automatic lifetime management of all of objects in the .NET
Framework, garbage collection is a multiprocessor, scalable garbage collector.
Security engine Provides evidence-based security, based on user identity and the origin of the
code.
Debugger Enables the developer to debug an application and trace the execution of code.
Type checker Does not allow unsafe casts or uninitialized variables. MSIL can be verified to
guarantee type safety.
Exception manager Provides structured exception handling, which is integrated with Windows
Structured Exception Handling (SEH). Error reporting has been improved.
Thread support Provides classes and interfaces that enable multithreaded programming.
COM marshaler Provides marshaling to and from COM.
.NET Framework class library Integrates code with the runtime that supports the .NET Framework class library.
support
Module 1: Overview of the Microsoft .NET Framework 7
Is Extensible
You can extend the library by creating your own classes and compiling them
into libraries. If designed properly, your class library will also be object-
oriented 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.
Module 1: Overview of the Microsoft .NET Framework 9
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 XML Web services, including such features as moving back and forth from
objects to an XML representation.
10 Module 1: Overview of the Microsoft .NET Framework
SOAP
SOAP defines how messages are formatted, sent, and received when working
with XML Web services. SOAP is also an industry standard that is built on
XML and HTTP. Any platform that supports the SOAP standard can support
XML Web services.
Module 1: Overview of the Microsoft .NET Framework 11
System.Web
In the System.Web namespace, there are lower-level services, such as caching,
security, and configuration, which are shared between XML Web services and
Web UIs.
System.Web.Services
The System.Web.Services namespace has classes that handle XML 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.
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 System
The .NET Framework Collections IO Security Runtime
includes a large set of class
Configuration Net ServiceProcess
library assemblies, which
contain hundreds of types. Diagnostics Reflection Text
These assemblies provide Globalization Resources Threading
access to system
functionality in your
development process.
Lead-in # System.Net
# System.Windows.Forms
This course covers many of # System.Net.Sockets
the System namespaces. # System.Drawing
Not all namespaces are Module 12
Module 4
covered, for example the # System.Runtime.Serialization
System.Security # System.Reflection
Module 13
namespaces. Module 7
# System.Runtime.Remoting.Channels
# System.Text
# System.Web.Services
# System.Collections
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Overview of the Microsoft .NET Framework
Lead-in ! Overview of Namespaces
The review questions cover
some of the key concepts
taught in the module.
Overview 1
Writing a .NET Application 2
Compiling and Running a .NET Application 11
Lab 2: Building a Simple .NET Application 29
Review 32
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 2: Introduction to a Managed Execution Environment iii
Instructor Notes
Presentation: After completing this module, students will be able to:
45 Minutes
! Create simple console applications in C#.
Lab: ! Explain how code is compiled and executed in a managed execution
20 Minutes
environment.
! Explain the concept of garbage collection.
Required Materials
To teach this module, you need the following materials:
! Microsoft® PowerPoint® file 2349B_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.
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.
Running the resulting executable file will generate the following output:
Hello World using C#!
Multimedia
This section lists the multimedia items that are part of this module. Instructions
for launching and playing the multimedia are included with the relevant slides.
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 development 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.
Module 2: Introduction to a Managed Execution Environment 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives. ! Writing a .NET Application
Lead-in ! Compiling and Running a .NET Application
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.
Delivery Tip Note In this module, and in Modules 3 and 4, Notepad is used as the source
Stress the importance of code editor, instead of the Microsoft Visual Studio® .NET development
understanding the process environment. The examples in these modules are simple enough to be compiled
of compiling and running the and built directly from a command prompt window. Working in Notepad will
.NET applications. Using allow you to focus on the compilation and execution processes.
Visual Studio .NET at this
time may obscure the
underlying processes.
Module 2: Introduction to a Managed Execution Environment 3
• From a Visual Studio .NET Command Prompt window, type the following
syntax:
csc HelloDemoCS.cs
Using a Namespace
Topic Objective
To describe how to use
namespaces in the .NET ! Classes Can Be Fully Referenced
Framework.
Lead-in //
// declares
declares aa FileStream
FileStream object
object
You can fully reference System.IO.FileStream
System.IO.FileStream aFileStream;
aFileStream;
classes in which an instance
of System.IO.FileStream is ! Or the Namespace of a Class Can Be Referenced
declared by using C#:
# No need to fully qualify contained class names
using
using System.IO;
System.IO;
...
...
FileStream
FileStream aFileStream;
aFileStream;
For example, in order to have convenient access to System objects, you must
use the System namespace.
6 Module 2: Introduction to a Managed Execution Environment
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 {
...
}
}
! In C#, Objects Must Be Declared Before They Can Be Used and Are
Instantiated Using the New Keyword
Lib.Comp
Lib.Comp myComp
myComp == new
new Lib.Comp();
Lib.Comp();
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.
class MainApp {
public static void Main() {
Case Sensitivity
Topic Objective
To describe case sensitivity ! Do Not Use Names That Require Case Sensitivity
issues in programming
languages. # Components should be fully usable from both case-
Lead-in sensitive and case-insensitive languages
C++ and C# are case-
sensitive, but Visual Basic is
# Case should not be used to distinguish between
not case-sensitive. identifiers within a single name scope
! Avoid the Following
class
class customer
customer {...}
{...}
class
class Customer
Customer {...}
{...}
void
void foo(int
foo(int X,
X, int
int x)
x)
! Do not have a function with two parameters whose names differ only by
case.
void foo(int X, int x)
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 common 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.
Module 2: Introduction to a Managed Execution Environment 11
Key Points
String literals in an
application are stored and
transported as clear text.
Therefore, you should avoid
putting sensitive information
such as passwords in string
literals.
12 Module 2: Introduction to a Managed Execution Environment
Compiler Options
Topic Objective
To introduce compiler
options in C#. ! Compile Directly from a Command Prompt Window
Lead-in >csc
>csc HelloDemoCS.cs
HelloDemoCS.cs
The .NET Framework
includes a command line
compiler for C#. ! Use /t to indicate target
>csc
>csc /t:exe
/t:exe HelloDemoCS.cs
HelloDemoCS.cs
>csc
>csc /t:exe
/t:exe /reference:assemb1.dll
/reference:assemb1.dll HelloDemoCS.cs
HelloDemoCS.cs
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 HelloDemoCS.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, HelloDemoCS.exe.
Module 2: Introduction to a Managed Execution Environment 13
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:HelloDemoCS.exe /t:exe HelloDemoCS.cs
Security
Security Checks
Checks
Runtime Engine
If the C# compiler’s 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
fundamental units of sharing, deployment, security, and versioning in the
common language runtime. The .NET common language runtime only executes
MSIL code that is contained in an assembly.
If the C# compiler’s 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 .NET’s 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 module’s
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 module’s 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 just-
in-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.
16 Module 2: Introduction to a Managed Execution Environment
Metadata
Topic Objective
To explain how metadata is
used in the common ! Declarative Information Emitted at Compile Time
language runtime.
Lead-in ! Included with All .NET Framework Files and Assemblies
Every compiler that targets
the common language ! Metadata Allows the Runtime to:
runtime is required to emit
# Load and locate code
full metadata into every
managed module. # Enforce code security
# Generate native code at runtime
# Provide reflection
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.
Module 2: Introduction to a Managed Execution Environment 17
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.
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.
Module 2: Introduction to a Managed Execution Environment 19
Assemblies
Topic Objective ManagedModule
Managed Module
This topic introduces the (MSILand
(MSIL andMetadata)
Metadata)
concept of an assembly and
the role of the assembly ManagedModule
Managed Module
(MSILand
(MSIL andMetadata)
Metadata) Assembly
manifest. Assembly
Lead-in
The common language
runtime uses an assembly Manifest
Manifest
.html
as the functional unit of
sharing and reuse.
.gif
Multiple Managed
Modules and
Resource Files Resource Files
Are Compiled to
Produce an Assembly
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.
20 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:
Just-In-Time Compilation
Topic Objective
To describe JIT compilation
and introduce JIT compiler
options. ! Process for Code Execution
Lead-in # MSIL converted to native code as needed
MSIL code must be
converted into native code # Resulting native code stored for subsequent calls
before it can execute.
Because an intermediate # JIT compiler supplies the CPU-specific conversion
step is involved, the
common language runtime
optimizes the compilation
process for efficiency.
Application Domains
Topic Objective
To describe how application
domains provide application ! Historically, Process Boundaries Used to Isolate
isolation. Applications
Lead-in ! In the Common Language Runtime, Application
Historically, process
boundaries have been used
Domains Provide Isolation Between Applications
to isolate applications # The ability to verify code as type-safe enables isolation
running on the same
computer.
at a much lower performance cost
# Several application domains can run in a single process
! Faults in One Application Cannot Affect Other
Applications
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. Cross-
domain calls use the same remote call infrastructure as calls between two
processes or between two computers.
Module 2: Introduction to a Managed Execution Environment 27
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.
28 Module 2: Introduction to a Managed Execution Environment
Garbage Collection
Topic Objective
To introduce memory and
resource management in
the .NET Framework. ! Garbage Collection Provides Automatic Object Memory
Management in the .NET Framework
Lead-in
Every program uses ! You No Longer Need to Track and Free Object Memory
resources, such as files,
screen space, network
connections, and database
resources.
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.
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.
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 prompt window,
you will then compile the application and test the resulting executable program.
1. From a Visual Studio .NET 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.
Module 2: Introduction to a Managed Execution Environment 31
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.
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Writing a .NET Application
Lead-in ! Compiling and Running a .NET Application
The review questions cover
some of the key concepts
taught in the module.
2. What class and methods can your application use to input and output to the
console?
You can use the common language runtime’s 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.
5. What .NET component compiles MSIL into CPU specific native code?
The just-in-time (JIT) compiler.
Contents
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 14
Lab 3.2: Creating a Simple Console-Based
Client 19
Demonstration: Creating a Windows
Forms Client 22
Creating an ASP.NET Client 27
Lab 3.3: Calling a Component Through
an ASP.NET Page 36
Review 40
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 3: Working with Components iii
Instructor Notes
Presentation: After completing this module, students will be able to:
70 Minutes
! Create a simple Microsoft® .NET Framework component in C#.
Lab: ! Implement structured exception handling.
60 Minutes
! 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.
Required Materials
To teach this module, you need the Microsoft PowerPoint® file 2349B_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.
iv Module 3: Working with Components
Demonstrations
This section provides demonstration procedures that will not fit in the margin
notes or are not appropriate for the student notes.
! To add references
1. On the Project menu, click Add Reference.
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;
Module 3: Working with Components v
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.
vi Module 3: Working with Components
Multimedia
This section lists the multimedia items that are part of this module. Instructions
for launching and playing the multimedia are included with the relevant slides.
Module Strategy
Use the following strategy to present this module:
! An Introduction to Key .NET Framework Technologies
Briefly introduce Windows Forms, Web Forms, and XML Web services.
Explain that you will show an example of a Windows Form in this module.
Tell students that they will learn about XML Web services in Module 13,
“Remoting and XML Web Services,” in Course 2349B, Programming with
the Microsoft .NET Framework (Microsoft Visual C# .NET).
! 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 Framework’s 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 stand-
alone client applications with that of an 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.
Module 3: Working with Components 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! An Introduction to Key .NET Framework
Development Technologies
Lead-in
In this module, you will learn ! Creating a Simple .NET Framework Component
how to create a small
client/server application. ! Creating a Simple Console Client
! Creating an ASP.NET Client
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.
Module 3: Working with Components 3
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.
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.
public
public class
class StringComponent
StringComponent {...}
{...}
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.
Module 3: Working with Components 7
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 statement.
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 throw exceptions
}
catch(Exception e) {
// place code that handles exceptions
}
finally {
// place code that runs after try or catch runs
}
Creating a Property
Topic Objective
To explain how to create a
property.
! Create a Read-Only Count Property to Get the Number
Lead-in of String Elements in the stringSet Array
To provide the number of
string elements in the
stringSet array in C#, you
public
public int
int Count
Count {{
create a read-only property
called Count. get
get {{ return
return stringSet.Length;
stringSet.Length; }}
}}
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.
Module 3: Working with Components 11
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.
• From a Visual Studio .NET 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.
14 Module 3: Working with Components
using
using VBStringComp
VBStringComp == CompVB.StringComponent;
CompVB.StringComponent;
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;
16 Module 3: Working with Components
class MainApp
{
public static void Main() {
class MainApp
{
public static void Main() {
Running a client program that first iterates over the C# component’s strings and
then iterates over the Visual Basic component’s strings will produce the
following output:
Strings from C# StringComponent
C# String 0
C# String 1
C# String 2
C# String 3
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.
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.
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.
Module 3: Working with Components 21
1. From a Visual Studio .NET 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 should 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. The C# assembly is
located in <install folder>\Labs\Lab03.1\Solution\C#\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
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
namespace WinForm_Client
{
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;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
// 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());
}
To launch the animation, The .NET Framework provides the capability to execute code that was used in
click the button in the lower- the preceding stand-alone client applications in an ASP.NET page. However,
left corner of the slide. To there are some differences in the code execution processes.
play the animation, click the
Start button, and then click An ASP.NET page generally produces HTML in response to a HTTP request;
the First Request, Second and the page itself is compiled dynamically, unlike the stand-alone client
Request, and Output Cache applications. Each ASP.NET page is individually parsed, and the syntax is
buttons at the top of the checked. Then, a .NET runtime class is produced, compiled, and invoked.
screen. There is no audio, ASP.NET caches the compiled object, so subsequent requests do not perform
but explanatory text appears the parse and compile step and thus execute much faster.
in the Info column when you
click one of the buttons. In this animation, you will see how ASP.NET pages are processed on the
server. To view the animation, open the 2349B_mod3.htm file from the Media
folder.
Tell students that they can
view the animation again
later for themselves by
opening the
2349B_mod3.htm file from
the Media folder.
Module 3: Working with Components 29
The following table describes the two @ Page directive attributes that are used
in the sample client ASP.NET page.
Attribute Description
Language Language that is used when compiling all <% %> and <%= %> blocks
within a page. Can be Visual Basic, C#, or Microsoft JScript® .NET.
Description Provides a text description of the page. Supports any string description.
30 Module 3: Working with Components
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 application’s starting point.
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.
Module 3: Working with Components 31
Notice that the client code that calls the string component is very similar to the
code for the stand-alone 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.
This code places the string output that was generated by the Page_Load event
handler in the HTTP response.
34 Module 3: Working with Components
<html>
<script language="C#" runat=server>
void Page_Load(Object sender, EventArgs EvArgs) {
StringBuilder Out = new StringBuilder();
int Count = 0;
Message.InnerHtml = Out.ToString();
}
</script>
<body>
<span id="Message" runat=server/>
</body>
</html>
Module 3: Working with Components 35
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.
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 stand-alone 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.
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 component’s 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.
38 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.
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! An Introduction to Key .NET Framework Development
Technologies
Lead-in
The review questions cover ! Creating a Simple .NET Framework Component
some of the key concepts
taught in the module. ! Creating a Simple Console Client
! Creating an ASP.NET Client
Contents
Overview 1
Introduction to Application Deployment 2
Application Deployment Scenarios 7
Related Topics and Tools 31
Lab 4: Packaging and Deployment 37
Review 42
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 4: Deployment and Versioning iii
Instructor Notes
Presentation: After completing this module, students will be able to:
90 Minutes
! Package and deploy simple and componentized applications.
Lab: ! Create strong-named assemblies.
50 Minutes
! Install and remove assemblies from the global assembly cache.
! Configure an application to control its binding to an assembly based on the
assembly’s location and version data.
Required Materials
To teach this module, you need the Microsoft® PowerPoint® file 2349B_04.ppt.
Preparation Tasks
To prepare for this module, you should:
! Read all of the materials for this module.
! Complete the lab.
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 Framework
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 stand-alone
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 2349B, Programming with
the Microsoft .NET Framework (Microsoft Visual C#™ .NET).
! Related Topics and Tools
Briefly introduce 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 just inform the students of these topics and encourage them to
look for more information in the .NET Framework Software Development
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.
Module 4: Deployment and Versioning 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Introduction to Application Deployment
Lead-in ! Application Deployment Scenarios
In this module, you will learn
about packaging and ! Related Topics and Tools
deployment of Microsoft
.NET Framework
applications and
assemblies.
Common Concepts
Topic Objective
To review the organization
of the .NET Framework ! Classes and Types Used in .NET Framework Applications Are:
class library and # Organized in a hierarchy of namespaces
assemblies, and the role of
the assembly manifest. # Stored in PE files, such as DLLs and EXEs
Lead-in # Fully described by metadata
The .NET Framework
! Assemblies:
provides a common class
library that is organized into # Are made up of one or more PE files
a hierarchical tree of
namespaces. # Contain a manifest that identifies the assembly and its files
# Specify exported and imported classes and types
# Are units of deployment, reuse, and versioning
Simple Applications
Topic Objective
To describe how easily an
application can be executed
in the .NET Framework. ! Require .NET Runtime Be Installed on Local Computer
Lead-in ! Can Be Run Directly from a File Server or Copied
In the simplest case, a .NET Locally
Framework application can
be executed locally on any ! Make No Registry Entries
computer on which the .NET
runtime is already installed. ! Cannot Break Another Application
# Eliminate DLL Hell
! Can Be Uninstalled by Deleting Locally Copied File(s)
Componentized Applications
Topic Objective
To describe how assemblies
are handled in
componentized applications. ! Assemblies Private to an Application
Lead-in # Same as a simple application
Componentized applications
are only slightly more ! Assemblies Private to Related Applications
complex than applications.
# Deployed into a common subdirectory
! Assemblies Shared with Other Unrelated Applications
# Require a strong name and version information
# Deployed into the global assembly cache
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 application’s 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.
Module 4: Deployment and Versioning 7
A Simple Application
Topic Objective
To explain how a simple ! Use the Microsoft Intermediate Language Disassembler
application is deployed. (Ildasm.exe) to Examine the Assembly Manifest
Lead-in
In Module 2, you looked at # Version information
the simplest .NET
Framework application, the
# Imported types
traditional Hello World # Exported types
application written in C#.
! Deploy the Application by:
# Running the executable file directly from a file server, or
# Installing it locally by copying the file
# Uninstall the application by deleting the file
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.
Module 4: Deployment and Versioning 9
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 affect on the
client workstation. There is also nothing to clean up because there is nothing to
remove on the client workstation.
As you would expect, HelloDemoCS.exe can also be copied to a local volume.
In this scenario, you can remove the program by deleting the file, and as before,
nothing would remain on the workstation.
Whether you run HelloDemoCS.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 HelloDemoCS.exe to stop functioning.
Module 4: Deployment and Versioning 11
A Componentized Application
Topic Objective
To introduce compapp, a
componentized application,
which uses multiple ! Assembly Component to Be Used by Application
assemblies.
# Assembly Stringer.dll is built from Stringer.cs as follows:
Lead-in
The Hello World application csc
csc /target:library
/target:library Stringer.cs
Stringer.cs
that is discussed in the
preceding topic is ! Client Needs to Reference Assembly
completely trivial and hardly
representative of even the csc
csc /reference:Stringer.dll
/reference:Stringer.dll Client.cs
Client.cs
simplest real-world
application.
! Deployment by File Server or Local Copy
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"
};
}
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]);
}
// ...
}
}
The MSIL disassembler displays the Stringer.dll and shows all of the members,
as in the following illustration.
14 Module 4: Deployment and Versioning
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 remove the application, you need only
delete the two files.
Module 4: Deployment and Versioning 15
When this configuration file is placed in the same directory as the executable
file, at run time, the .NET Framework uses the privatePath attribute to
determine where to look for components—in 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 application’s .config file can also be copied to a local
volume, using the same relative directory structure. Deleting the files and
directory effectively removes 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.
Module 4: Deployment and Versioning 17
A Strong-Named Assembly
Topic Objective
To discuss the problems ! Global Assembly Cache
that may occur when # Contains assemblies shared by unrelated applications
multiple applications share
components, and to ! Strong Names Are Required for Assemblies in the Cache
introduce the use of strong # Generate a public-private key pair:
names.
sn
sn –k
–k orgKey.snk
orgKey.snk
Lead-in
The client applications # Add code to source file to specify version and key information:
discussed in the preceding
topics are limited in that they #if
#if STRONG
STRONG
only illustrate the use of [assembly:
[assembly: System.Reflection.AssemblyVersion("1.0.0.0")]
System.Reflection.AssemblyVersion("1.0.0.0")]
assemblies that are private [assembly:
[assembly: System.Reflection.AssemblyKeyFile("orgKey.snk")]
System.Reflection.AssemblyKeyFile("orgKey.snk")]
#endif
#endif
to the Client.exe and do not
demonstrate the use of # Compile:
assemblies that are shared
csc
csc /define:STRONG
/define:STRONG /target:library
/target:library /out:AReverser.dll!
/out:AReverser.dll!
by more than one AReverser.cs
application. AReverser.cs
*****************************ILLEGAL FOR NON-TRAINER USE******************************
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
Framework solution to these problems.
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.
Important Strong names provide a strong integrity check. Passing the .NET
Framework security checks guarantees that the contents of the assembly have
not been changed since it was built. Note, however, that strong names in and of
themselves do not imply a level of trust, such as that provided by a digital
signature and supporting certificate.
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 assembly’s 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 module’s lab contains the complete code details.
After compiling the new AReverser assembly, you can examine the metadata
by using the MSIL disassembler. The MSIL disassembler indicates that the
assembly 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
Module 4: Deployment and Versioning 19
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.
20 Module 4: Deployment and Versioning
After installing the AReverser assembly, you can then examine the system
assembly cache by typing:
gacutil /l
Module 4: Deployment and Versioning 21
You can also examine the system assembly cache by navigating to the
\WindowsDirectory\Assembly directory and by using the cache shell extension.
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.
22 Module 4: Deployment and Versioning
A Versioned Assembly
Topic Objective
To discuss the physical
representation and logical
mapping of the compatibility ! Applications Need to Bind to a Suitable Version of a
version number. Shared Assembly
Lead-in ! The Version Number Is Represented by a 4-Part Number
The final packaging and
deployment example in this
module involves updating <major
<major version>.<minor
version>.<minor version>.<revision>.<build
version>.<revision>.<build number>
number>
the shared assembly to a
new version.
! Applications Get the Versions of Assemblies with Which
They Were Built and Tested
# Unless overridden by explicit policy rules
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>
Module 4: Deployment and Versioning 23
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
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:
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
Module 4: Deployment and Versioning 25
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 than 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
}
26 Module 4: Deployment and Versioning
Binding Policy
Topic Objective ! Policy Resolution
To discuss binding policy. # Allows an assembly reference, specified at compile time, to be
modified after the application has been deployed without recompiling
Lead-in
Whenever the .NET ! Happens in the Following Stages:
Framework is asked to bind 1. Application-policy resolution
to a specific version of a
shared assembly, the 2. Publisher-policy resolution
version of the assembly 3. Administrator-policy resolution
reference may be altered at
! In Each Stage, an XML Configuration File Is Read
several policy-resolution
stages before the .NET # Note: XML is case-sensitive
Framework finally decides to ! Version Numbers of Assemblies That Are Not Strong-Named Are
which version to bind. Not Checked
! Configuration File Tag Examples
# privatePath
# bindingRedirect
In each stage, an XML configuration file that describes the policy is read. The
privatePath attribute 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.
Module 4: Deployment and Versioning 27
Lead-in gacutil
gacutil /i
/i AReverser_v2.0.0.0\AReverser.dll
AReverser_v2.0.0.0\AReverser.dll
After you have configured gacutil
gacutil /i AReverser_v2.0.1.0\AReverser.dll
/i AReverser_v2.0.1.0\AReverser.dll
both versions of the
AReverser assembly to use ! Compile the VerClient Executable and Specify Version 2.0.0.0 of the
strong names, you can AReverser Component
deploy those versions.
csc
csc /reference:MyStringer\Stringer.dll!
/reference:MyStringer\Stringer.dll!
/reference:AReverser_v2.0.0.0\AReverser.dll
/reference:AReverser_v2.0.0.0\AReverser.dll VerClient.cs
VerClient.cs
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
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 assembly’s manifest. The rules that
specify the acceptable versions of an assembly are called version policies.
Version policies are expressed in configuration files.
Note The publicKeyToken tag’s 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.
to:
newVersion="2.0.1.0"/>
Related Topics
Topic Objective
To briefly introduce several
related topics and provide
references for students to ! ASP.NET
follow up on.
! Assemblies
Lead-in
This module introduces the ! Security
concepts of packaging and
deployment of .NET ! Localization
Framework applications and
assemblies. Several related
topics are worth mentioning,
and, when appropriate,
references to additional
information are provided.
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.
Module 4: Deployment and Versioning 33
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.
34 Module 4: Deployment and Versioning
The preceding command removes only the hello assembly that matches the
fully specified version number, culture, and public key.
Module 4: Deployment and Versioning 35
The following command lists the contents of the global assembly cache:
gacutil /l
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
assembly’s 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.
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.
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
assembly’s location and version data.
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.
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.
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.
Module 4: Deployment and Versioning 41
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Introduction to Application Deployment
Lead-in ! Application Deployment Scenarios
The review questions cover
some of the key concepts ! Related Topics and Tools
taught in the module.
5. What kind of assembly can be placed in the global assembly cache and be
versioned?
A strong-named assembly.
Contents
Overview 1
An Introduction to the Common Type
System 2
Elements of the Common Type System 8
Object-Oriented Characteristics 25
Lab 5: Building Simple Types 39
Review 44
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 5: Common Type System iii
Instructor Notes
Presentation: After completing this module, students will be able to:
90 Minutes
! Describe the difference between value types and reference types.
Lab: ! Explain the purpose of each element in the type system, including values,
45 Minutes
objects, and interfaces.
! Explain how object-oriented programming concepts, such as abstraction,
encapsulation, inheritance, and polymorphism, are implemented in the
Common Type System.
Required Materials
To teach this module, you need the Microsoft® PowerPoint® file 2349B_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 student’s 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.
Module 5: Common Type System 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! An Introduction to the Common Type System
Lead-in ! Elements of the Common Type System
In this module, you will learn
about the Common Type ! Object-Oriented Characteristics
System and object-oriented
programming.
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 Description
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.
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
2349B, Programming with the Microsoft .NET Framework (Microsoft
Visual C# .NET).
Module 5: Common Type System 5
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.
6 Module 5: Common Type System
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.
Module 5: Common Type System 7
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.
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;
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.
8 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
Lead-in ! Naming Differences
Primitive types in the .NET
Framework common ! C# Support
language runtime are simple
value types, commonly ! Conversions
found in most programming
languages.
The following example shows how to create and initialize the primitive
System.UInt16 type in C# to store an employee’s 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);
Objects
Topic Objective
To explain the role of object ! Every Class Inherits from System.Object
types in the Common Type
System. ! Objects Specify Data and Behavior
Lead-in ! Fields Define the Data
Everything in the Common
Type System is an object ! Methods Define the Behavior
and inherits from
System.Object. class
class Accumulator
Accumulator
{{
public
public float
float Result;
Result;
public
public void
void Add(float
Add(float amount)
amount)
{{
Result
Result +=
+= amount;
amount;
}}
}}
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;
}
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;
}
}
Constructors
Topic Objective
To explain how to use
constructors to initialize ! Constructors Are Used to Initialize Classes
classes.
! Constructors Can Have Zero or More Parameters
Lead-in
If you design a class that class
class Rectangle
Rectangle
requires special initialization {{
code, you can use a private
private int
int x1,y1,x2,y2;
x1,y1,x2,y2;
constructor to initialize the public
class properly when objects public Rectangle(int
Rectangle(int x1,
x1, int
int y1,
y1, int
int x2,int
x2,int y2)
y2)
{{
are created. this.x1
this.x1 == x1;
x1;
this.x2
this.x2 == x2;
x2;
this.y1
this.y1 == y1;
y1;
this.y2
this.y2 == y2;
y2;
}}
}}
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.
Parameterized Constructor
You can also create a constructor with parameters as follows:
class Rectangle
{
//Rectangle coordinates
private int x1,y1,x2,y2;
Properties
Topic Objective
To describe how to use ! Properties Are Similar to Fields
properties.
Lead-in ! Properties Use get and set Accessor Methods for
Properties are values that Managing Data Values
can be stored or retrieved
on a class. public
public float
float Start
Start
{{
get
get
{{
return
return start;
start;
}}
set
set
{{
if
if (start
(start >=
>= 0)
0) start
start == value;
value;
}}
}}
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);
}
}
}
Custom Types
Topic Objective
To describe how to build ! Inherit from System.ValueType
data types that use the C#
struct keyword. ! Are Defined with the struct Keyword in C#
Lead-in
You can build your own data ! Can Have Methods, Properties, and Fields
type by using the C# struct
struct
struct Employee
Employee
keyword. {{
public
public string
string Name;
Name;
public
public ushort
ushort Age;
Age;
public
public DateTime
DateTime HireDate;
HireDate;
public
public float
float Tenure()
Tenure()
{{
TimeSpan
TimeSpan ts
ts == DateTime.Now
DateTime.Now –– HireDate;
HireDate;
return ts.Days/(float)365;
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.
Module 5: Common Type System 19
Enumerations
Topic Objective
To describe how to create
enumerations, which allow ! .NET Framework Enumerations
developers to specify and
represent simple types. # Inherit from System.Enum
Lead-in # Use the enum keyword
It is common for a variable
to take on only one of a ! Bit Flags
small number of values.
enum
enum SeatPreference
SeatPreference :: ushort
ushort
{{
Window,
Window, //Assigned
//Assigned value
value 00
Center,
Center, //Assigned
//Assigned value
value 11
Aisle
Aisle //Assigned
//Assigned value
value 22
}}
To use enumeration literals, you must fully specify the literal name as in the
following example:
SeatPreference sp;
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 enumeration’s 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”);
Module 5: Common Type System 21
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 (|).
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());
When using the Flags attribute, you must specify the values for the literals
manually.
22 Module 5: Common Type System
Interfaces
Topic Objective ! An Interface Is a Contractual Description of Methods
To describe the uses of
interfaces.
and Properties
Lead-in ! An Interface Has No Implementation
An interface is a contractual
description of a set of ! Use Casting in Client Code to Use an Interface
related methods and interface
interface ICDPlayer
ICDPlayer
properties. {{
void
void Play(short
Play(short playTrackNum);
playTrackNum);
void
void Pause();
Pause();
void
void Skip(short
Skip(short numTracks);
numTracks);
short
short CurrentTrack
CurrentTrack
{{
get;
get;
set;
set;
}}
}}
*****************************ILLEGAL FOR NON-TRAINER USE******************************
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.
Module 5: Common Type System 23
//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);
}
}
24 Module 5: Common Type System
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 2349B, Programming with the Microsoft .NET Framework (Microsoft
Visual C# .NET).
Module 5: Common Type System 25
Abstraction
Topic Objective
To describe the use and
advantages of abstraction
in object-oriented ! Abstraction Works from the Specific to the General
programming.
! Grouping Elements Makes It Easier to Work with
Lead-in Complex Data Types
In object-oriented
programming, the term ! Abstraction Is Supported Through Classes
abstraction refers to the
process of reducing an
object to its essence so that
only essential elements are
represented.
Encapsulation
Topic Objective
To explain the process of ! Encapsulation Is the Process of Hiding Internal Details
encapsulation in object- of a Class
oriented programming.
! Encapsulation Keywords
Lead-in
Encapsulation, or # public
information hiding, is the
process of packaging # protected
attributes and functionality
to prevent other objects # internal
from manipulating data or
procedures directly. # private
! Type-Level Accessibility
! Nested Classes
enum public
class private
interface public
struct 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;
}
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;
}
}
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
}
}
30 Module 5: Common Type System
Inheritance
Topic Objective
To explain how inheritance
works in the Common Type ! Inheritance Is the Reuse of Class Members in
System. Other Classes
Lead-in ! The Common Type System Only Supports Single
Inheritance is a method of Inheritance for Classes
reuse that enables one
class to reuse, or inherit, the ! Member Hiding
fields, properties, and
methods of another class. # Redefine the same method in the derived class
# Use the new keyword
! Abstract Members
! Sealed Classes
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 2349B,
Programming with the Microsoft .NET Framework (Microsoft Visual C#
.NET).
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.
Module 5: Common Type System 31
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.
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");
}
}
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 class’s 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");
}
}
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.
Module 5: Common Type System 33
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;
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);
}
}
34 Module 5: Common Type System
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()
{
}
}
Polymorphism
Topic Objective
To explain the use of
polymorphism to define a
base class. ! Polymorphism Allows a Reference Variable to Call the
Correct Method
Lead-in
In object-oriented ! Virtual Methods Enable Polymorphism in the Common
programming, polymorphism Type System
allows you to define a base
class that includes routines # Use the virtual keyword in the base class
that perform standard
operations on groups of # Use the override keyword in the derived class
related objects, without
regard to the exact type of ! Sealed Methods
each object.
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");
}
}
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()
{/*..*/
}
}
Module 5: Common Type System 39
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.
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
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
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 user’s 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.
Module 5: Common Type System 41
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
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)
{
}
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.
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! An Introduction to the Common Type System
Lead-in ! Elements of the Common Type System
The review questions cover
some of the key concepts ! Object-Oriented Characteristics
taught in the module.
4. What is an interface?
An interface is a contractual description of a set of related methods and
properties.
Contents
Overview 1
System.Object Class Functionality 2
Specialized Constructors 12
Type Operations 18
Interfaces 28
Managing External Types 34
Lab 6: Working with Types 38
Review 43
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 6: Working with Types iii
Instructor Notes
Presentation: After completing this module, students will be able to:
75 Minutes
! Apply attributes to control visibility and inheritance in classes and
Lab: interfaces.
45 Minutes
! 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.
Required Materials
To teach this module, you need the Microsoft® PowerPoint® file 2349B_06.ppt.
Preparation Tasks
To prepare for this module, you should:
! Read all of the materials for this module.
! Complete the lab.
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 2349B, Programming
with the Microsoft .NET Framework (Microsoft Visual C#™ .NET).
! 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.
Be aware that more information about these topics is available in Module
15, “Interoperating Between Managed and Unmanaged Code,” in Course
2349B, Programming with the Microsoft .NET Framework (Microsoft
Visual C# .NET) and “Interoperating with Unmanaged Code” in the .NET
Framework SDK documentation.
Module 6: Working with Types 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! System.Object Class Functionality
Lead-in ! Specialized Constructors
In this module, you will learn
how to apply your ! Type Operations
knowledge of the Common
Type System to various ! Interfaces
programming scenarios.
! Managing External Types
Hash Codes
Topic Objective
To explain how to use hash ! Hash Code Used to Perform Quick Lookups
codes to perform quick
lookups in tables and other ! Override GetHashCode Method on System.Object
types of collections.
Lead-in ! Should Return Same Hash Code for Objects of
A hash function is used to Same Value
quickly generate a number,
or hash code, that
! Should Implement Efficient Algorithm
corresponds to the value of
an object. struct
struct Student
Student {{
string
string name;
name;
int
int ID;
ID; //Unique
//Unique for
for each
each instance
instance
public
public override
override int
int GetHashCode()
GetHashCode() {{
return
return ID;
ID;
}}
}}
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.
The following example shows how to implement GetHashCode for a Student
structure that stores a student’s name and ID.
struct Student
{
string name;
int ID; //Unique for each instance
public override int GetHashCode()
{
return ID;
}
}
Module 6: Working with Types 5
Identity
Topic Objective
To explain how identity is
determined in the .NET
Framework common ! Compare to Determine If Two References Are Actually
language runtime. the Same Object
Lead-in ! Use the Object.ReferenceEquals Method to Test 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 object’s 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 object’s 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.
6 Module 6: Working with Types
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");
}
}
Equality
Topic Objective
To explain how to override ! Comparing Two Objects to Determine If They Are Equal
the Equals method and to
introduce guidelines for ! Override the Equals Method
implementing code to
provide equality comparison ! Supply == and != Operators
for types. ! Guidelines
Lead-in
Objects can also be
# If overriding Equals, override GetHashCode
compared for equality. # If overloading ==, override Equals to use same
algorithm
# If implementing IComparable, implement Equals
# Equals, GetHashCode, and == operator should never
throw exceptions
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.
8 Module 6: Working with Types
The following example shows how to override the Equals method and the ==
and != operators to test user-defined Rectangle objects for equality.
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);
}
}
Module 6: Working with Types 9
String Representation
Topic Objective
To explain how the ! Override ToString to Customize String Form of a Class
ToString method is used in
the .NET Framework struct
struct President
President
common language runtime. {{
Lead-in public
public string
string FirstName;
FirstName;
All objects have the ability to public
public string LastName;
string LastName;
represent themselves in a public
public override
override string
string ToString()
ToString()
string form. {{
return
return FirstName
FirstName ++ "" "" ++ LastName;
LastName;
}}
}}
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.ToString());
}
}
Static Constructors
Topic Objective
To explain how static
constructors work. ! Used to Initialize Static Members
Lead-in
class
class DeviceConnection
DeviceConnection
Static constructors are used
to initialize static fields. {{ public
public static
static uint
uint ConnectionCount;
ConnectionCount;
public
public void OpenConnection(string connectionName)
void OpenConnection(string connectionName)
{{ ConnectionCount++;
ConnectionCount++;
//Other
//Other work
work to
to open
open device
device }}
static
static DeviceConnection()
DeviceConnection()
{{ //Initialize
//Initialize static
static members
members
ConnectionCount
ConnectionCount == 0; 0; }}
}}
! .cctor in Disassembly
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);
}
}
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
}
}
Private Constructors
Topic Objective
To explain when to use
private constructors. ! Prevent a Class from Being Instantiated
Lead-in ! Use Them on Classes with All Static Members
A private constructor can
never be called. Therefore ! Use a Protected Constructor to Inherit from the Class
any class with a private
constructor cannot be class
class Trig
Trig
instantiated. {{
public
public static
static double
double Sin
Sin (double
(double x)
x)
{{ //Calculate
//Calculate and return
and return sin(x)
sin(x) }}
public
public static
static double
double Cos
Cos (double
(double x)
x)
{{ //Calculate
//Calculate and return
and return cos(x)
cos(x) }}
public
public static
static double
double Tan
Tan (double
(double x)
x)
{{ //Calculate
//Calculate and
and return
return tan(x)
tan(x) }}
private
private Trig(){}
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.
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.
18 Module 6: Working with Types
Conversions
Topic Objective
To explain when and how
to use explicit and implicit ! Explicit Conversions
conversions.
int
int xx == 5;
5;
Lead-in double
double yy == (double)
(double) x;
x;
Conversion is the process
of changing a type to ! Implicit Conversions
another type.
int
int xx == 5;
5;
double
double yy == x;
x;
! Conversion Operators
public
public static
static implicit
implicit operator
operator byte(Digit
byte(Digit d)
d)
public
public static
static explicit
explicit operator
operator Digit(byte
Digit(byte b)
b)
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 To
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
}
}
22 Module 6: Working with Types
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.
Module 6: Working with Types 23
Casting
Topic Objective
To explain how casting is
used in the .NET
Framework. ! Casting Up from Derived Class to Base Class
Lead-in ! Casting Down from Base Class to Derived Class
Casting is used for explicit
conversions. However, ! Type Operators
casting is also used for
changing the type that is # is
used to reference an object.
# as
# typeof
! Casting Interfaces
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.
24 Module 6: Working with Types
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;
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 Developer’s Kit
(SDK) documentation and Module 17, “Attributes,” in Course 2349B,
Programming with the Microsoft .NET Framework (Microsoft Visual C#
.NET).
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();
Module 6: Working with Types 25
Boxing
Topic Objective
To explain when and how ! Boxing Occurs to Convert a Value Type to a
boxing occurs. Reference Type
Lead-in
Boxing and unboxing are # Instance of System.Object is allocated on heap
conversions that occur
automatically when a value
# Value type is copied to new object
type is converted to an int
int xx == 5;
5; //Value
//Value type
type
object or when an object is Object
Object o = x; //Boxed
o = x; //Boxed
converted to a value type. Console.WriteLine("The
Console.WriteLine("The answer
answer is
is :: {0}
{0} ",
", x);//Boxed
x);//Boxed
! Unboxing Occurs to Retrieve Value Type from Object
int
int yy == (int)
(int) o;
o; //unbox
//unbox
! Boxing Can Be Expensive If Inside Loops
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.
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
}
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
}
Module 6: Working with Types 27
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
}
" Interfaces
Topic Objective
To provide an overview of
the topics covered in this
section. ! Inheritance Considerations
Lead-in ! Explicit Interface Implementation
When designing and using
interfaces, you should
consider a number of
factors.
Inheritance Considerations
Topic Objective
To explain the use of
inheritance and the use of
interfaces. ! Multiple Inheritance
Lead-in interface
interface IFoo
IFoo {void
{void DoSomething1();}
DoSomething1();}
Interfaces are used only interface
interface IBar
IBar {void
{void DoSomething2();}
DoSomething2();}
through inheritance. class
class MyObject
MyObject :: IFoo,
IFoo, IBar
IBar {...}
{...}
! Deriving New Interfaces from Existing Ones
interface
interface INewInterface
INewInterface :: IFoo,
IFoo, IBar
IBar
{void DoSomething3();}
{void DoSomething3();}
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");
}
}
30 Module 6: Working with Types
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.
32 Module 6: Working with Types
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 MainClass
{
public static void Main()
{
MyObject o = new MyObject();
IFoo foo = (IFoo) o;
IBar bar = (IBar) o;
foo.DoSomething();
bar.DoSomething();
}
}
This module does not cover all aspects of Platform Invocation Services or COM
Integration Services. For more information, see Module 15, “Interoperating
Between Managed and Unmanaged Code,” in Course 2349B, Programming
with the Microsoft .NET Framework (Microsoft Visual C# .NET) and
“Interoperating with Unmanaged Code” in the .NET Framework SDK
documentation.
Module 6: Working with Types 35
class MainClass
{
[DllImport("user32.dll", CharSet=CharSet.Ansi)]
public static extern int MessageBox(int h, string m,
string c, int type);
COM Interoperability
Topic Objective
To introduce COM
interoperability.
! Exposing .NET Framework Classes to COM
Lead-in
COM interoperability allows # Must create COM Callable Wrapper
managed code to create
and call COM objects. It # Create CCWs by using Tlbexp.exe
also allows COM objects to
create and call .NET # Register by using Regasm.exe
Framework objects.
! Exposing COM Classes to the .NET Framework
# Must create Runtime Callable Wrapper
# Create RCWs by using Tlbimp.exe
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.
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 equality
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.
40 Module 6: Working with Types
! Implement conversion
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 OfficeSizes
<= 64 Small
>64 and <100 Medium
>=100 Large
3. Assign the Building and Room values to the new type and return an
instance of the new type.
! Test
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.
Module 6: Working with Types 41
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.
RangeBegin uint
RangeEnd uint
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! System.Object Class Functionality
Lead-in ! Specialized Constructors
The review questions cover
some of the key concepts ! Type Operations
taught in the module.
! Interfaces
! Managing External Types
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.
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.
Contents
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
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 7: Strings, Arrays, and Collections iii
Instructor Notes
Presentation: After completing this module, students will be able to:
120 Minutes
! Parse, format, manipulate, and compare strings.
Lab: ! Use the classes in the System.Array and System.Collections namespaces.
60 Minutes
! Improve the type safety and performance of collections by using specialized
collections and class-specific code.
Required Materials
To teach this module, you need the Microsoft® PowerPoint® file 2349B_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.
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.
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\Mod07\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\Mod07\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.
Module 7: Strings, Arrays, and Collections v
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.
Module 7: Strings, Arrays, and Collections 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Strings
Lead-in ! Terminology – Collections
In this module, you will learn
about some of the key ! .NET Framework Arrays
classes in the .NET
Framework class library. ! .NET Framework Collections
" Strings
Topic Objective
To introduce the topics in
the section. ! Parse
Lead-in ! Format
In this section, you will learn ! Format Examples
how to work with strings in
! Changing Case
the .NET Framework.
! Compare
! Trim and Pad
! Split and Join
! StringBuilder
! C# Specifics
! Regular Expressions
Parse
Topic Objective ! Parse Method Converts a Numeric String to a Numeric
To explain how the Parse
method is used to convert
string
string MyString
MyString == "12345";
"12345";
numeric strings to a .NET
int
int MyInt == int.Parse(MyString);
MyInt int.Parse(MyString);
Framework numeric base
type. MyInt++;
MyInt++;
Console.WriteLine(MyInt);
Console.WriteLine(MyInt);
Lead-in //
// The
The output
output to
to the
the console
console is
is "12346".
"12346".
The Parse method converts
a string that represents a
.NET Framework numeric ! To Ignore Commas, Use the
base type to an actual .NET NumberStyles.AllowThousands Flag
Framework numeric base
type. string
string MyString
MyString == "123,456";
"123,456";
int
int MyInt == int.Parse(MyString,
MyInt int.Parse(MyString,
System.Globalization.NumberStyles.AllowThousands);
System.Globalization.NumberStyles.AllowThousands);
Console.WriteLine(MyInt);
Console.WriteLine(MyInt);
//
// The
The output
output to
to the
the console
console is
is "123456".
"123456".
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".
4 Module 7: Strings, Arrays, and Collections
Format
Topic Objective
To explain how to use
format strings, or specifiers, ! Format Strings Are Used in Methods That Create String
to format the appearance of Representations of a .NET Framework Data Type
your application.
# To display $100.00 to the console on computers on
Lead-in which U.S. English is the current culture
The .NET Framework
provides several format int
int MyInt
MyInt == 100;
100;
strings that you can use to string
format the appearance of string MyString
MyString == MyInt.ToString("C");
MyInt.ToString("C");
Console.WriteLine(MyString);
Console.WriteLine(MyString);
strings that derive from
other objects. # Alternatively
int
int MyInt
MyInt == 100;
100;
Console.WriteLine("{0:C}",
Console.WriteLine("{0:C}", MyInt);
MyInt);
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);
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);
Format Examples
Topic Objective
To provide examples of ! Currency Format
format strings that return
common numeric string # C - $XX,XXX.XX
types.
int
int MyInt
MyInt == 12345;
12345;
Lead-in string
string MyString
MyString == MyInt.ToString("C"
MyInt.ToString("C" ););
Let’s look at some examples //
// In
In the
the U.S.
U.S. English
English culture:
culture: "$12,345.00"
"$12,345.00"
of format strings that return
the value of MyString in the ! Date Time Format
currency and date time
formats. # D - dd MMMM yyyy
# d - MM/dd/yyyy
DateTime
DateTime MyDate
MyDate == new
new DateTime(2000,
DateTime(2000, 1,
1, 10,
10, 0,
0, 0,
0, 0);
0);
string
string MyString
MyString == MyDate.ToString(
MyDate.ToString( "d"
"d" );
);
//
// In
In the
the U.S.
U.S. English
English culture:
culture: "1/10/2000"
"1/10/2000"
The following table lists some format characters for standard patterns that are
used to format DateTime types.
Associated Example Format Pattern
Format Character Property/Description (en-US)
The following example shows the use of the format string that returns the value
of MyDate in the short date pattern format:
DateTime MyDate = new DateTime(2000, 1, 10, 0, 0, 0);
Changing Case
Topic Objective
To explain how to use the
String.ToUpper and
String.ToLower methods to
! You Can Easily Change the Case of a String
change the case of a string. # String.ToUpper – converts to upper case
Lead-in
string
string MyString
MyString == "hello
"hello world!";
world!";
You can easily change the
//
// outputs:
outputs: HELLO
HELLO WORLD!
WORLD!
case of a string by using the
Console.WriteLine(MyString.ToUpper());
Console.WriteLine(MyString.ToUpper());
String.ToUpper and
String.ToLower methods.
# String.ToLower – converts to lower case
string
string MyString
MyString == "HELLO
"HELLO WORLD!";
WORLD!";
// outputs: hello world!
// outputs: hello world!
Console.WriteLine(MyString.ToLower());
Console.WriteLine(MyString.ToLower());
Compare
Topic Objective
To introduce some of the
value-comparison methods ! The .NET Framework Has Methods to Compare Strings
that are used to compare
the values of strings. # For example, the Compare method compares the
Lead-in current string object to another string or object, returning:
The .NET Framework - Negative if first string is less than second string
provides several value-
comparison methods to
- 0 if the two strings are equal
compare the values of - Positive if first string is greater than second string
strings.
string
string MyString
MyString == "Hello
"Hello World!";
World!";
Console.WriteLine(
Console.WriteLine(
String.Compare(MyString,"Hello
String.Compare(MyString,"Hello World!"));
World!"));
//
// outputs:
outputs: 00
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.
Module 7: Strings, Arrays, and Collections 11
The following table shows the three integer values that are returned by the
Compare(string strA, string strB) method.
Value Type Condition
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!"));
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 Use
String.Trim Removes white spaces from the beginning and end of a string.
String.Remove 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 );
For a complete list of trim methods in the System.String class, see “Trimming
and Removing Characters” in the .NET Framework SDK documentation.
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 Use
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, '-'));
StringBuilder
Topic Objective
To explain how to use the ! The String Object is Immutable
StringBuilder method to
modify a string without ! System.Text.StringBuilder – Allows You to Modify a
creating a new object. String Without Creating a New Object
Lead-in StringBuilder
StringBuilder MyStringBuilder
MyStringBuilder == new
new StringBuilder("Hello");
StringBuilder("Hello");
When you want to perform
repeated modifications to a ! You Can Specify the Maximum Number of Characters
string, use the
//
// MyStringBuilder
MyStringBuilder can
can hold
hold aa maximum
maximum of
of 25
25 characters
characters
System.Text.StringBuilder
StringBuilder
StringBuilder MyStringBuilder
MyStringBuilder ==
class to modify a string new
without creating a new new StringBuilder("Hello
StringBuilder("Hello World!",
World!", 25);
25);
object. ! Methods Include:
# Append, AppendFormat, Insert, Remove,
and Replace
StringBuilder Methods
The following table describes the methods that you can use to modify the
contents of the StringBuilder object.
Method Name Use
C# Specifics
Topic Objective ! C# string Type Is a String of Unicode Characters
To explain what the string # Alias for System.String
type is in the .NET
Framework and to describe # Equality operators (== and !=) compare the values of string objects,
the functions of the +, [ ], not references
and != operators, and @- # The + operator concatenates strings
quoting.
string
string aa == "\u0068ello
"\u0068ello ";
";
Lead-in string
string bb == "world";
"world";
The string type represents Console.WriteLine(
Console.WriteLine( aa ++ bb ==
== "hello
"hello world"
world" );//True
);//True
a string of Unicode
characters; string is an # The [ ] operator accesses individual characters of a string
alias for System.String in
char
char xx == "test"[2];
"test"[2]; //
// xx == 's';
's';
the .NET Framework.
String literals are of type string and can be written in two forms: quoted and
@-quoted. Quoted string literals are enclosed in 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
18 Module 7: Strings, Arrays, and Collections
@-quoted string literals start with @ and are enclosed in 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"
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
Module 7: Strings, Arrays, and Collections 19
Regular Expressions
Topic Objective
To briefly describe how
regular expressions can be
used in the .NET ! Regular Expressions – Powerful Text Processing
Framework.
! Pattern-Matching Notation Allows You to:
Lead-in
Regular expressions allow # Find specific character patterns
you to quickly parse large
amounts of text in order to # Extract, edit, replace, or delete text substrings
find specific character
# Add the extracted strings to a collection to generate
patterns; to extract, edit,
replace, or delete text a report
substrings; and to add the
! Designed to be Compatible With Perl 5
extracted strings to a
collection to generate a
report.
This topic provides a brief Regular expressions provide a powerful, flexible, and efficient method to
summary of regular process text. The extensive pattern-matching notation of regular expressions
expressions. Do not spend allows you to quickly parse large amounts of text to find specific character
much time on this slide, but patterns; to extract, edit, replace, or delete text substrings; and to add the
encourage students to refer extracted strings to a collection in order to generate a report.
to the .NET Framework
SDK, especially for details For many applications that deal with strings, such as HTML processing, log file
about using the regular parsing, and HTTP header parsing, regular expressions are an essential tool.
expression classes.
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.
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 ! In This Module, the Term Collection Is Used in Its
collections are found in the Broader Sense to Refer to a Group of Items
.NET Framework.
! In the .NET Framework, Collections Are Found in
Lead-in the Namespaces
In this module, the term
collection is used in its # System.Array
broader sense: to describe a
group of items. # System.Collections
Do not spend much time on In this module, the term collection is used in its broader sense to refer to a
this slide. The objective of group of items. In the .NET Framework, examples of collections are found in
this slide is to define the the namespaces System.Array, and System.Collections.
term collection clearly,
before discussing the
collections that are found in
the .NET Framework.
Module 7: Strings, Arrays, and Collections 21
System.Array
Topic Objective
To explain how array types
are used and defined. ! System.Array Is the Base Class of All Array Types
Lead-in ! Arrays Implement the Following Interfaces
The System.Array class is
the base class of all array # ICloneable, IList, ICollection, and IEnumerable
types and contains methods
for creating, manipulating, ! System.Array Has Methods For
searching, and sorting
arrays. # Creating, manipulating, searching, and sorting
! Null, Empty String, and Empty (0 item) Arrays Should Be
Treated the Same
# Therefore, return an Empty array, instead of a
null reference
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.
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 Use
Property Use
IsFixedSize Gets a value that indicates whether the Array has a fixed size.
IsReadOnly Gets a value that indicates whether the Array is read-only.
Length Gets the total number of elements in all of the dimensions of the
Array.
Rank Gets the rank (number of dimensions) of the Array.
Note The IsFixedSize and IsReadOnly properties are always false unless they
are overridden by a derived class.
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 Use
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 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.
Module 7: Strings, Arrays, and Collections 25
C# Specifics
Topic Objective ! C# Array Indexes Start at Zero
To explain features that are
unique to C# arrays. ! Declaring an Array – Size Is Not Part of Its Type
Lead-in int[]
int[] numbers;
numbers; //
// declare
declare numbers
numbers as
as
C# arrays are similar to //
// an int array of
an int array of any
any size
size
arrays in most other popular ! Creating an Array
languages, but you should
be aware of the differences int[]
int[] numbers
numbers == new
new int[5];
int[5]; //
// declare
declare and
and create
create
that are presented in this
topic. ! Initializing an Array
int[]
int[] numbers
numbers == new
new int[5]
int[5] {1,
{1, 2,
2, 3,
3, 4,
4, 5};
5};
! Using System.Array Members
int[]
int[] numbers
numbers == {1,
{1, 2,
2, 3,
3, 4,
4, 5};
5};
int LengthOfNumbers
int LengthOfNumbers == numbers.Length;
numbers.Length;
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 array’s length, as in the following examples.
int[] numbers; // declare numbers as an int array of any size
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
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
// Multidimensional array
string[,] names = new string[5,4];
Initializing Arrays
C# provides simple and straightforward ways to initialize arrays when they are
declared, by enclosing the initial values in curly braces ( {} ).
Single-Dimensional Array
The following examples show different ways to initialize single-dimensional
arrays:
int[] numbers = new int[5] {1, 2, 3, 4, 5};
You can omit the size of the array, as in the following examples:
int[] numbers = new int[] {1, 2, 3, 4, 5};
If an initializer is provided, you can also omit the new statement, as in the
following examples:
int[] numbers = {1, 2, 3, 4, 5};
Multidimensional Array
The following examples show different ways to initialize multidimensional
arrays:
int[,] numbers = new int[3, 2] { {1, 2}, {3, 4}, {5, 6} };
You can omit the size of the array, as in the following examples:
int[,] numbers = new int[,] { {1, 2}, {3, 4}, {5, 6} };
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} };
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} };
The following code example shows how to access a member of a jagged array:
int[][] numbers = new int[][]
{
new int[] {1, 2},
new int[] {3, 4}
};
numbers[1][1] = 5;
The System.Array class provides many other useful methods and properties,
such as methods for sorting, searching, and copying arrays.
30 Module 7: Strings, Arrays, and Collections
Iterating Over
Topic Objective ! System.Array and System.Collections Classes
To explain the role of the
IEnumerable and
Implement IEnumerable Interface and its
IEnumerator interfaces in GetEnumerator Method
collections.
! Enumerator Classes Implement IEnumerator
Lead-in
A .NET Framework interface # Members: MoveNext, Reset, and Current
provides a way to group a
int[]
int[] numbers
numbers == new
new int[5]
int[5] {1,
{1, 2,
2, 3,
3, 4,
4, 5};
5};
set of related members that
IEnumerator e = numbers.GetEnumerator();
IEnumerator e = numbers.GetEnumerator();
can be used to perform a
while
while (e.MoveNext())
(e.MoveNext()) {{
particular action.
Console.WriteLine("Number:
Console.WriteLine("Number: {0}", {0}", (int)e.Current);
(int)e.Current);
}}
//
// alternatively
alternatively
foreach
foreach (int
(int ii in
in numbers)
numbers)
{{
Console.WriteLine("Number:
Console.WriteLine("Number: {0}",{0}", i);
i);
}}
*****************************ILLEGAL FOR NON-TRAINER USE******************************
Emphasize the difference To understand the functionality of the various collection classes, you must
between enumeration and understand the key interfaces of the collection classes. A .NET Framework
an enumerator. 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.
The IEnumerator interface has the Current public instance property. 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 Use
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.
After 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.
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);
}
Comparing
Topic Objective ! To Sort and Search, Collections Must Be Able to Compare Items
To explain how the ! IComparer’s Compare Method Compares Two Objects of Any Type
IComparer and int
IComparable interfaces are int Compare(
Compare( object
object x,
x, object
object yy );
);
used to sort and order a # Comparer class is the default implementation of IComparer
collection’s items. Its Compare method uses IComparable.CompareTo
Lead-in ! IComparable’s CompareTo Method Compares the Current Instance
To sort a collection, you to an Object of the Same Type
must be able to compare int
and order the items of the int CompareTo(
CompareTo( object
object anObject
anObject );
);
collection. ! CompareTo Returns
Value Meaning
Less than zero Instance is less than object
Zero Instance is equal to object
Greater than zero Instance is greater than object
*****************************ILLEGAL FOR NON-TRAINER USE******************************
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 collection’s items.
The IComparer interface’s 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.
The following table describes the possible meanings of the return value.
Value Meaning
By definition, any object compares greater than a null reference, and two null
references compare equal to each other.
Sorting
Topic Objective
To explain how to compare ! Sort Method Using Element’s IComparable.CompareTo
and order the items of a
collection by using the Array.Sort(
Array.Sort( anArray
anArray );
);
IComparer and
IComparable interfaces. ! IComparable.CompareTo Design Pattern
Knowledge of this topic is
required for the lab. public
public int
int CompareTo(Object
CompareTo(Object anObject)
anObject) {{
if
if (( anObject
anObject ==== null)
null) return
return 1;
1;
Lead-in if
Some collections, such as if (( !(anObject
!(anObject isis <classname>)
<classname>) )) {{
throw
throw new
new ArgumentException();
ArgumentException(); }}
Array, sort their items when //
their Sort method is called. // Do comparison and
Do comparison and return
return aa
//
// negative integer if instance
negative integer if instance << anObject
anObject
// 0 if instance == anObject
// 0 if instance == anObject
//
// positive
positive integer
integer if
if instance
instance >> anObject
anObject
}}
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;
}
}
}
}
Do not spend a lot of time The following table shows some of the collection classes in the
on this slide. Just introduce System.Collections namespace.
students to some commonly
used collection classes and Class Description
encourage them to refer to
the .NET Framework SDK ArrayList Implements the IList interface by using an array whose
for more information. size is dynamically increased as required.
BitArray 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).
CollectionBase Provides the abstract base class (MustInherit in
Microsoft Visual Basic®) for a strongly-typed collection.
DictionaryBase Provides the abstract base class (MustInherit in
Visual Basic) for a strongly-typed collection of
associated keys and values.
Hashtable Represents a collection of associated keys and values that
are organized around the hash code of the key.
Queue Represents a first-in, first-out collection of objects.
ReadOnlyCollectionBase Provides the abstract base class (MustInherit in
Visual Basic) for a strongly-typed read-only collection.
SortedList Represents a collection of associated keys and values that
are sorted by the keys and are accessible by key and by
index.
Stack Represents a simple last-in-first-out collection of type
Object.
Module 7: Strings, Arrays, and Collections 41
Lists
Topic Objective
To describe the public
instance members that the
IList interface implements. ! IList – Interface for Classes That Represent an Ordered
Collection of Objects That Can Be Individually Indexed
Lead-in
IList is an interface for ! Some Classes That Implement IList
classes that represent an
ordered collection of objects # Array, ArrayList, StringCollection, and
that can be individually TreeNodeCollection
indexed. Array, ArrayList,
StringCollection, and ! Methods Include:
TreeNodeCollection are
some of the classes that # Add, Clear, Contains, Insert, IndexOf, Remove, and
implement IList. RemoveAt
IsFixedSize When implemented by a class, gets a value indicating whether the IList
has a fixed size.
IsReadOnly When implemented by a class, gets a value indicating whether the IList
is read-only.
Item 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.
42 Module 7: Strings, Arrays, and Collections
The following table describes the public instance methods that the IList
interface defines.
Method Use
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.
class listSample
{
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 the following page.)
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
List Contains:
Apple
Pear
Kiwi
Orange
Banana
Dictionaries
Topic Objective
To describe the IDictionary
interface and the classes ! IDictionary is an Interface for Collections of Associated
that it implements. Keys and Values
Lead-in # Each association must have a unique non-null key, but
IDictionary is an interface
for collections of associated
the value of an association can be any object reference,
keys and values. including a null reference
! Collection Classes That Implement IDictionary Include
# Hashtable, DictionaryBase, and SortedList
! Methods Include:
# Add, Clear, Contains, GetEnumerator, and Remove
The following table describes some of the public instance properties that the
IDictionary interface implements.
Property Use
The following table describes some of the public instance methods that the
IDictionary interface implements.
Method Use
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 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);
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 Name
-- ----
1254 Brian
6839 Seth
3948 Rajesh
1930 Lakshan
0123 Jay
0569 Brad
SortedList
Topic Objective ! SortedList Maintains Two Arrays for Entries
To explain how arrays are
used in a SortedList and # One array for the keys and another array for the associated values
how to create, initialize, and SortedList
access a SortedList. This SortedList mySL
mySL == new
new SortedList();
SortedList();
//
// Add an entry with aa key
Add an entry with key == "First"
"First" and
and aa value
value == 11
topic is very important
mySL.Add("First",
mySL.Add("First", 1);1);
because its contents are
//
// Increment
Increment the
the value
value of
of the
the entry
entry whose
whose key
key == "First"
"First"
required for the lab.
mySL["First"] = (Int32)mySL["First"]
mySL["First"] = (Int32)mySL["First"] + 1; + 1;
Lead-in
! Count Property – Number of Elements in the SortedList
A SortedList maintains two
arrays internally to store ! Sorted Using a Specific IComparer Implementation or According to
entries to the list: one array the Key's IComparable Implementation
for the keys, and another ! Printing the Keys and Values of a SortedList
array for the associated
values. for
for (( int
int ii == 0;
0; ii << myList.Count;
myList.Count; i++
i++ )) {{
Console.WriteLine( "\t{0}:\t{1}",
Console.WriteLine( "\t{0}:\t{1}",
myList.GetKey(i),
myList.GetKey(i), myList.GetByIndex(i)
myList.GetByIndex(i) );
); }}
*****************************ILLEGAL FOR NON-TRAINER USE******************************
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.
You can sort the keys of a SortedList according to an IComparer
For Your Information implementation that is specified when the SortedList is instantiated or
You should carefully cover
the SortedList class, the
according to the IComparable implementation that is provided by the keys
Add method, and the [ ] themselves. In either case, a SortedList does not allow duplicate keys.
Operator because they are
Operations on a SortedList tend to be slower than operations on a Hashtable
used in the lab.
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.
Module 7: Strings, Arrays, and Collections 51
The following example shows how to create a SortedList, add an entry, modify
an entry’s value, and print out the SortedList’s keys and values.
using System;
using System.Collections;
public class SamplesSortedList {
The preceding code example displays the following output to the console:
mySL
Count: 3
Capacity: 16
Keys and Values:
-KEY- -VALUE-
First: 1
Second: 2
Third: 3
-KEY- -VALUE-
First: 1
Second: 2
Third: 4
52 Module 7: Strings, Arrays, and Collections
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 Description
For example, in the case of a collection of integer values where you want to be
able to add an integer to an element’s value, you can have your value type
implement an interface, as in the following code:
interface IAdd
{
void Add(int amount);
}
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.
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.
Words Chars
11 41
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.
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
entry’s 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.
Module 7: Strings, Arrays, and Collections 61
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
Module 7: Strings, Arrays, and Collections 63
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Strings
Lead-in ! Terminology – Collections
The review questions cover
some of the key concepts ! .NET Framework Arrays
taught in the module.
! .NET Framework Collections
2. What class should you use to improve performance when you want to
perform repeated modifications to a string?
System.Text.StringBuilder
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.
Contents
Overview 1
Delegates 2
Multicast Delegates 12
Events 21
When to Use Delegates, Events, and
Interfaces 31
Lab 8: Creating a Simple Chat Server 32
Review 42
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 8: Delegates and Events iii
Instructor Notes
Presentation: After completing this module, students will be able to:
75 Minutes
! Use the delegate class to create type-safe callback functions and event-
Lab: handling methods.
75 Minutes
! 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.
Required Materials
To teach this module, you need the Microsoft PowerPoint® file 2349B_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.
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 object’s method is passed to a switch object.
When the switch object’s state changes, the switch object calls the light
object’s 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
Use the Event Scenario to help students to visualize and comprehend the
concept of 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.
Module 8: Delegates and Events 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Delegates
Lead-in ! Multicast Delegates
Delegates are the object-
oriented equivalents of ! Events
function pointers.
! When to Use Delegates, Events, and Interfaces
" Delegates
Topic Objective
To provide an overview of
the topics in this section.
! Delegate Scenario
Lead-in
In this section, you will learn ! Declaring a Delegate
about how delegates are
used in the .NET ! Instantiating a Delegate
Framework.
! Calling a Delegate
Delegate Scenario
Topic Objective 1 - Change in
To illustrate one use of switch position Switch Object
delegates through the invokes switch’s
OnFlip method
scenario of a switch and a
light bulb.
Lead-in Light Object
This scenario of a switch
that controls a light OnFlip method
illustrates one use of
delegates. 2 - OnFlip Method
invokes delegate
OnFlipCallback
Delegate
Delegate object
object method
To run the build slide, click This scenario of a switch that controls a light illustrates one use of delegates.
through the lower-left button The switch object models an electric switch, and the light object models an
on the slide. electric light. The delegate object encapsulates a reference to a light object’s
OnFlipCallback method.
The switch object code could be written without a delegate by referring directly
to the specific light object’s 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.
In real life, the preceding scenario would probably not occur as described.
For Your Information While a house would never be rewired dynamically, software programs often
Stress that this scenario
reflects a common scenario
need to dynamically rebind.
to which everyone can When the switch is flipped in the light switch scenario shown in the slide:
relate. While you may not
use the same light switch to 1. The switch object’s OnFlip method is invoked.
turn different lights on and
off at different times, this 2. The OnFlip method invokes the delegate object.
scenario helps you to 3. The delegate object invokes the light object’s OnFlipCallback method.
visualize and comprehend
the concepts behind 4. The OnFlipCallback method changes the state of the light.
delegates.
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.
4 Module 8: Delegates and Events
Declaring a Delegate
Topic Objective
To explain how to declare a
delegate.
! A Delegate Declaration Defines a Type That
Lead-in Encapsulates a Method with a Particular Set of
A delegate declaration Arguments and Return Type
defines a type that
encapsulates a method with
a particular set of arguments
and return type. //
// declares
declares aa delegate
delegate for
for aa method
method that
that takes
takes aa single
single
//
// argument
argument of
of type
type string
string and
and has
has aa void
void return
return type
type
delegate
delegate void
void MyDelegate1(string
MyDelegate1(string s);
s);
Instantiating a Delegate
Topic Objective
To explain how to instantiate
delegates.
! A Delegate Object Is Created with the new Operator
Lead-in
After you have declared a ! Delegate Objects Are Immutable
delegate type, you can
create a delegate object and //
// instantiating
instantiating aa delegate
delegate to
to aa static
static method
method Hello
Hello
associate it with a particular //
// in
in the
the class
class MyClass
MyClass
method. MyDelegate1
MyDelegate1 aa == new
new MyDelegate1(MyClass.Hello);
MyDelegate1(MyClass.Hello);
//
// instantiating
instantiating aa delegate
delegate to
to an
an instance
instance method
method
// AMethod in object
// AMethod in object p p
MyClass
MyClass pp == new
new MyClass();
MyClass();
MyDelegate1
MyDelegate1 bb == new
new MyDelegate1(p.AMethod);
MyDelegate1(p.AMethod);
Calling a Delegate
Topic Objective
To explain how to call
delegates.
! Use a Statement Containing:
Lead-in
After a delegate is created, # The name of the delegate object
it can be passed to other
code that will call the # Followed by the parenthesized arguments to be passed
delegate. to the delegate
//
// given
given the
the previous
previous delegate
delegate declaration
declaration and
and
//
// instantiation,
instantiation, the
the following
following invokes
invokes MyClass'
MyClass'
//
// static
static method
method Hello
Hello with
with the
the parameter
parameter "World"
"World"
a("World");
a("World");
using System;
For Your Information
As noted in C# Language-
namespace SwitchAndLight
Specific Syntax in this
module, delegate types with {
a void return value in C# public enum SwitchPosition {Up, Down};
cause the compiler to derive
the delegate class from the delegate void SwitchFlipped(SwitchPosition switchState);
MulticastDelegate class.
Therefore, the IL for this class Light
delegate demonstration {
code will show the private string name;
SwitchFlipped delegate
inheriting from the
public Light(string s)
System.MulticastDelegate
{
class.
name = s;
}
class Switch
{
private SwitchPosition switchState =
SwitchPosition.Down;
private SwitchFlipped switchFlippedHandler = null;
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);
}
}
}
}
Module 8: Delegates and Events 11
5 - delegate2 Multicast
Multicastdelegate2
delegate2object
object 6 - delegate2 invokes
is invoked light2’s OnFlipCallback
To run the build slide, click In the light scenario, multicast delegate1 refers to the light1 object’s
through the lower-left button OnFlipCallback method, and multicast delegate2 refers to the light2 object’s
on the slide. 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
The following scenario of a
switch that controls two
encapsulate references to two objects and two methods. When the switch is
lights illustrates the use of flipped:
multicast delegates. The 1. The switch object’s OnFlip method is invoked.
switch object models the
light switch, and the two 2. The OnFlip method invokes the multicast delegate1 object.
light objects model the two
electric lights. To provide
3. The multicast delegate1 object first invokes the light1 object’s
the capability to dynamically OnFlipCallback method.
connect, disconnect, and 4. The light1 object’s OnFlipCallback method changes the state of the light1
reconnect light object object.
methods to the switch
object, the switch object is 5. The multicast delegate1 object next invokes the multicast delegate2
dynamically connected to object.
the light objects by
6. The multicast delegate2 object invokes the light2 object’s
instantiating and composing
two multicast delegate OnFlipCallback method.
objects. 7. The light2 object’s OnFlipCallback method changes the state of the light2
object.
You can compose additional multicast delegates to allow the switch to control
additional lights.
14 Module 8: Delegates and Events
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 object with 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.
You can use the method GetInvocationList to obtain the invocation list as an
array of delegate references. You can also use the delegate’s 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.
Module 8: Delegates and Events 15
using System;
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);
The preceding code invokes the delegate that invokes object aFoo2’s Bar
method and outputs:
Bar invoked
Module 8: Delegates and Events 17
C# Language-Specific Syntax
Topic Objective
To present helpful
alternative C# syntax.
! C# Delegates That Return Void Are Multicast Delegates
Lead-in
Delegate types with a void ! In C#, Use the + and - Operators to Add and Remove
return value in C# cause the Invocation List Entries
compiler to derive the
delegate class from the # Less verbose than Combine and Remove methods
MulticastDelegate class.
MyDelegate
MyDelegate a, a, b,
b, c,
c, d;
d;
aa == new MyDelegate(Foo);
new MyDelegate(Foo);
bb == new
new MyDelegate(Bar);
MyDelegate(Bar);
cc == aa ++ b;
b; //
// Compose
Compose two
two delegates
delegates toto make
make another
another
dd == cc -- a;
a; //// Remove
Remove aa from
from the
the composed
composed delegate
delegate
aa +=
+= b;
b; //
// Add
Add delegate
delegate bb to
to a's
a's invocation
invocation list
list
aa -=
-= b;
b; //
// Remove
Remove delegate
delegate bb from
from a's
a's list
list
class MyClass
{
public static void Hello(string s) {
Console.WriteLine(" Hello, {0}!", s);
}
Delegate Details
Topic Objective
To show how a delegate
declaration is handled by
the compiler. ! A Delegate Declaration Causes the Compiler to
Generate a New Class
Lead-in
When delegate declarations
//
// delegate
delegate void
void MyDelegate3(string
MyDelegate3(string val);
val);
are compiled, the compiler
generates a new class that
derives from class
class MyDelegate3
MyDelegate3 :: System.MulticastDelegate
System.MulticastDelegate {{
System.Delegate. public
public MyDelegate3(object
MyDelegate3(object obj,
obj, methodref
methodref mref)
mref)
:: base (obj, mref) { //...
base (obj, mref) { //...
}}
public
public void
void virtual
virtual Invoke(string
Invoke(string val)
val) {{ //...
//...
}}
};
};
The first member is a constructor: its first parameter is the delegate’s 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.
Module 8: Delegates and Events 21
" Events
Topic Objective
To provide an overview of
the topics in this section.
! Event Scenario
Lead-in
An event is a way for a class ! Declaring an Event
to notify clients of that class
of a change in an object. ! Connecting to an Event
! Raising an Event
! .NET Framework Guidelines
Event Scenario
Topic Objective Mouse Object SoundMaker Object
To illustrate the .NET event MouseClicked field
mechanism through the MouseClicked
MouseClicked method
method
Invocation List:
scenario of a mouse clicked
event.
Lead-in multicast delegate object
This scenario of a mouse
object that notifies multicast delegate object
stopButton object
interested objects when a
mouse clicked event occurs MouseClicked
MouseClicked method
method
illustrates one use of add_MouseClicked method
delegates and events.
remove_MouseClicked method
OnMouseClicked
method
To run the build slide, click This scenario of a mouse object that notifies interested client objects when a
through the lower-left button mouse click occurs illustrates one use of the .NET event mechanism. Client
on the slide. objects add and remove multicast delegate objects to the mouse object’s
invocation list. These delegates specify the event handler methods to be called
when a mouse click occurs. The mouse object code could be written to call a
predefined list of event handler methods. However, this approach does not offer
the flexibility to dynamically connect, disconnect, and reconnect methods to be
called when the mouse click event occurs. By using multicast delegate objects,
you can provide this flexibility.
In the mouse clicked event scenario that is shown in the slide, a mouse object
encapsulates code to monitor a hardware mouse:
1. The mouse object’s class uses the Microsoft Visual C#™ compiler event
keyword to have the compiler automatically create a private field named
MouseClicked that is used to store a reference to the invocation list of
delegates, and two public methods named add_MouseClicked and
remove_MouseClicked that are used to add and remove delegates to this
list. You can call these methods in Visual C# by using the += and -=
operators.
2. The mouse object’s class declares an OnMousedClicked method that is
called when a mouse click is detected. The OnMouseClicked method raises
the MouseClicked event by invoking the invocation list’s first delegate
object.
3. A user issues a command that causes sound to be generated whenever the
mouse is clicked. This command causes the mouse object’s
add_MouseClicked method to be called with a delegate object that points
to the soundMaker object’s MouseClicked method. This delegate is added
to the mouse object’s MouseClicked invocation list.
4. The mouse is clicked and the mouse object’s OnMouseClicked method is
called to raise the mouse clicked event.
Module 8: Delegates and Events 23
Declaring an Event
Topic Objective
To explain how to declare ! Declare the Delegate Type for the Event
events.
Lead-in ! Declare the Event
To declare an event inside a
class, you first must declare # Like the field of delegate type preceded by an event
a delegate type for the keyword
event.
//
// MouseClicked
MouseClicked delegate
delegate declared
declared
public
public delegate
delegate void
void MouseClickedEventHandler();
MouseClickedEventHandler();
public
public class
class Mouse
Mouse
{{
//
// MouseClicked
MouseClicked event
event declared
declared
public
public static
static event
event MouseClickedEventHandler
MouseClickedEventHandler
MouseClicked;
MouseClicked;
//...
//...
}}
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 MouseClicked:
public class Mouse
{
public static event MouseClickedEventHandler
MouseClicked;
//...
}
Module 8: Delegates and Events 25
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 MouseClicked, which refers to delegates of type
MouseClickedEventHandler, is created.
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_MouseClicked and remove_MouseClicked.
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.
26 Module 8: Delegates and Events
Connecting to an Event
Topic Objective
To describe how to connect
to and disconnect from an
event.
! Connect by Combining Delegates
Lead-in ! Disconnect by Removing Delegates
From outside the class that
declared it, an event looks //
// Client’s
Client’s method
method to
to handle
handle the
the MouseClick
MouseClick event
event
like a field, but access to private void MouseClicked() { //...
private void MouseClicked() { //...
that field is restricted. }}
//...
//...
//
// Client
Client code
code to
to connect
connect to
to MouseClicked
MouseClicked event
event
Mouse.MouseClicked +=
Mouse.MouseClicked += newnew
MouseClickedEventHandler(MouseClicked);
MouseClickedEventHandler(MouseClicked);
//
// Client
Client code
code to
to break
break connection
connection to
to MouseClick
MouseClick event
event
Mouse.MouseClicked
Mouse.MouseClicked -= -= new
new
MouseClickedEventHandler(MouseClicked);
MouseClickedEventHandler(MouseClicked);
//...
Raising an Event
Topic Objective
To show when and how to
raise an event.
! Check Whether Any Clients Have Connected to
Lead-in This Event
After a class has declared
an event, it can treat that # If the event field is null, there are no clients
event like a field of the
indicated delegate type. ! Raise the Event by Invoking the Event’s Delegate
if
if (MouseClicked
(MouseClicked !=
!= null)
null)
MouseClicked();
MouseClicked();
public
public delegate
delegate void
void SwitchFlippedEventHandler(
SwitchFlippedEventHandler(
object
object sender,
sender, SwitchFlippedEventArgs
SwitchFlippedEventArgs e);
e);
public
public event
event SwitchFlippedEventHandler
SwitchFlippedEventHandler SwitchFlipped;
SwitchFlipped;
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.
Module 8: Delegates and Events 29
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);
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.
30 Module 8: Delegates and Events
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};
//delegate declaration
public delegate void SwitchFlippedEventHandler(
object sender, SwitchFlippedEventArgs e);
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-and-
subscribe design.
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.
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 method’s 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 delegate’s invocation list and invoke only those
delegates that do not match the excluded client argument.
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 server’s “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.
Scenario
As in Exercise 2, each client connects with the server’s 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 client’s
delegates with a non-null object source parameter.
! Create the event class that will encapsulate the event’s state
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.
Module 8: Delegates and Events 39
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Delegates
Lead-in ! Multicast Delegates
The review questions cover
some of the key concepts ! Events
taught in this module.
! When to Use Delegates, Events, and Interfaces
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) { //...
};
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 user’s 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. Using the following declarations, write the code to add delegate b to a’s
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.
Contents
Overview 1
Memory Management Basics 2
Non-Memory Resource Management 12
Implicit Resource Management 13
Explicit Resource Management 26
Optimizing Garbage Collection 36
Lab 9: Memory and Resource Management 48
Review 55
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 9: Memory and Resource Management iii
Instructor Notes
Presentation: After completing this module, students will be able to:
125 Minutes
! Describe how garbage collection manages object memory.
Lab: ! Implicitly manage non-memory resources by using a destructor’s finalize
60 Minutes
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.
Required Materials
To teach this module, you need the Microsoft® PowerPoint® file 2349B_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.
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\
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
ResurrectionDemo methods.
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.
Multimedia
This section lists the multimedia items that are part of this module. Instructions
for launching and playing the multimedia are included with the relevant slides.
Garbage Collection
This animation will show students the .NET Framework common language
runtime garbage collection process, including finalization.
Module 9: Memory and Resource Management v
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 collection 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.
Module 9: Memory and Resource Management 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Memory Management Basics
Lead-in ! Non-Memory Resource Management
Objects in the Microsoft
.NET Framework use ! Implicit Resource Management
memory resources and may
use other resources, such ! Explicit Resource Management
as file handles. For software
! Optimizing Garbage Collection
to run properly, these
resources must be well
managed.
Developer Backgrounds
Topic Objective
To discuss various
developer backgrounds with
regard to memory ! COM
management.
# Manually implement reference counting and handle
Lead-in circular references
Your experience with
memory management will ! C++
vary depending upon your
development background. # Manually use the new operator and delete operator
! Visual Basic
# Accustomed to automatic memory management
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 object’s 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 runtime’s garbage
collector eliminates the need for reference counting and, as a result, the bugs
that can arise from this manual memory management scheme.
4 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 object’s 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.
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.
Module 9: Memory and Resource Management 7
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.
To launch the animation, This animation illustrates the .NET Framework common language runtime
click the button in the lower garbage collection process.
left corner of the slide. To
play the animation, click the
Simplified Garbage
Note Compiler optimization is disabled in this scenario to prevent an object
Collection button at the top from becoming eligible for garbage collection earlier than would be expected.
of the screen, and then click Otherwise, the compiler could optimize away assignments to local variables
the play button in the lower that are never observed by a later read. This optimization could result in an
left corner of the screen. object being subject to garbage collection before its reference is assigned to
null.
Finalization
Topic Objective
To define and describe
finalization in garbage
collection. ! Finalize Code Called by Garbage Collection
Lead-in ! In C#, the Finalize Code Is Provided by a Destructor
Implicit management of
resources ensures that an ! Use C# Destructor to Implicitly Close a FileStream
object can properly clean up
its resources at some time class
class Foo
Foo {{
in the future when there are private
private System.IO.FileStream
System.IO.FileStream fs;
fs;
no longer any valid //...
//...
references to the object. public
public Foo()
Foo() {{
fs
fs == new
new System.IO.FileStream(
System.IO.FileStream(
"bar",
"bar", FileMode.CreateNew);
FileMode.CreateNew);
}}
~Foo()
~Foo() {{ fs.Close();
fs.Close(); }}
}}
At this point, the finalization phase of the garbage collection process can
commence on a separate thread.
Module 9: Memory and Resource Management 17
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.
Finalization Guidelines
Topic Objective
To alert students to issues
that are associated with
! Avoid Finalization and Destructors If Possible
finalization.
# Performance costs
Lead-in
This topic provides # Complexity
guidelines for handling
# Delay of memory resource release
finalization.
! If You Require Finalization, Finalize Code Should:
# Avoid calling other objects
# Avoid making assumptions about thread ID
! Classes with Finalization Should:
# Avoid making references to other objects
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 on to. 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.
Module 9: Memory and Resource Management 21
void
void System.GC.ReRegisterForFinalize(object
System.GC.ReRegisterForFinalize(object obj);
obj);
After the garbage collection process calls an object’s 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 object’s finalize code again the next time the object is
destroyed. Note that if ReRegisterForFinalize is called multiple times, the
object’s 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);
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.
// Resurrection
// Create a ResurrectObj
ResurrectObj obj = new ResurrectObj("Resurrection");
// Implement IDisposable.
public void Dispose()
{
Dispose(true);
// Take yourself off of the Finalization queue.
GC.SuppressFinalize(this);
}
~BaseResource()
{
Dispose(false);
}
public MyResourceWrapper()
{
// Constructor for this object.
}
The following summarizes the way this design pattern works. Whenever an
object’s Finalize code or Dispose method is called it is always the object’s base
class’ implementation of these methods that is invoked. In the base class both
the Finalize code and Dispose method call the virtual Dispose method, and
this causes the code in the object’s actual class to be invoked. The virtual
Dispose method cleans up its class specific resources. The bool flag indicates
whether the call originated from Finalize or Dispose code. If finalization is
occurring the virtual Dispose method should not call methods in other objects
as these other objects may have already been finalized. The virtual Dispose
method then calls its parent’s class virtual Dispose method allowing the parent
class’ method to release its class specific resources. This calling of the parent
virtual Dispose methods continues until the base class’ virtual Dispose
method is called. This design pattern allows each class in the object’s class
hierarchy to release its class specific resources.
For Your Information ! Consider not having your object be fully usable after calling Dispose. It is
Students will need to be often difficult to recreate an object that has already been disposed.
able to determine which ! Allow your Dispose method to be called more than once without throwing
methods require resources an exception. It is a no-op after the first call.
that may have been
disposed to be able to do
the lab. Illustrate this
important concept with an
example or two.
Module 9: Memory and Resource Management 31
Note You can replace Close with a method name appropriate to your domain.
For Your Information Note The DisposeObj class in the demonstration does not contain any
Use the debugger to step managed resources that have Dispose methods. Therefore, it can use an
through the code while you implementation of the Dispose method that is simpler than the more general
point out features and ask design pattern.
students what they think will
happen next. In this section
run the DisposeDemo // This method demonstrates how to implement a type that
method. // 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();
! Using Statement
using
using (Resource
(Resource r1
r1 == new
new Resource())
Resource()) {{
r1.Foo();
r1.Foo();
}}
*****************************ILLEGAL FOR NON-TRAINER USE******************************
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();
}
}
34 Module 9: Memory and Resource Management
Weak References
Topic Objective
To introduce the use of
weak references to
conserve memory ! A Weak Reference Allows an Object to Be Collected If
resources. Memory Is Low
Lead-in Object
Object obj
obj == new
new Object();
Object(); //
// create
create strong
strong reference
reference
A weak reference allows WeakReference wr = new WeakReference(obj);
WeakReference wr = new WeakReference(obj);
garbage collection to collect obj
objects if memory in the obj == null;
null; //
// remove
remove strong
strong reference
reference
//
// ...
...
managed heap is low. obj
obj == (Object)
(Object) wr.Target;
wr.Target;
if
if (obj !=
(obj != null)
null) {//garbage
{//garbage collection
collection hasn’t
hasn’t occurred
occurred
// ...
// ...
}}
else
else {//
{// object
object was
was collected,
collected, reference
reference is
is null
null
//...
//...
}}
For Your Information Important Using the debugger to single-step through the WeakRefDemo code
In this section run the may prevent the garbage collection process from collecting an object that is
WeakRefDemo method. only referenced by a weak reference. Instead of using the debugger to single-
Read and follow the step through the code you should set breakpoints at the beginning and end of
procedure in the Note and
the WeakRefDemo method to observe that objects with only weak references
avoid using the debugger to
to them are collected.
single-step through the
WeakRefDemo code.
40 Module 9: Memory and Resource Management
// Create an object
BaseObj obj = new BaseObj("WeakRef");
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");
Generations
Topic Objective
To explain how the .NET
Framework common ! To Force Garbage Collection of Generation 0 Through a
language runtime uses a Specified Generation:
system of generations to
make garbage collection void
void System.GC.Collect(int
System.GC.Collect(int Generation);
Generation);
more efficient.
Lead-in ! To Determine the Generation of an Object:
To improve the performance
of garbage collection, the
.NET Framework uses a Int32
Int32 System.GC.GetGeneration(Object
System.GC.GetGeneration(Object obj);
obj);
system based on object
generations.
! To Return the Maximum Number of Generations That
the System Currently Supports:
Int32
Int32 System.GC.MaxGeneration;
System.GC.MaxGeneration;
Demonstration: Generations
Topic Objective
To demonstrate how
garbage collection handles
generations.
Lead-in
This demonstration shows
how garbage collection
handles generations.
Collect();
obj.DisplayGeneration(); // Displays 2
Collect();
obj.DisplayGeneration(); // Displays 2 (max generation)
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 Start, click Run, and in the text
box, type perfmon.exe.
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.
Module 9: Memory and Resource Management 47
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 workstation 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.
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.
Module 9: Memory and Resource Management 49
Exercise 1
Programming for Explicit Resource Management
In this exercise, you will modify the Memory and Resource Management
application to incorporate explicit resource management.
hello world
are you out there?
Note The SentenceFormatter should send its text buffer to its contained
SimpleTextBuffer object named aSimpleTextBuffer before it calls that
SimpleTextBuffer object’s Close method.
b. Free the object’s internal state and set disposed to indicate that the
object has been disposed.
Multiple calls to protected virtual void Dispose should not throw an
exception.
4. For both classes, add a public void Dispose method that takes no
arguments. This method calls the protected virtual void Dispose method
created in step 3 with true as its argument followed by a call to the GC
class’s method to suppress finalization.
5. For both classes, modify the Close method to call the public void Dispose
method.
6. For the SentenceFormatter and SimpleTextBuffer methods, which require
resources that are freed by their classes’ protected virtual void Dispose
method, add an initial check that throws an ObjectDisposedException if
those resources have been released.
52 Module 9: Memory and Resource Management
Exercise 2
Programming for Implicit Resource Management
In this exercise, you will modify the Memory and Resource Management
application to incorporate implicit resource management.
3. Enter the following text, and then enter an empty line, as prompted:
hello world.are you out there?
hello world
are you out there?
Note With explicit resource management, the output is identical to the output
in Exercise 1. All the characters you entered are output and counted.
54 Module 9: Memory and Resource Management
2. In the preceding step there is a statement after the code 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
hello world
SimpleTextBuffer destructor called
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.
Module 9: Memory and Resource Management 55
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Memory Management Basics
Lead-in ! Non-Memory Resource Management
The review questions cover
some of the key concepts ! Implicit Resource Management
taught in the module.
! Explicit Resource Management
! Optimizing Garbage Collection
Contents
Overview 1
Streams 2
Readers and Writers 5
Basic File I/O 8
Lab 10: Files 21
Review 26
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 10: Data Streams and Files iii
Instructor Notes
Presentation: After completing this module, students will be able to:
45 Minutes
! Use Stream objects to read and write bytes to backing stores, such as
Lab: strings and files.
45 Minutes
! 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 Framework isolated storage
mechanism.
Required Materials
To teach this module, you need the Microsoft PowerPoint® file 2349B_10.ppt.
Preparation Tasks
To prepare for this module, you should:
! Read all of the materials for this module.
! Complete the lab.
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 2349B, Programming with the
Microsoft .NET Framework (Microsoft Visual C#™.NET).
! 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 I/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.
Module 10: Data Streams and Files 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Streams
Lead-in ! Readers and Writers
In this module, you will learn
about how to use types that ! Basic File I/O
allow reading from and
writing to data streams and
files.
Streams
Topic Objective
To introduce the functions of ! A Way to Read and Write Bytes from and to a Backing Store
the Stream class and its
subclasses. " Stream classes inherit from System.IO.Stream
! Fundamental Stream Operations: Read, Write, and Seek
Lead-in
Streams provide a way to " CanRead, CanWrite, and CanSeek properties
read and write bytes from ! Some Streams Support Buffering for Performance
and to a backing store. A " Flush method outputs and clears internal buffers
backing store is a storage
medium, such as a disk or ! Close Method Frees Resources
memory. " Close method performs an implicit Flush for buffered streams
! Stream Classes Provided by the .NET Framework
" NetworkStream, BufferedStream, MemoryStream, FileStream,
CryptoStream
! Null Stream Instance Has No Backing Store
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.
4 Module 10: Data Streams and Files
CryptoStream Class
The CryptoStream class defines a stream that links data streams to
cryptographic transformations. The common language runtime uses a stream-
oriented design for cryptography. The core of this design is CryptoStream.
Any cryptographic objects that implement CryptoStream can be chained
together with any objects that implement Stream, so the streamed output from
one object can be fed into the input of another object. The intermediate result
(the output from the first object) does not need to be stored separately. For
further details about the CryptoStream class see the .NET Framework SDK.
BinaryReader and BinaryWriter These classes read and write primitive types as
binary values in a specific encoding to and from
a stream.
TextReader and TextWriter The implementations of these classes are
designed for character input and output.
StreamReader and StreamWriter These classes are derived from the TextReader
and TextWriter classes, and read and write their
characters to a stream.
StringReader and StringWriter 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.
A reader or writer is attached to a stream so that the desired types can be read or
written easily.
6 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 file’s 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();
}
}
}
Module 10: Data Streams and Files 7
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;
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.
8 Module 10: Data Streams and Files
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.
FileStream Class
Topic Objective
To define the FileStream
class and the types that are ! The FileStream Class Is Used for Reading from and Writing to Files
used as parameters in some ! FileStream Constructor Parameter Classes
FileStream constructors.
" FileMode – Open, Append, Create
Lead-in
" FileAccess – Read, ReadWrite, Write
The FileStream class is
used for reading from and " FileShare – None, Read, ReadWrite, Write
writing to files. The FileStream
FileMode, FileAccess, and FileStream ff == new
new FileStream(name,
FileStream(name, FileMode.Open,
FileMode.Open,
FileAccess.Read,
FileAccess.Read, FileShare.Read);
FileShare.Read);
FileShare types are used as
parameters in some ! Random Access to Files by Using the Seek Method
FileStream constructors.
" Specified by byte offset
" Offset is relative to seek reference point: Begin, Current, End
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 Description
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.
10 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);
FileStream
FileStream aStream
aStream == File.Create("foo.txt");
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");
12 Module 10: Data Streams and Files
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.
Module 10: Data Streams and Files 13
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);
}
}
}
Module 10: Data Streams and Files 15
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:\\"
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.
16 Module 10: Data Streams and Files
FileSystemWatcher
Topic Objective ! FileSystemWatcher Is Used to Monitor a File System
To explain how the ! Creating a FileSystemWatcher Object
FileSystemWatcher
component can be used to FileSystemWatcher
FileSystemWatcher watcher
watcher == new
new FileSystemWatcher();
FileSystemWatcher();
monitor and react to ! Configure
changes in a file system.
watcher.Path
watcher.Path == args[0];
args[0];
Lead-in watcher.Filter
watcher.Filter == "*.txt";
"*.txt";
You use the watcher.NotifyFilter
watcher.NotifyFilter == NotifyFilters.FileName;
NotifyFilters.FileName;
FileSystemWatcher watcher.Renamed
watcher.Renamed +=+= new
new
component to monitor a file RenamedEventHandler(OnRenamed);
RenamedEventHandler(OnRenamed);
system and react when ! Begin Watching
changes to it occur.
watcher.EnableRaisingEvents
watcher.EnableRaisingEvents == true;
true;
! Catch Events
public
public static
static void
void OnRenamed(object
OnRenamed(object s,
s, RenamedEventArgs
RenamedEventArgs e)
e) {{
Console.WriteLine("File:
Console.WriteLine("File: {0}{0} renamed
renamed to
to {1}",
{1}",
e.OldFullPath,
e.OldFullPath, e.FullPath);
e.FullPath); }}
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 Development 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 provided.
Module 10: Data Streams and Files 17
watcher.Renamed += new
RenamedEventHandler(OnRenamed);
// Begin watching.
watcher.EnableRaisingEvents = true;
Isolated Storage
Topic Objective
To introduce isolated
storage and its potential
uses. ! Isolated Storage Provides Standardized Ways of
Associating Applications with Saved Data
Lead-in
For some applications, such ! Semi-Trusted Web Applications Require:
as downloaded Web
applications and code that " Isolation of their data from other applications' data
may come from untrusted
sources, the basic file " Safe access to a computer’s file system
system does not provide the
necessary isolation and ! System.IO.IsolatedStorage Namespace Contains:
safety.
public
public sealed
sealed class
class IsolatedStorageFile
IsolatedStorageFile :: IsolatedStorage,
IsolatedStorage, IDisposable
IDisposable
public
public class
class IsolatedStorageFileStream
IsolatedStorageFileStream :: FileStream
FileStream
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 application
files to minimize storage conflicts.
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 file’s 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.
Exercise 1
Reading and Writing Files and Strings
In this exercise, you will modify the Files application to output to a specified
file.
5. View the WordCount.cs file, and locate the last line in Application’s Main
method, which is:
return 0;
6. Right-click this line, and select Run To Cursor. You should see the
following output:
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.
Module 10: Data Streams and Files 23
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)
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 line’s 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.
24 Module 10: Data Streams and Files
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
Module 10: Data Streams and Files 25
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.
26 Module 10: Data Streams and Files
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Streams
Lead-in ! Readers and Writers
The review questions cover
some of the key concepts ! Basic File I/O
taught in the module.
3. Name the classes that are used to read and write primitive types as binary
values.
BinaryReader and BinaryWriter.
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 Framework’s isolated
storage provides for an application.
Isolation and Safety.
THIS PAGE INTENTIONALLY LEFT BLANK
Module 11:
Internet Access
Contents
Overview 1
Internet Application Scenarios 2
The WebRequest and WebResponse Model 3
Application Protocols 16
Handling Errors 25
Security 28
Best Practices 35
Lab 11: Creating a DateTime Client/Server
Application 36
Review 41
Course Evaluation 43
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 11: Internet Access iii
Instructor Notes
Presentation: After completing this module, students will be able to:
60 Minutes
! Use the basic request/response model to send and receive data over the
Lab: Internet.
45 Minutes
! 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.
Required Materials
To teach this module, you need the Microsoft® PowerPoint® file 2349B_11.ppt.
Preparation Tasks
To prepare for this module, you should:
! Read all of the materials for this module.
! Complete the lab.
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 Microsoft
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 Framework 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.
Module 11: Internet Access 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Internet Application Scenarios
Lead-in ! The WebRequest and WebResponse Model
In this module, you will learn
about the basic ! Application Protocols
request/response model that
is used to send and receive ! Handling Errors
data over the Internet, the
! Security
System.Net classes that
are used to communicate ! Best Practices
with other applications, and
various techniques to
enhance application security
and performance.
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.
Module 11: Internet Access 5
NetworkStream Class
Topic Objective ! A NetworkStream Object Provides:
To explain the function of
Network streams in the " A Way to Send and Receive All Types of Web Data
.NET Framework. " Methods That Are Compatible with Other .NET Streams
Lead-in " Processing of Data As It Arrives
When resources on the
Internet are obtained by ! System.Text.Encoding – Characters from and to Bytes
using the System.Net
//
// reading
reading ASCII
ASCII stream
stream to
to string
string
classes, the data that is
Byte[] read = new Byte[32];
Byte[] read = new Byte[32];
being sent and received is
int
int bytes
bytes == anASCIIStream1.Read(read,
anASCIIStream1.Read(read, 0, 0, read.Length);
read.Length);
represented through a string
Stream object. string stringData
stringData == Encoding.ASCII.GetString(read);
Encoding.ASCII.GetString(read);
//
// writing
writing string
string to
to ASCII
ASCII stream
stream
Byte[]
Byte[] asciiBytes
asciiBytes == Encoding.ASCII.GetBytes(stringData);
Encoding.ASCII.GetBytes(stringData);
anASCIIStream2.Write(asciiBytes,
anASCIIStream2.Write(asciiBytes, 0, 0, asciiBytes.Length);
asciiBytes.Length);
Creating a WebRequest
Topic Objective ! The WebRequest Encapsulates Details of Request
To describe how client
applications use the " Created by calling WebRequest.Create method
WebRequest.
WebRequest
WebRequest req
req ==
Lead-in WebRequest.Create("http://www.contoso.com/");
Client applications request WebRequest.Create("http://www.contoso.com/");
data from servers by using
the WebRequest class and " Set any property values that are required
its descendents. req.Credentials
req.Credentials == new
new
NetworkCredential("username","password");
NetworkCredential("username","password");
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/");
Invoking a WebRequest
Topic Objective
To explain how to invoke the
request for an Internet
resource by calling the ! Request Is Made by Calling the GetResponse Method
GetResponse method on
the WebRequest instance. WebResponse
WebResponse resp
resp == req.GetResponse();
req.GetResponse();
Lead-in
After creating the
WebRequest, you invoke " Cast to access HTTP-specific features
the request for the Internet
resource by calling the HttpWebResponse
HttpWebResponse httpResp
httpResp ==
GetResponse method on (HttpWebResponse)httpReq.GetResponse();
(HttpWebResponse)httpReq.GetResponse();
the WebRequest instance.
//Get
//Get the
the HTTP
HTTP content
content length
length returned
returned by
by the
the server.
server.
String contentLength
String contentLength = =
httpResp.ContentLength.ToString();
httpResp.ContentLength.ToString();
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();
Sending Data
Topic Objective ! For Requests That Send Data to the Server
To describe how requests
that send data to the server //
are created. // ...
...
try
try
Lead-in {{
For requests that send data byte[]
byte[] sendData
sendData ==
Encoding.ASCII.GetBytes("some
Encoding.ASCII.GetBytes("some data");
data");
to the server, such as
int
int sendLength
sendLength == sendData.Length;
sendData.Length;
HTTP-POST or FTP-PUT
HttpWebRequest
HttpWebRequest httpReq
httpReq ==
requests, the data is sent (HttpWebRequest)
through a network stream (HttpWebRequest) WebRequest.Create(
WebRequest.Create(
"http://www.contoso.com/");
"http://www.contoso.com/");
that is provided by the httpReq.Method
httpReq.Method == "POST";
"POST";
WebRequest.GetRequest httpReq.ContentLength
httpReq.ContentLength == sendLength;
sendLength;
Stream method. Stream
Stream sendStream
sendStream == httpReq.GetRequestStream();
httpReq.GetRequestStream();
sendStream.Write(sendData,0,sendLength);
sendStream.Write(sendData,0,sendLength);
sendStream.Close();
sendStream.Close();
}}
catch(Exception
catch(Exception e)
e) {//...}
{//...} //...
//...
After closing the stream, you can call GetResponse to ensure that the server
received the data correctly.
12 Module 11: Internet Access
Receiving Data
Topic Objective
To explain how to obtain the
! Reading Response Data
stream that contains
response data from the
network. //
// Get
Get the
the response
response stream.
stream.
Stream
Stream respstrm == resp.GetResponseStream();
respstrm resp.GetResponseStream();
Lead-in //
// Create
Create aa buffer
buffer to to hold
hold the
the response
response data.
data.
To obtain the stream that int BufferSize = 512;
int BufferSize = 512;
contains response data from Byte[]
the network resource, use Byte[] Buffer
Buffer == new
new Byte[BufferSize];
Byte[BufferSize];
//
// Read
Read the
the stream
stream to to access
access the
the data.
data.
the GetResponseStream int
method of the int bytesRead
bytesRead == respstrm.Read(Buffer,
respstrm.Read(Buffer, 0, 0, BufferSize);
BufferSize);
while (bytesRead >
while (bytesRead > 0) { 0) {
WebResponse instance.
Console.Write(
Console.Write(
Encoding.ASCII.GetString(Buffer,
Encoding.ASCII.GetString(Buffer, 0, 0, bytesRead));
bytesRead));
bytesRead
bytesRead = respstrm.Read(Buffer, 0, BufferSize);
= respstrm.Read(Buffer, 0, BufferSize);
}}
respstrm.Close();
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();
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.
class App
{
public static void Main(string[] args)
{
try
{
WebRequest wReq = WebRequest.Create
("http://localhost/postinfo.html");
WebResponse wResp = wReq.GetResponse();
catch(Exception e)
{
Console.WriteLine(
"\r\nThe request URI could not be found or was!
malformed:\n {0}",
e.ToString());
}
}
}
16 Module 11: Internet Access
# Application Protocols
Topic Objective
To introduce the topics in
the section.
! HTTP
Lead-in
The .NET Framework ! Internet Domain Name System
supports application
protocols that are currently ! TCP and UDP
in common use on the
Internet. ! Sockets
HTTP
Topic Objective
To describe the support that
the .NET Framework
provides for the HTTP ! Classes That Provide HTTP and HTTPS Protocols
protocol.
" HttpWebRequest and HttpWebResponse
Lead-in
With the HttpWebRequest ! Support Most HTTP 1.1 features
and HttpWebResponse
classes, the .NET ! HTTP Redirects Automatically if AllowAutoRedirect
Framework provides Property Is true (the Default)
comprehensive support for
the HTTP protocol, which ! Use ServicePoint, ServicePointManager, and
makes up the majority of all ConnectionGroupName Classes to Manage Connections
Internet traffic.
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
dotted-quad 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");
20 Module 11: Internet Access
Sockets
Topic Objective
To describe the Socket
class and provide an
example of how the Socket ! System.Net Classes Are Built on System.Net.Sockets
class can be used to send
! System.Net.Sockets Are Based on the WinSock32 API
data to an HTTP server and
to receive the response. ! See Example in Student Notes
Lead-in
The System.Net.Sockets
namespace contains an
implementation of the
Windows Sockets
interface.
The following example shows how the Socket class can be used to send data to
an HTTP server and receive the response:
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using 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 = "";
Handling Errors
Topic Objective ! A WebException Can Be Thrown by GetResponse
To explain how the Status
property is used to " Has Status property, value from WebExceptionStatus
determine if an error has " If WebExceptionStatus.ProtocolError, then WebResponse
occurred. contains protocol error information
Lead-in try
try
The WebRequest and {{ // // ...
... Create
Create aa request,
request, get
get response
response and
and process
process stream.
stream. }}
WebResponse classes catch
catch (WebException
(WebException webExcp)
webExcp)
{{
throw system exceptions Console.WriteLine("A
Console.WriteLine("A WebException
WebException has
has been
been caught");
caught");
and Web-specific Console.WriteLine(webExcp.ToString());
Console.WriteLine(webExcp.ToString());
exceptions, which are WebExceptionStatus
WebExceptionStatus status
status == webExcp.Status;
webExcp.Status;
instances of WebException if
if (status
(status ==
== WebExceptionStatus.ProtocolError)
WebExceptionStatus.ProtocolError) {{
and thrown by the Console.Write(
Console.Write(
"The
"The server
server returned
returned protocol
protocol error
error ");
");
GetResponse method. Console.WriteLine(webExcp.Response.ToString());
Console.WriteLine(webExcp.Response.ToString());
}}
}}
catch
catch (Exception
(Exception e)e)
{//
{// Code
Code to
to catch
catch other
other exceptions
exceptions goes
goes here.}
here.}
*****************************ILLEGAL FOR NON-TRAINER USE******************************
The WebRequest and WebResponse classes throw system exceptions, such as
InvalidArgumentException, and Web-specific exceptions, which are instances
of WebException and are 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 Description
(continued)
Value Description
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_bad_URL");
}
}
# Security
Topic Objective
To introduce the topics in
the section.
! Web Proxy
Lead-in
Your application can provide ! Secure Sockets Layer
security for sending and
receiving data over the ! Internet Authentication
Internet by using a Web
proxy, SSL encryption, ! Permissions
Internet authentication, and
the NET Framework’s code
access permissions.
Web Proxy
Topic Objective
To show how to use a Web ! Global Proxy for All Web Requests
proxy to communicate with
the Internet.
" Proxy named webproxy using port 80
Lead-in
WebProxy
WebProxy proxyObject
proxyObject == new
new WebProxy(
WebProxy(
If your Web site uses a
proxy to provide access to "http://webproxy:80/");
"http://webproxy:80/");
the Internet, you must GlobalProxySelection.Select
GlobalProxySelection.Select == proxyObject;
proxyObject;
configure a proxy instance
to enable your application to
! Overriding the Global Proxy Setting
communicate with the Web
proxy. " Request uses proxy named alternateproxy and port 80
WebRequest
WebRequest req
req == WebRequest.Create(
WebRequest.Create(
"http://www.contoso.com/");
"http://www.contoso.com/");
req.Proxy
req.Proxy == new
new WebProxy(
WebProxy(
"http://alternateproxy:80/");
"http://alternateproxy:80/");
*****************************ILLEGAL FOR NON-TRAINER USE******************************
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.
Internet Authentication
Topic Objective
To introduce the client
authentication mechanisms ! .NET Supports Various Kinds of Authentication
that are supported by the
System.Net classes. " Basic, digest, negotiate, NTLM, and Kerberos
authentication
Lead-in
The System.Net classes " Users can also create their own authentication
support a variety of client
authentication mechanisms,
! Credentials Stored in Classes
including the standard " NetworkCredential – for a single Internet resource
Internet authentication
methods: basic, digest, " CredentialCache – for multiple Internet resources
negotiate, NTLM, and
Kerberos authentication, ! Authentication Managed by the AuthenticationManager
and custom methods that
you can create.
! Some Schemes Allow Pre-Authentication to Save Time
Caution String literals in an application are stored and transported as clear text.
Therefore, you should avoid putting sensitive information such as passwords in
string literals.
Passport Authentication
Passport authentication is a centralized authentication service provided by
Microsoft that offers a single logon and core profile services for member sites.
This benefits the user because it is no longer necessary to log on to access new
protected resources or sites. If you want your site to be compatible with
Passport authentication and authorization, this is the provider you should use.
For more information, see the Passport documentation located at
http://www.passport.com/business.
34 Module 11: Internet Access
Permissions
Topic Objective
To explain which permission ! WebPermissions
classes best suit which
application types. " Controls an application's right to request data from a URI or to serve
a URI to the Internet
Lead-in ! SocketPermissions
The WebPermissions and
" Controls an application's right to accept data on a local port or to
SocketPermissions contact applications
classes provide Internet
security for applications that ! Choose Permission Class Based on Application Use
use System.Net. " WebRequest and its descendents use WebPermissions
" Socket-level access uses SocketPermissions
! Both Classes Support Two Kinds of Permissions
" Accept – application can answer an incoming connection
" Connect – application can initiate a connection
Best Practices
Topic Objective
To introduce best practices
! When Possible, Use WebRequest and WebResponse,
that will help students use
the System.Net classes Instead of Protocol-Specific Subclasses
more effectively. ! For Better Performance, Use Asynchronous Methods
Lead-in
The following ! Tune Performance by Adjusting the Number
recommendations will help of Connections
you use the classes that are
contained in System.Net " ConnectionLimit property in the ServicePoint instance
more effectively.
! When Possible, Use TcpClient or UdpClient, Instead of
Writing Directly to a Socket
! Use the CredentialCache Class If Credentials
Are Required
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 stream’s ASCII data into a string that is
then output to the console.
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.
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.
Tip You can display your computer’s current TCP/IP network connections
by running the program netstat in a command prompt window. The
following example shows that port 7 is in use by a process with PID 1504:
C:\>netstat -o -n -a
Active Connections
5. Run the client application as directed in step 3 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
Visual Studio .NET Command Prompt window:
datetimeclient foo
40 Module 11: Internet Access
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 3 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
Note that the client application outputs the number of bytes received and the
current date and time string retrieved from the server.
Module 11: Internet Access 41
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Internet Application Scenarios
Lead-in ! The WebRequest and WebResponse Model
The review questions cover
some of the key concepts ! Application Protocols
taught in the module.
! Handling Errors
! Security
! Best Practices
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();
42 Module 11: Internet Access
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
Module 11: Internet Access 43
Course Evaluation
Topic Objective
To direct students to a Web
site to complete a course
evaluation.
Lead-in
Between now and the end of
the course, you can go to
the Web site listed on this
page to complete a course
evaluation.
Contents
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
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 12: Serialization iii
Instructor Notes
Presentation: After completing this module, students will be able to:
30 Minutes
• Write an application that serializes and deserializes an object graph by using
Lab: either a binary or Simple Object Access Protocol (SOAP) XML format.
45 Minutes
Required Materials
To teach this module, you need the Microsoft® PowerPoint® file 2349B_12.ppt.
Preparation Tasks
To prepare for this module, you should:
! Read all of the materials for this module.
! Complete the lab.
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 in-
memory objects to disk and in remoting. Mention the Microsoft .NET
Framework’s 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.
Module 12: Serialization 1
Overview
Topic Objective
To provide an overview of ! Serialization Scenarios
the module topics and
objectives.
! Serialization Attributes
Lead-in ! Object Graph
In this module, you will learn
about serialization and learn ! Serialization Process
how to write an application
that serializes and ! Serialization Example
deserializes an object graph ! Deserialization Example
by using a binary or SOAP
XML format. ! Custom Serialization
! Custom Serialization Example
! Security Issues
Serialization Scenarios
Topic Objective
To show how serialization is
used.
! Persistence
Lead-in
Serialization is used in some " Store and retrieve a graph of objects to and from a file
very common scenarios,
such as persisting a graph ! Remoting
of objects to disk or to
objects in another process. " Pass by value arguments that are transmitted between
processes
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.
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 2349B, Programming with the Microsoft .NET Framework
(Microsoft Visual C# .NET).
4 Module 12: Serialization
Serialization Attributes
Topic Objective
To explain how to mark a
class with serialization ! To Mark a Class, Use Serializable Attribute
attributes in C#.
Lead-in [Serializable]
[Serializable] public
public class
class MyClass
MyClass {}
{}
If you are writing a class,
you should be aware of
serialization. ! To Skip Specified Members, Use NonSerialized Attribute
[Serializable]
[Serializable] public
public class
class MyClass
MyClass {{
[NonSerialized]
[NonSerialized] int
int _cashSize;
_cashSize;
//...
//...
}}
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.
Module 12: Serialization 5
Object Graph
Topic Objective
To define an object graph 33 Dog
and explain its function.
Lead-in
An object graph is a set of
objects that share a set of 44 Cat 77 Duck 11 Mouse
references to each other.
99 Horse 22 Duck
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.
6 Module 12: Serialization
Serialization Process
Topic Objective ! Classes Used by the Default Serialization Process
To introduce the classes
that are used in the " ObjectIDGenerator – generates IDs for objects
serialization process.
Lead-in " ObjectManager – tracks objects as they are being
The process of serializing deserialized
an object graph involves
identifying the individual ! Examples of Classes Used with Serialized Streams
objects in the graph and the
" FileStream, MemoryStream, NetworkStream
relationships between them.
! Formatter Class
" Writes or reads data in a specified format to the output
or input streams
" Runtime provides BinaryFormatter and SoapFormatter
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.
Because formatters are pluggable, you can also build your own formatters.
Module 12: Serialization 9
Serialization Example
Topic Objective class
class SerializeExample{
SerializeExample{
To provide an example of
serialization of an object public
public static
static void
void Main(String[]
Main(String[] args)
args) {{
graph. //
// create
create the
the object
object graph
graph
ArrayList
ArrayList ll == new
new ArrayList();
ArrayList();
Lead-in
This code sample shows for
for (int x=0; x< 100;
(int x=0; x< 100; x++)
x++) {{
how to perform default l.Add (x);
l.Add (x);
serialization of a graph of }}
objects, whose root is an //
// create
create the
the filestream
filestream
ArrayList. FileStream
FileStream ss == File.Create("foo.bin");
File.Create("foo.bin");
//
// create
create the
the BinaryFormatter
BinaryFormatter
BinaryFormatter
BinaryFormatter bb == new
new BinaryFormatter();
BinaryFormatter();
//
// serialize the graph to
serialize the graph to the
the stream
stream
b.Serialize(s, l);
b.Serialize(s, l);
s.Close();
s.Close();
}}
}}
class SerializeExample
{
Deserialization Example
Topic Objective
To show how to create a class
class DeSerialize
DeSerialize
clone of the graph by {{
deserializing it. public
public static
static void
void Main(String[]
Main(String[] args)
args)
{{
Lead-in //
The preceding Serialization // open
open the
the filestream
filestream
FileStream
FileStream ss == File.OpenRead("foo.bin");
File.OpenRead("foo.bin");
Example shows how to
perform default serialization //
of a graph of objects, whose // create
create the
the formatter
formatter
BinaryFormatter
BinaryFormatter bb == new
new BinaryFormatter();
BinaryFormatter();
root is an ArrayList, with a
//
// deserialize
deserialize
serialized stream that is
ArrayList
ArrayList pp == (ArrayList)
(ArrayList) b.Deserialize(s);
b.Deserialize(s);
written to a FileStream in
binary format. s.Close();
s.Close();
//
// print
print out
out the
the new
new object
object graph
graph
//
// see module text for PrintValues’
see module text for PrintValues’ code
code
PrintValues(p);
PrintValues(p);
}}
class DeSerialize
{
}
12 Module 12: Serialization
Custom Serialization
Topic Objective ! Customize Serialization by Implementing ISerializable:
To explain what is required
to implement ISerializable " When some of the data is not valid after deserialization
for performing custom
serialization. " When some of the data must be obtained by calculation
Lead-in ! ISerializable Requires:
This module has so far
discussed the default " GetObjectData method, called during serialization,
serialization process. which returns a PropertyBag of type SerializationInfo
However, you may also
want to customize the way " PropertyBag, which contains the type of the object
data from a given object is being serialized and the name/object pairs for the values
serialized. being serialized
" A constructor, called during deserialization, which uses
SerializationInfo to reconstitute the state of the object
Deserialization
Deserialization occurs during the call to the class’s constructor. If you need to
create custom deserialization of an object, you use the object’s
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 class’s 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.
14 Module 12: Serialization
[Serializable]
public class ExampleFoo : ISerializable
{
public int i, j, k;
public ExampleFoo()
{
}
Type t = this.GetType();
si.AddValue("TypeObj", t);
}
}
Outputs:
ToFile
i: 1
j: 20
k: 50
FromFile
i: 1
j: 20
k: 50
Module 12: Serialization 17
Security Issues
Topic Objective
To alert students to the
need for security when
serializing objects. ! Serialization Handles an Object’s Private Data
Lead-in " If private data is sensitive, consider encrypting the
The serialization engine stream before transmitting or saving to a disk
handles both the public and
private state of the objects " System.Security.Cryptography namespace contains
that are passed to it. classes to perform cryptography
The CryptoStream class can be used to encrypt
streams of serialized data
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 runtime’s 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 Framework’s 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.
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.
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:
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
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
file’s 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 application’s 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
data’s format, structure, and size.
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.
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 array’s 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:
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
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
Entering Scope 6
Deserializing Array from file ..
Node 0 Value: 0 Value of NextNode Ref: 1
8. Using Visual Studio .NET, open and visually examine the Array.soap file in
the bin\Debug subdirectory, and note the serialized array data’s format,
structure, and size.
Module 12: Serialization 27
Review
Topic Objective
To reinforce module ! Serialization Scenarios
objectives by reviewing
key points. ! Serialization Attributes
Lead-in ! Object Graph
The review questions cover
some of the key concepts ! Serialization Process
taught in the module.
! Serialization Example
! Deserialization Example
! Custom Serialization
! Custom Serialization Example
! Security Issues
2. Name and describe the two kinds of formatters that the .NET Framework
provides.
BinaryFormatter for a compact binary
SoapFormatter for XML representation
4. What kind of data that is not normally accessible by clients can be made
visible by serialization?
Private object state
THIS PAGE INTENTIONALLY LEFT BLANK
Module 13: Remoting
and XML Web Services
Contents
Overview 1
Remoting 2
Remoting Configuration Files 19
Demonstration: Remoting 22
Lab 13.1: Building an Order-Processing
Application by Using Remoted Servers 28
XML Web Services 36
Lab 13.2: Using an XML Web Service 48
Review 54
Course Evaluation 56
Information in this document, including URL and other Internet Web site references, is subject to
change without notice. Unless otherwise noted, the example companies, organizations, products,
domain names, e-mail addresses, logos, people, places and events depicted herein are fictitious,
and no association with any real company, organization, product, domain name, e-mail address,
logo, person, place or event is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 13: Remoting and XML Web Services iii
Instructor Notes
Presentation: After completing this module, students will be able to:
120 Minutes
! Write and configure distributed applications that use .NET Remoting.
Lab: ! Create an XML Web service by using Microsoft® Visual Studio® .NET and
105 Minutes
ASP.NET.
! Consume an XML Web service by using the Web Services Description
Language tool (Wsdl.exe).
Required Materials
To teach this module, you need the Microsoft PowerPoint® file 2349B_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.
iv Module 13: Remoting and XML 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.
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 .NET Framework supports server-side and client-side activation of
remote objects and describe the differences between server-side and client-
side 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 Developer’s Guide (SDK) documentation.
Because the module is long, conclude this part of the lecture and instruct
students to do Lab 13.1.
! XML Web Services
Explain how to use Visual Studio .NET to implement an ASP.NET XML
Web service and how to access the XML Web service from a Web browser
and a client application. Use the Using Visual Studio .NET to Create an
XML Web Service demonstration to illustrate the concepts that are covered
in this section.
Introduce the XML Web service discovery process and the tools that are
available for discovery.
Module 13: Remoting and XML Web Services 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Remoting
Lead-in ! Remoting Configuration Files
In this module, you will learn
about distributed ! XML Web Services
applications that use .NET
Remoting.
" Remoting
Topic Objective
To provide an overview of
the topics covered in this ! Remoting Overview
section.
! Channels and Formatters
Lead-in
This section shows how ! Activation and Proxies
.NET Remoting supports
communication in various ! Lease-Based Lifetime
scenarios.
! Object Marshaling
! Server Side
! Client Side
! Client Compilation Techniques
Remoting Overview
Topic Objective
To provide an overview of
.NET Remoting.
Lead-in
The .NET Framework Client AppDomain Server AppDomain
provides several services
that are used in remoting. Client Formatter Formatter
Object
Server
Object
Server Channel Channel
Proxy
Remoting Boundary
Note Because the .NET context mechanism is beyond the scope of this course,
this module does not cover remoting calls between contexts.
4 Module 13: Remoting and XML Web Services
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 infrastructure 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 not valid 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.
Module 13: Remoting and XML Web Services 5
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.
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
Uniform Resource Identifier by using the HTTP protocol. You can create
industry-standard XML 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 Uniform Resource
Identifier 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 XML Web services.
6 Module 13: Remoting and XML 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);
//...
Security Issues
If you have a choice between using the HttpChannel and the TcpChannel, it is
recommended that you use the HttpChannel and host your remote objects in
Internet Information Services (IIS), no matter what the user authentication and
authorization models are. IIS hosting provides support for wire-level protection
using Secure Sockets Layer (SSL) and authentication using Integrated
Windows Authentication (formerly NTLM authentication) or Kerberos. For
configuring SSL and authentication, see the IIS documentation.
The TcpChannel, as an implementation of the Transmission Control Protocol
(TCP), does not have default support for some of the robust authentication
standards that the HTTP standard does. Within a secured environment (one that
has wire-level protection such as IPSec), the high-speed TcpChannel can be
used, but it is not recommended over the Internet or a nonsecure intranet.
You can use cryptography to protect data from being viewed or modified and
thereby provide secure channels of communication over otherwise insecure
channels. The System.Security.Cryptography namespace contains a set of
classes that allow you to perform both symmetric and asymmetric
cryptography, create hashes, and provide random number generation.
Successful cryptography is the result of combining these tasks. See the .NET
SDK for documentation about the System.Security.Cryptography namespace.
Module 13: Remoting and XML Web Services 7
Server-Side Activation
Server-side activation supports single call and singleton modes of activation.
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.
Module 13: Remoting and XML Web Services 9
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.
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.
10 Module 13: Remoting and XML Web Services
Lease-Based Lifetime
Topic Objective
To explain how using a
leasing mechanism can
extend the lifetime of client- ! A Leasing Mechanism Controls the Lifetime of a Client-
activated remote objects. Activated Remote Object
Lead-in ! An Object’s Lease Time Can Be Extended
You can control the lifetime
of client-activated remote ! When an Object’s Lease Time Reaches Zero
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
Object Marshaling
Topic Objective
To explain how objects are
marshaled in .NET ! Objects Instantiated Remotely Are Returned by Reference and
Remoting. Accessed by the Client Through a Proxy
Lead-in ! Remote Call Parameters, Return Values, and Fields Can Be:
Because calls to a remote # Marshal-by-value objects – A copy of the object is passed from one
object can cause other AppDomain to another
objects to be passed across
- Value types and classes that are serializable
a remoting boundary, you
should understand how # Marshal-by-reference objects – A reference to the object is passed
objects are marshaled in from one AppDomain to another
.NET Remoting. - 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
! 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.
12 Module 13: Remoting and XML Web Services
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
{
//. . .
}
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 object’s class must derive from the
System.MarshalByRefObject class.
Use marshal-by-reference objects when an object’s 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
operating system handle, application domain-bound. In this case, the operating
system handle would not be useful or appropriate in another application
domain, process, or computer.
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.
Module 13: Remoting and XML Web Services 13
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
{
//. . .
}
14 Module 13: Remoting and XML Web Services
Server Side
Topic Objective
To explain how to register
and activate a remote object ! Register the Channel
from the server side.
! Register Remote Objects by Using:
Lead-in
Remote objects must be # The RegisterWellKnownServiceType call
registered with the remoting
framework before clients RemotingConfiguration.RegisterWellKnownServiceType(
RemotingConfiguration.RegisterWellKnownServiceType(
can access them. typeof(HelloServer),
typeof(HelloServer),
"SayHello",
"SayHello",
WellKnownObjectMode.SingleCall);
WellKnownObjectMode.SingleCall);
# Or a configuration file
RemotingConfiguration.Configure("MyHello.exe.config");
RemotingConfiguration.Configure("MyHello.exe.config");
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 Uniform Resource Identifier 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.
Module 13: Remoting and XML Web Services 15
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(HelloServer),
"SayHello",
WellKnownObjectMode.SingleCall);
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");
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.
16 Module 13: Remoting and XML Web Services
Client Side
Topic Objective
To explain how to register
! Register the Channel
and activate a remote object
from the client side. ChannelServices.RegisterChannel(new
ChannelServices.RegisterChannel(new TcpChannel());
TcpChannel());
Lead-in
On the client side, a client ! Activate Remote Object by Using:
registers the channel and
activates the remote object. # Activator.GetObject
HelloServer
HelloServer obj
obj == (HelloServer)Activator.GetObject(
(HelloServer)Activator.GetObject(
typeof(RemotingSamples.HelloServer),
typeof(RemotingSamples.HelloServer),
"tcp://localhost:8085/SayHello");
"tcp://localhost:8085/SayHello");
Important You do not specify a port number when you register the client
channel.
The only difference between GetObject and new is that GetObject allows you
to specify a Uniform Resource Identifier as a parameter, while new obtains the
Uniform Resource Identifier 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");
After the configuration file has been loaded, the client can activate the object as
follows:
HelloServer obj = new HelloServer();
18 Module 13: Remoting and XML Web Services
Note The Web Service Utility extracts only metadata and does not generate the
source for the remote object.
Module 13: Remoting and XML 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 Configure call on RemotingConfiguration only reads the relevant
sections in the configuration file that apply to remoting, while the rest of the
information is ignored.
Module 13: Remoting and XML Web Services 21
<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>
<!--Specifies a remote object this client used -->
<!--One or more clients can be specified -->
</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>
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.
Delivery Tip Important Before running the application, ensure that all currently running
Although this demonstration server applications that may be using the same port number have been closed.
includes detailed Running more than one server that uses the same port number will generate an
instructions, this is not a error.
guided practice. Present the
demonstration and suggest
that the students try the
demonstration for Tip You can display your machine’s current TCP/IP network connections by
themselves later. running the program netstat in a command prompt window. The following
example shows that port 7 is in use by a process with PID 1504:
C:\>netstat -o -n -a
Active Connections
Server-Side
The following sample code is the server source code, which is named Server.cs:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
namespace RemotingSamples
{
ChannelServices.RegisterChannel(chan1);
ChannelServices.RegisterChannel(chan2);
/*
RemotingConfiguration.RegisterWellKnownServiceType
(
typeof(HelloServer),
"SayHello",
WellKnownObjectMode.Singleton
);
*/
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(HelloServer),
"SayHello",
WellKnownObjectMode.SingleCall
);
public HelloServer()
{
Console.WriteLine("HelloServer activated");
}
Client-Side
The following sample code is the client source code, which is named Client.cs:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Runtime.Remoting.Channels.Http;
using System.IO;
namespace RemotingSamples
{
public class Client
{
public static int Main(string [] args)
{
int counter;
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;
}
}
}
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 Uniform
Resource Identifier.
For the client’s TCP connection, the Uniform Resource Identifier is
tcp://localhost:8085/SayHello.
For the client’s HTTP connection, the Uniform Resource Identifier is
http://localhost:8086/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 object’s method has been called.
Module 13: Remoting and XML Web Services 27
csc server.cs
csc /r:server.exe client.cs
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 object’s activation mode is SingleCall.
Rebuild and execute as in the preceding example. Note the counter values on
both calls. They should increase after each call.
28 Module 13: Remoting and XML Web Services
Objectives
After completing this lab, you will be able to:
! Create an XML Web service hosted in a .NET executable file.
! Create a TCP server.
! Create a client that uses .NET Remoting to access both an XML 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.
Module 13: Remoting and XML Web Services 29
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 customer’s ID and
arranging order fulfillment that is to say, having the ordered item sent to the
customer.
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
XML 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 XML 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.
Exercise 1
Creating an Authentication XML Web Service
In this exercise, you will create an XML 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.
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 Visual Studio .NET Command Prompt window, build Authenticate.exe.
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.
Note You cannot have two channels on one computer that are using the
same port number; therefore you cannot use port 8086.
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 greater than or 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 Visual Studio .NET Command Prompt window, build Fulfillment.exe.
34 Module 13: Remoting and XML Web Services
Exercise 3
Creating a Test Client
In this exercise, you will create a test client application to test the order-
processing servers. The client calls the authentication XML Web service. If the
user is authenticated, the client calls the order fulfillment server.
Tip You can display your machine’s current TCP/IP network connections
by running the program netstat in a command prompt window. The
following example shows that port 7 is in use by a process with PID 1504:
C:\>netstat -o -n -a
Active Connections
>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
36 Module 13: Remoting and XML Web Services
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 type http://Foo/Bar/HelloWorld.asmx in the
Address bar, the resulting page shows the public methods for this XML Web
service and the protocols, such as SOAP or HTTP GET, that you can use to
invoke these methods.
The public methods for the XML Web service are marked with the
[WebMethod] attribute.
The Web Services Description Language XML file for this service is produced
when you type 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.
Module 13: Remoting and XML Web Services 39
ASP.NET Features
! ASP.NET Can Expose Web Services Defined in a .NET Class
Topic Objective
To explain how to create an # Class derives from WebService, method attribute [WebMethod]
XML Web service by namespace
namespace MyNameSpace
MyNameSpace {{
exposing a .NET class that public
public class
class HelloWorld
HelloWorld :: WebService
WebService {{
inherits from the [WebMethod]
[WebMethod] public
public String
String SayHelloWorld()
SayHelloWorld() {{
WebService class, and to return "Hello World";
return "Hello World"; } }
introduce advanced }}
ASP.NET features. }} #
Lead-in # Class source file is compiled into a library DLL and placed in \Bin
In ASP.NET, you can create
csc
csc /out:bin\helloworld.dll
/out:bin\helloworld.dll /t:library
/t:library helloworld.cs
helloworld.cs
an XML Web service by
simply exposing a .NET # The .asmx file contains a single line that names the class
class that inherits from the
WebService class. <%@
<%@ WebService
WebService Class="MyNameSpace.HelloWorld"
Class="MyNameSpace.HelloWorld" %>
%>
! Advanced ASP.NET Features
# Data sets, Global.asax, Session and Application objects, pattern matching
namespace MyNameSpace {
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
XML 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.
Further discussion of these and other advanced ASP.NET features is beyond the
scope of this course.
Module 13: Remoting and XML Web Services 41
6. On the Build menu, click Build Solution to create the XML Web service.
7. Use Internet Explorer to access the XML Web service at the following
URL:
http://localhost/MathService/Service1.asmx
Tip To use Internet Explorer to view an XML Web service from within the
Visual Studio environment, right-click the .asmx file in the Solution
Explorer window, and then click View in Browser.
8. In the Internet Explorer page that is returned in step 7, click the link for the
Service1 operation labeled SalesTax.
9. In the Internet Explorer page that is returned in step 8, enter some
parameters, and then click Invoke to verify that the correct value is returned
and displayed in SOAP/XML format.
10. Use Internet Explorer to access and verify that the XML Web service’s
description is obtained from the following URL:
http://localhost/MathService/Service1.asmx?wsdl
Module 13: Remoting and XML Web Services 43
csc
csc salestaxclient.cs
salestaxclient.cs service1.cs
service1.cs
The following process shows how to create a simple application that uses the
XML Web service that is created in the Using Visual Studio to Create an XML
Web service demonstration in this module.
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 service’s class.
To generate a proxy for the Service1 class in a file named Service1.cs, type
the following command in a Visual Studio .NET Command Prompt
window:
wsdl http://localhost/MathService/service1.asmx?wsdl
Module 13: Remoting and XML Web Services 45
3. Write the client code that calls the remote object. Create a text file named
Salestaxclient.cs in the folder <install folder>\DemoCode\Mod13\
Demo13.2 containing the following code:
using System;
4. 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.
5. To build Salestaxclient.exe, type the following command in a Visual Studio
.NET Command Prompt window:
csc salestaxclient.cs service1.cs
Objectives
After completing this lab, you will be able to:
• Access an XML 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.
Module 13: Remoting and XML Web Services 49
Scenario
This lab is similar to the scenario used in Lab 13.1, Building an Order-
Processing 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 customer’s 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 an XML Web service to calculate the
item’s cost including sales tax. This scenario simulates the case where you do
not have access to the XML Web service’s source code or assembly.
You will build a MathService XML 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 XML Web service. Then you will build a client called
Testclient2.exe that uses this proxy to access the XML Web service’s
Service1.SalesTax method to calculate the cost of the ordered item.
Exercise 1
Creating the XML Web Service Proxy
In this exercise, you will create the MathService XML Web service and use the
Web Services Description Language tool (Wsdl.exe) to create a proxy class to
this XML Web service.
! Create the MathService XML Web service using Visual Studio .NET
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 ASP.NET Web Service.
c. In the Location box, type the name of the Web server,
http://localhost/MathService. The grayed out Name box will now
contain the text MathService. Then click OK.
2. On the View menu, click Code.
Because the XML Web service in this demonstration is simple, you can
work on the code directly. For more complex XML Web services, you can
use the Service1.asmx.cs Design palette that is displayed when you create a
new project of type XML 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 commented-
out WEB SERVICE EXAMPLE.
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 Solution to create the XML Web service.
6. Use Internet Explorer to access the XML Web service at the following
URL:
http://localhost/MathService/Service1.asmx
Tip To use Internet Explorer to view an XML Web service from within the
Visual Studio environment, right-click the .asmx file in the Solution
Explorer window, and then click View in Browser.
Module 13: Remoting and XML Web Services 51
7. In the Internet Explorer page that is returned in step 6, click the link for the
Service1 operation labeled SalesTax.
8. In the Internet Explorer page that is returned in step 7, type some
parameters, and then 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 XML Web service’s
description is obtained from the following URL:
http://localhost/MathService/Service1.asmx?wsdl
• In a Visual Studio .NET Command Prompt window, from the Lab 13.2
Starter directory, create a proxy to the authentication XML Web service
named Service1.cs by running the following command:
wsdl http://localhost/MathService/service1.asmx?wsdl
52 Module 13: Remoting and XML 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 XML 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.
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 in a Visual Studio .NET Command Prompt window as
follows:
a. Reference 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.
Module 13: Remoting and XML Web Services 53
>testclient2
Authentication Server Customer 1234 Authorization: True
Fulfillment Server Customer 1234 Item Number 5678!
Shipped: False
54 Module 13: Remoting and XML Web Services
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Remoting
Lead-in ! Remoting Configuration Files
The review questions cover
some of the key concepts ! XML Web Services
taught in the module.
7. How can a client invoke an XML Web service that is not implemented by
using the .NET Framework or in which the XML Web service’s assembly or
source code is not available?
The Web Services Description Language tool (Wsdl.exe) can be used to
read the WSDL description of an XML Web service and create a proxy
class. The client can use the proxy class to invoke the methods of the
XML Web service.
56 Module 13: Remoting and XML Web Services
Course Evaluation
Topic Objective
To direct students to a Web
site to complete a course
evaluation.
Lead-in
Between now and the end of
the course, you can go to
the Web site listed on this
page to complete a course
evaluation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 14 (Optional): Threading and Asynchronous Programming iii
Required Materials
To teach this module, you need the Microsoft PowerPoint® file 2349B_14.ppt.
Preparation Tasks
To prepare for this module:
! Read all of the materials for this module.
! Practice the demonstrations.
! Complete the lab.
iv Module 14 (Optional): Threading and Asynchronous Programming
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 project
folders that are located in <install folder>\Democode\Mod14.
Use the debugger to step through the code while you point out features and ask
students what they think will happen next.
Managing Threads
In this demonstration, you will show students how to create and manage threads
in the .NET Framework by using some of the classes and methods that were
covered in Using Threads in .NET.
The code for this demonstration is contained in one project and is located in
<install folder>\Democode\Mod14\Demo14.1.
Using a Delegate
In this demonstration, you will show students how to use a delegate object to
make asynchronous calls.
The code for this demonstration is contained in one project and is located in
<install folder>\Democode\Mod14\Demo14.7.
Multimedia Presentation
This section lists the multimedia items that are part of this module. Instructions
for launching and playing the multimedia are included with the relevant slides.
Asynchronous Programming
This animation illustrates the .NET Framework common language runtime
support for asynchronous programming using Delegate objects.
vi Module 14 (Optional): Threading and Asynchronous Programming
Module Strategy
Use the following strategy to present this module:
! Introduction to Threading
Provide a general introduction to the concept of threads and discuss
advantages and disadvantages of using them. As a simple illustration of the
concept of threading, use Microsoft Internet Explorer to show how you can
still do work while waiting for a download operation to complete.
Provide a high level overview of the System.Threading namespace and
introduce the asynchronous design pattern, which you will cover in more
detail in Asynchronous Programming in .NET.
Explain how application domains play a key role in .NET threading
architecture.
! Using Threads in .NET
Focus on the classes in the System.Threading namespace that are used to
start, manage, and terminate threads.
In addition to the preceding operations, discuss the role of managed thread
local storage.
! Thread Safety
Focus on the issues that students may encounter in multithreaded
programming from sharing data and resources between threads, as a result
of thread synchronization.
Introduce strategies that the .NET Framework provides for dealing with
synchronization, in particular classes and interfaces in System.Threading.
! Special Thread Topics
Introduce the Thread.Timer class, which provides a mechanism for
executing methods at specified intervals. Explain how a TimerCallback
delegate is used in conjunction with a Timer.
Discuss the use of thread pools in making multiple threads operate more
efficiently.
Discuss how managed threads call into a COM object.
Outline best practices for implementing thread-safe code.
Module 14 (Optional): Threading and Asynchronous Programming vii
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Introduction to Threading
Lead-in ! Using Threads in .NET
In this module, you will learn
about the support that the ! Thread Safety
.NET Framework provides
for working with ! Special Thread Topics
multithreaded applications
! Asynchronous Programming in .NET
and asynchronous
programming.
Overview of Threads
Topic Objective
To define threads in the
context of general ! Threads
multitasking and state the # The basic unit to which an operating system allocates processor time
primary advantages and # Enable multiple activities to appear to occur simultaneously
disadvantages of using
! Advantages of using multiple threads
threads.
# Application does background processing while keeping the UI responsive
Lead-in
Whether you are developing # Distinguish tasks of varying priority
for computers with one # Communicate over a network, to a Web server, and to a database
processor or several, you ! Potential disadvantages of using threads
want your application to
# Diminished performance due to increased operating system overhead, for
provide the most responsive example, thread context switching
interaction with the user,
even if the application is # Controlling code execution with many threads is complex, and can be a
source of many difficult to find and fix bugs
currently doing other work.
Threads
Threads are the basic unit to which an operating system allocates processor
Delivery Tip time, and more than one thread can execute code inside a process. Each thread
You can quickly illustrate
how multiple threads are
maintains exception handlers, a scheduling priority, and a set of structures that
used to create nonblocking the system uses to save the thread context until it is scheduled. The thread
UI by running the Microsoft context includes all of the information that the thread needs to smoothly resume
Internet Explorer Web execution, including the thread’s set of CPU registers and stack, in the address
browser. Start the browser space of the thread’s host process.
and type a URL address or
click a link to a site that Operating systems use processes to separate the different applications that they
takes some time to are executing. The .NET Framework further subdivides an operating system
download. Show how you process into lightweight, managed subprocesses, called application domains,
can still interact with the represented by System.AppDomain. One or more managed threads,
application during this represented by System.Threading.Thread, can run in one or any number of
download operation, for application domains within the same process. A preemptive multitasking
example, canceling the operating system allocates a processor time slice to each thread that it executes.
current download by clicking Because each time slice is small, multiple threads appear to execute at the same
Stop.
time.
4 Module 14 (Optional): Threading and Asynchronous Programming
Note While this module focuses on threading, there are other ways of
achieving concurrency that include using multiple processes/AppDomains,
messaging, and database stored procedures.
Module 14 (Optional): Threading and Asynchronous Programming 5
Thread
Thread Thread
Thread Thread
Thread
Specific
Specific Specific
Specific Specific
Specific
Data
Data Data
Data Data
Data
Starting Threads
Topic Objective
To explain how to instantiate
and start a new thread by ! Create a new instance of a Thread Object
using the .NET Framework
classes. # Constructor takes a ThreadStart delegate as its only
Lead-in parameter
Creating a new instance of a
Thread class creates a new
# ThreadStart references the method that will be
managed thread. executed by the new thread
! Thread is not executed until the Thread.Start method is
invoked
Thread
Thread tt == new
new
Thread(new
Thread(new ThreadStart(MyClass.AStaticMethod));
ThreadStart(MyClass.AStaticMethod));
t.Start();
t.Start();
The following code shows how to create and start new threads:
using System;
using System.Threading;
class MyClass
{
//…
public static void AStaticMethod()
{
//…
}
public void AnInstanceMethod()
{
//…
}
}
class App
{
//…
}
}
In the preceding example, the calls to t1.Start and t2.Start place the t1 and t2
threads in the running state, and the operating system can schedule them for
execution. The Start method submits an asynchronous request to the system,
and the call returns immediately, possibly before the new thread has started.
The thread’s execution begins at the first line of the method that is referred to
by the thread delegate. Calling Start more than once on the same thread causes
the runtime to throw a ThreadStateException.
12 Module 14 (Optional): Threading and Asynchronous Programming
To get or set the name of a thread and its priority, use the Thread.Name and
Thread.Priority properties. Thread.Priority gets or sets the following values
that indicate the scheduling priority of a thread:
! Highest
! AboveNormal
! Normal
! BelowNormal
! Lowest
For example, to set the name of a thread t to “My Background Thread” and
make its priority AboveNormal, you use the following code:
t.Name = "My Background Thread";
t.Priority = ThreadPriority.AboveNormal;
Note Because the details of scheduling algorithms vary with each operating
system, operating systems are not required to honor the priority of a thread.
Module 14 (Optional): Threading and Asynchronous Programming 13
class MyClassWithThreadState
{
int sleepTime;
class Class1
{
static void Main()
{
int sleepTime = 1000; // time for the thread to sleep
MyClassWithThreadState myClassWithThreadState =
new MyClassWithThreadState(sleepTime);
Thread ts = new Thread(new
ThreadStart(myClassWithThreadState.ThreadMethod));
ts.Start();
// …
}
}
Module 14 (Optional): Threading and Asynchronous Programming 15
Managing Threads
Topic Objective
To describe the classes that ! Thread.Sleep causes the current thread to block
the runtime uses to pause,
resume, and force threads Thread.Sleep(3000);
Thread.Sleep(3000); //
// blocks
blocks for
for 33 seconds
seconds
to wait. ! Suspend and Resume methods are not generally useful
Lead-in # Can result in serious application problems like deadlocks
Let’s look at how the
runtime provides classes to ! Thread.Join waits for another thread to stop
manage threads.
t.Start();
t.Start();
t.Join();
t.Join(); //
// Wait
Wait for
for the
the thread
thread to
to exit
exit
! Thread.WaitHandle methods wait for one or more events
WaitHandle.WaitAll(waitEvents);
WaitHandle.WaitAll(waitEvents);
! Thread.ThreadState property - bit mask of the thread's state
class MyApp
{//…
static void MyThreadMethod()
{
//…
}
static void Main()
{
// create, start and join a simple background thread
// MyThreadMethod is the secondary thread's entry point.
Thread t = new Thread(new ThreadStart(MyThreadMethod));
// Start the thread
t.Start();
// Wait for the thread to exit
t.Join();
}
}
Module 14 (Optional): Threading and Asynchronous Programming 17
WaitAll This method waits for all of the elements in the specified array to
receive a signal.
WaitAny This method waits for any of the elements in the specified array to
receive a signal.
WaitOne This method blocks the current thread until the current WaitHandle
receives a signal.
For example, the following code shows how to force the main thread to wait
until the threads that it has created signal that they have finished executing:
using System;
using System.Threading;
class MyClassWithThreadState
{
AutoResetEvent done;
public MyClassWithThreadState(AutoResetEvent done)
{
this.done = done;
}
public void ThreadMethod()
{
//…
done.Set(); // signal that we are finished
}
}
class MyApp
{
//…
static void Main()
{
//…
int numberOfThreads = 3; // number of threads to create
AutoResetEvent[] waitEvents = new
AutoResetEvent[numberOfThreads];
Thread ts;
MyClassWithThreadState myClassWithThreadState;
for (int i=0; i<numberOfThreads; i++)
{
waitEvents[i] = new AutoResetEvent(false);
myClassWithThreadState = new
MyClassWithThreadState(waitEvents[i]);
ts = new
Thread( new
ThreadStart(myClassWithThreadState.ThreadMethod));
ts.Start();
}
// Wait for all threads to indicate that they are done.
WaitHandle.WaitAll(waitEvents);
//…
}
}
Note You can also use multiple calls to the Thread.Join method to wait for
multiple threads to exit.
In this module, thread safety describes how to force a thread to wait for access
to a synchronized object, such as a Mutex method call.
Also in this module, Terminating Threads describes how to interrupt a waiting
thread by calling the Thread.Interrupt or Thread.Abort method.
Module 14 (Optional): Threading and Asynchronous Programming 19
Because the Running state has a value of 0, you cannot perform a bit test to
discover this state. Instead, you can use the following test (in pseudo-code):
if ((tState & (Unstarted | Stopped)) == 0) // implies Running
Threads are often in more than one state at any particular time. For example, if
a thread is blocked from a Wait call and another thread calls Abort on that
same thread, the thread is in both the WaitSleepJoin and the AbortRequested
state at the same time. In that case, as soon as the thread returns from the call to
Wait or is interrupted, it receives the ThreadAbortException.
After a thread leaves the Unstarted state as the result of a call to Thread.Start,
it can never return to the Unstarted state. A thread can never leave the Stopped
state, either.
20 Module 14 (Optional): Threading and Asynchronous Programming
public
public void
void ThreadMethod()
ThreadMethod() {{
count++;
count++;
}}
}}
Using Thread.Interrupt
When you call Thread.Interrupt, you wake a thread from any wait state and
cause a ThreadInterruptedException to be thrown in the destination thread.
The thread should catch the ThreadInterruptedException and do whatever is
appropriate to continue working. If the thread ignores the exception, the runtime
catches the exception and stops the thread.
For example, you may want to terminate a thread in response to a user-initiated
event, such as clicking a Cancel button. The Cancel button’s event handler may
run in one thread (thread1), while the event to which the Cancel action applies
may run in a separate thread (thread2). In your event handler, you can call the
Interrupt method on the second thread, as follows:
// inside the Cancel button's event handler
if ( thread2 != null)
{
thread2.Interrupt();
thread2 = null;
}
24 Module 14 (Optional): Threading and Asynchronous Programming
Using Thread.Abort
To terminate a thread permanently, you use the Thread.Abort method. When
you call Abort to terminate a thread, the system wakes the thread from any wait
state and throws a ThreadAbortException. The runtime executes the catch
block and any finally block.
ThreadAbortException is a special exception that can be caught by
application code, but is rethrown at the end of the catch block unless
ResetAbort is called. Only code with the proper permissions can call
ResetAbort method. ResetAbort cancels the request to abort, and prevents the
ThreadAbortException from terminating the thread. If the finally blocks
contain any unbounded computations, the thread’s termination may be delayed
indefinitely.
Because the call to Thread.Abort does not always result in the immediate
termination of a thread, you can ensure the thread’s destruction by calling the
Join method on the thread after you call Abort. Join blocks the calling thread
until the thread stops executing.
After a thread terminates, you cannot restart it by calling Start again. For
example, if code creates a thread, lets it run, and then aborts the thread, any
attempt to restart the thread causes the runtime to throw a
ThreadStateException.
Blocking Issues
If a thread makes an unmanaged call into the operating system, and the system
has blocked the thread in unmanaged code, the runtime will not take control of
the blocked thread for Thread.Interrupt or Thread.Abort.
In the case of Thread.Abort, the runtime marks the thread for Abort and takes
control of the thread when it re-enters managed code. Where possible, you
should use managed blocking rather than unmanaged blocking. The following
methods are all responsive to Thread.Interrupt and Thread.Abort:
! WaitHandle
! WaitOne
! WaitAny
! WaitAll
! Monitor.Enter
! Monitor.Block
! Thread.Join
! GC.WaitForPendingFinalizers
catch(ThreadInterruptedException e)
{
Console.WriteLine(
"Thread - caught ThreadInterruptedException");
Console.WriteLine(
"Exception message: {0}", e.Message);
}
catch(ThreadAbortException e)
{
Console.WriteLine(
"Thread - caught ThreadAbortException");
Console.WriteLine(
"Exception message: {0}", e.Message);
if (resetAbort == true) Thread.ResetAbort();
}
finally
{
Console.WriteLine("Thread - finally block");
}
Console.WriteLine(
"Thread - still alive and working.");
Thread.Sleep(1000);
Console.WriteLine(
"Thread - finished working.");
}
}
class ThreadAbortTest
{
public static void Main()
{
ThreadStart myThreadDelegate = new
ThreadStart(ThreadWork.DoWork);
Thread myThread;
Console.WriteLine(
"Main - interrupting my thread.");
myThread = new Thread(myThreadDelegate);
myThread.Start();
Thread.Sleep(100);
myThread.Interrupt();
Thread.Sleep(2000);
ThreadWork.resetAbort = true;
Console.WriteLine(
"Main - aborting my thread with resetAbort: {0}.",
ThreadWork.resetAbort);
myThread = new Thread(myThreadDelegate);
myThread.Start();
Thread.Sleep(100);
myThread.Abort();
Thread.Sleep(2000);
ThreadWork.resetAbort = false;
Console.WriteLine(
"Main - aborting my thread with resetAbort: {0}.",
ThreadWork.resetAbort);
myThread = new Thread(myThreadDelegate);
myThread.Start();
Thread.Sleep(100);
myThread.Abort();
myThread.Join();
Console.WriteLine("Main ending.");
}
}
28 Module 14 (Optional): Threading and Asynchronous Programming
Race condition
Two or more threads that simultaneously access the same data can cause
undesirable and unpredictable results. For example, one thread may update the
contents of a structure while another thread reads the contents of the same
structure. In this scenario, it is unknown what data the reading thread will
receive: the old data, the newly written data, or possibly a mixture of both.
When the proper operation of a program depends on the uncontrolled order of
execution of multiple threads, then a race condition exists.
Deadlock
A multithreaded application can also encounter problems with thread
synchronization if multiple threads are waiting for each other to release
resources. This blocking of thread execution is known as a deadlock.
For example, consider two threads that transfer money between accounts A and
B. The first thread, Thread 1, is coded to do the following tasks in the following
order:
! Wait for and acquire a lock on account A
! Wait for and acquire a lock on account B
! Transfer funds
! Release both locks
The second thread, Thread 2, is coded in the same way, except that it first
acquires a lock on account B, then on account A.
Module 14 (Optional): Threading and Asynchronous Programming 31
Consider the case where Thread 1 acquires lock A, but before it can acquire
lock B, Thread 2 runs and acquires lock B. In this case, both threads block
while waiting for the other lock. Because both threads are blocked, neither
thread releases the lock that is required by the other thread to proceed. This
condition is referred to as a deadlock situation.
You can best achieve thread safety by not sharing data or resources between
threads. If possible, use a design pattern that encapsulates data and resources
into instances that are not shared across requests. When this is not possible you
should use the .NET Framework thread synchronization classes to provide
thread safety.
The runtime provides a thread model in which classes fall into a number of
categories that can be synchronized in a variety of different ways, depending on
the requirements.
No Synchronization
No synchronization support is the default for objects. Any thread can access
any method or field at any time.
Synchronized Context
You can use the SynchronizationAttribute on any class that is derived from
ContextBoundObject to synchronize all instance methods and fields. All
objects in the same context domain share the same lock. Multiple threads are
allowed to access the instance methods and fields, but only a single thread is
allowed at any one time. Static members are not protected from concurrent
access by multiple threads.
The following table shows the support provided for fields and methods under
the synchronization context category.
Synchronization context supports Synchronization context does not support
Instance fields and instance methods Global fields, static fields, and static methods
Specific code blocks
32 Module 14 (Optional): Threading and Asynchronous Programming
Static methods, instance methods, and Global fields, static fields, and instance
specific code blocks fields
Manual Synchronization
You can use the Interlocked, Mutex, ManualResetEvent, AutoResetEvent,
and ReaderWriterLock classes to acquire and release a lock to protect global,
static, and instance fields and global, static, and instance methods.
Module 14 (Optional): Threading and Asynchronous Programming 33
Synchronization Context
Topic Objective
To describe how to ! SynchronizationAttribute enables simple, automatic
synchronize access to synchronization for ContextBoundObject objects
instance fields and methods
by using synchronization # Only instance fields and methods are synchronized
contexts.
# Static fields and methods are not protected from
Lead-in concurrent access by multiple threads
Let’s look at using
synchronization contexts in [Synchronization()]
[Synchronization()]
more detail. class
class CounterSynchronizedContext
CounterSynchronizedContext :: ContextBoundObject
ContextBoundObject
{{
static
static int
int sCount
sCount == 0;
0; //multiple
//multiple threads
threads can
can access
access
int
int iCount
iCount == 0;
0; //only
//only one
one thread
thread can
can access
access at
at aa time
time
public
public void
void Increment()
Increment() {{
//…
//… only
only one
one thread
thread can
can access
access at
at aa time
time
}}
}}
Caution A synchronization context does not protect static fields and methods
from concurrent access by multiple threads.
34 Module 14 (Optional): Threading and Asynchronous Programming
[Synchronization()]
class CounterSynchronizedContext : ContextBoundObject
{
// Caution! multiple concurrent threads allowed for
// static field – can use manual synchronization to protect
static int staticCount = 0;
[MethodImplAttribute(MethodImplOptions.Synchronized)]
In the following example, the class CounterSynchronizedCodeRegion has
both its instance method IncrementInstance and static method
IncrementStatic attributed for synchronized access. This allows only one
thread to execute either method at one time.
using System;
using System.Threading;
using System.Runtime.CompilerServices;
class ASynchronizedClassExample
{
static int staticValue = 0;
int instanceValue = 0;
[MethodImplAttribute(MethodImplOptions.Synchronized)]
public void ChangeInstance()
{
// thread safe changes to instanceValue
}
[MethodImplAttribute(MethodImplOptions.Synchronized)]
public static void ChangeStatic()
{
// thread safe changes to staticValue
}
}
//…
The Monitor class provides methods that you can use to synchronize access to
a specific region of code by taking and releasing a lock on a particular object.
After you obtain a lock on a code region, you can use the Monitor.Wait,
Monitor.Pulse, and Monitor.PulseAll methods.
38 Module 14 (Optional): Threading and Asynchronous Programming
Monitor.Wait
The Monitor.Wait method releases the lock on an object and blocks the current
thread until it reacquires the lock. The thread that currently owns the lock on the
specified object invokes this method to release the object so that another thread
can access it. The caller is blocked while waiting to reacquire the lock. This
method is called when the calling thread is waiting for a change in the state of
the object that will occur as a result of another thread’s operations on the object.
When a thread calls Wait, it releases the lock on the object and enters the
object’s waiting queue. The next thread in the object’s ready queue, if there is
one, acquires the lock and has exclusive use of the object. All threads that call
Wait remain in the waiting queue until they receive a signal from Pulse or
PulseAll, sent by the owner of the lock. If Pulse is sent, only the thread at the
head of the waiting queue is affected. If PulseAll is sent, all threads that are
waiting for the object are affected. When the signal is received, one or more
threads leave the waiting queue and enter the ready queue. A thread in the ready
queue is permitted to reacquire the lock.
This method returns when the calling thread reacquires the lock on the object.
Note that this method blocks indefinitely if the holder of the lock does not call
Pulse or PulseAll.
Caution You should check whether the Pulse method is ever called before its
corresponding Wait method is called. A thread must have already issued a
Wait for the Pulse to affect it. You can use the Monitor.Wait methods with a
timeout parameter to prevent the caller of the Wait from blocking indefinitely
when such a condition occurs.
Monitor.Pulse
The Monitor.Pulse method notifies a thread in the waiting queue of a change in
the locked object's state. Only the current owner of the lock can signal a waiting
object by using Pulse. The thread that currently owns the lock on the specified
object invokes this method to signal the next thread in line for the lock. Upon
receiving the pulse, the waiting thread is moved to the ready queue. When the
thread that invoked Pulse releases the lock, the next thread in the ready queue,
which is not necessarily the thread that was pulsed, acquires the lock.
Note Be aware of the distinction between the use of Monitor and WaitHandle
objects. Monitor objects are purely managed, fully portable, and may be more
efficient in terms of operating system resource requirements. WaitHandle
objects represent operating system waitable objects, are useful for
synchronizing between managed and unmanaged code, and expose some
advanced operating system features like the ability to wait on many objects at
once.
Module 14 (Optional): Threading and Asynchronous Programming 39
Compiler Support
Both Visual Basic and Visual C# support a language keyword that uses
Monitor.Enter and Monitor.Exit to lock the object. Visual Basic supports the
SyncLock keyword; Visual C# supports the lock keyword.
When you use the lock or SyncLock keyword, the compiler generates code.
The Visual C# and Visual Basic compilers emit a try/finally block with
Monitor.Enter at the beginning of the try, and Monitor.Exit in the finally
block. If an exception is thrown inside of the lock or SyncLock block, the
finally handler runs to allow you to perform any clean-up work.
The C# statement, of the form lock(x) where x is an expression of a reference-
type, is equivalent to the following except that x is only evaluated once:
System.Threading.Monitor.Enter(x);
try {
...
}
finally {
System.Threading.Monitor.Exit(x);
}
class Cache
{
public static void Add(object x)
{
// method code that doesn't require exclusive access
lock (typeof(Cache))
{
// code requiring exclusive access to static data
}
// method code that doesn't require exclusive access
}
The Unsafe test should result in output that is similar to the following example.
Notice that the Increment method has been called three times but the count has
only been incremented by one.
Starting Unsafe Test
Start Resource writing count: 0
Start Resource writing count: 0
Start Resource writing count: 0
Stop Resource writing count: 1
Stop Resource writing count: 1
Stop Resource writing count: 1
All Unsafe threads have completed.
Manual Synchronization
Topic Objective
To describe the use of the
Interlocked class methods, ! Interlocked methods – synchronize access to a variable
the Mutex class, and the that is shared by multiple threads
ReaderWriterLock class in
manual synchronization. # CompareExchange, Decrement, Exchange, Increment
Lead-in
Let’s look at some options
# Threads of different processes can use this mechanism
that the .NET Framework to safely handle variables in
provides to create shared memory
synchronization
mechanisms. ! Mutex – synchronization between threads
across processes
! ReaderWriterLock – single-writer/multiple-reader
Note The C# increment operator (++) and decrement operator (--) are not
implemented by atomic operations and therefore do not provide the thread
safety that the Increment and Decrement methods do.
The following Visual C# code example only allows a single call to set the
property X. The property X is only set once because the CompareExchange
method changes the value of _x only when its first and third parameters are
equal, that is to say when _x is equal to null. After _x has been set to ovalue, it
no longer equals null and the CompareExchange method will no longer
modify it.
using System;
using System.Threading;
namespace CompareandExchange
{
class PropertyTest
{
private Object _x;
public int X
{
set {
Object ovalue = value;
Interlocked.CompareExchange(
ref _x, ovalue, null);
}
get {
return (int) _x;
}
}
}
class Class1
{
static void Main(string[] args)
{
PropertyTest pt = new PropertyTest();
pt.X = 1;
pt.X = 2;
Console.WriteLine("pt.X: {0}", pt.X);
}
}
}
Mutex
You can use a Mutex object to synchronize between threads and across
processes. The Mutex class provides a synchronization primitive that grants
exclusive access to the shared resource to only one thread. If a thread acquires a
mutex, the second thread that wants to acquire that mutex is suspended until the
first thread releases the mutex. Although Mutex does not have all of the wait
and pulse functionality of the Monitor class, it does offer the creation of named
mutexes that can be used between processes.
You call WaitOne, WaitAll, or WaitAny to request ownership of the Mutex.
The state of the Mutex is signaled if no thread owns it.
If a thread owns a Mutex, that thread can specify the same Mutex in repeated
wait-request calls without blocking its execution. However, it must release the
Mutex as many times as it called wait to release ownership. If a thread
terminates normally while owning a Mutex, the state of the Mutex is set to
signaled and the next waiting thread gets ownership. The Mutex class
corresponds to a Win32 CreateMutex call.
ReaderWriterLock
The ReaderWriterLock defines a lock that implements single-writer/multiple-
reader semantics. In terms of resources, ReaderWriterLock objects are
sufficiently inexpensive enough to be used in large numbers such as with per-
object synchronization.
The ReaderWriterLock provides equity between readers and writers. After a
writer-lock is requested, no new readers are accepted until the writer has access.
Neither readers nor writers are perpetually denied access. The
ReaderWriterLock class supports functionality for upgrading to a writer lock
with a return argument that indicates intermediate writes, and for downgrading
from a writer lock, which restores the state of the lock. The class recovers from
most common failures such as the creation of events. The lock maintains a
consistent internal state and remains usable.
48 Module 14 (Optional): Threading and Asynchronous Programming
The following example shows how a class can use a ReaderWriterLock object
to allow multiple threads to execute its Read method or a single thread to
execute its Write method at any time.
using System;
using System.Threading;
class Resource
{
ReaderWriterLock rwl = new ReaderWriterLock();
Collections
By default, Collections classes are generally not thread-safe. Multiple readers
can safely read the collection; however, any modification to the collection
produces undefined results for all threads that access the collection, including
the reader threads.
You can make Collections classes thread safe by using any of the following
techniques:
! Create a thread-safe wrapper by using the Synchronized method and access
the collection exclusively through that wrapper. When implementing the
Synchronized method, derived classes must override the IsReadOnly
property to return the correct value.
! If the class does not have a Synchronized method, derive from the class and
implement a Synchronized method by using the SyncRoot property.
! Use a locking mechanism, such as the lock statement in Visual C#
(SyncLock in Visual Basic), on the SyncRoot property when accessing the
collection.
By default, only the Hashtable class guarantees thread safety when one writer
and multiple readers simultaneously access the collection. You can make the
collection thread-safe for multiple writers by using any of the preceding
techniques.
The Array class does not include a Synchronized method and, although it has
a SyncRoot property, you cannot derive from the class. Therefore, you can
make an array thread safe only through the locking mechanism.
Module 14 (Optional): Threading and Asynchronous Programming 51
You will also learn how the runtime synchronizes access to shared resources
between unmanaged COM objects and managed objects in a way that ensures
thread safety.
In addition, you will learn about the requirements for dealing with nonthread-
safe Windows Forms controls, and how you can optimize the performance
effects that are associated with marshaling method calls.
Finally, you will learn the recommended best practices for implementing
thread-safe code.
52 Module 14 (Optional): Threading and Asynchronous Programming
Timer Class
Topic Objective
To describe how to use the
Thread.Timer class with a
delegate to execute ! Thread.Timer class - periodically executes a method
methods periodically.
# Threading.TimerCallback delegate for callback method
Lead-in
The Thread.Timer class # Change method changes timer values
provides functionality to
execute a method at # Dispose method frees the resources held by the timer
specified intervals.
Timer
Timer timer
timer == new
new Timer(
Timer(
new
new TimerCallback(CheckStatus),
TimerCallback(CheckStatus), null,
null, 0,
0, 2000);
2000);
//
// ……
static
static void
void CheckStatus(Object
CheckStatus(Object state)
state) {{
Console.WriteLine("Checking
Console.WriteLine("Checking Status.");
Status.");
}}
Note There are multiple Timer classes in the .NET Framework. Be careful not
to confuse the Thread.Timer class with the System.Timers.Timer and
System.Windows.Forms.Timer classes. For more information about these
classes, see the .NET Framework SDK documentation.
Module 14 (Optional): Threading and Asynchronous Programming 53
The following example shows how to use a timer and a delegate to execute
methods at specified intervals of two seconds:
using System;
using System.Threading;
class App {
public static void Main() {
Console.WriteLine(
"Checking for status updates every 2 seconds.");
Console.WriteLine(
" (Hit Enter to terminate the sample)");
Timer timer = new Timer(new TimerCallback(CheckStatus),
null, 0, 2000);
Console.ReadLine();
timer.Dispose();
}
Thread Pools
Topic Objective
To introduce thread pooling.
! Thread pooling is used to improve efficiency
Lead-in
You can often use thread # System optimizes based on all of computer’s processes
pooling to make the use of ! Do not use thread pooling when you
multiple threads more
efficient. # Need a task to have a particular priority
# Have a task that might run for a long time
# Need to place threads into a single-threaded apartment
# Need a stable identity to be associated with the thread
! IOCompletionCallback delegate for asynchronous I/O
completion events
# A thread from the thread pool will process data when received
The following example shows one way to use the ThreadPool class methods to
start multiple threads and monitor their completion:
using System;
using System.Threading;
class Counter
{
public void Read(int threadNum)
{
//…
}
public void Increment(int threadNum)
{
//…
}
}
class App
{
static Counter counter = null;
static int totalNumberOfAsyncOps = 10;
static int numAsyncOps = totalNumberOfAsyncOps;
static AutoResetEvent asyncOpsAreDone =
new AutoResetEvent(false);
if (( Interlocked.Decrement(ref numAsyncOps)) == 0)
asyncOpsAreDone.Set();
}
}
Module 14 (Optional): Threading and Asynchronous Programming 57
IOCompletionCallback
Using asynchronous I/O completion events, a thread from the thread pool
processes data only when the data is received. After the data has been
processed, the thread returns to the thread pool.
To make an asynchronous I/O call, you must associate an operating system I/O
handle with the thread pool and specify a callback method. When the I/O
operation completes, a thread from the thread pool invokes the callback method.
For more information about using asynchronous I/O completion events, see the
.NET Framework SDK documentation.
58 Module 14 (Optional): Threading and Asynchronous Programming
You can set the ApartmentState property when the thread is in the
ThreadState.Unstarted or ThreadState.Running state; however, you can
only set the property once for a thread. The two valid property states are single-
threaded apartment (STA) or multithreaded apartment (MTA).
66 Module 14 (Optional): Threading and Asynchronous Programming
The following table describes the invoke methods and specifies the method
signatures for those methods.
Method Signature and description
InvokeRequired public bool InvokeRequired { get ; }
Returns true if the caller must call Invoke when making method
calls to this control.
BeginInvoke public IAsyncResult BeginInvoke(Delegate
method)
public IAsyncResult BeginInvoke(Delegate
method, Object[] args)
The following code demonstrates how to create a background thread that uses a
MethodInvoker to update a ProgressBar control at regular intervals:
Module 14 (Optional): Threading and Asynchronous Programming 69
//…
//Start the background thread
timerThread = new Thread(new ThreadStart(ThreadProc));
timerThread.IsBackground = true;
timerThread.Start();
//…
try {
MethodInvoker mi = new
MethodInvoker(this.UpdateProgress);
while (true)
{
//Call BeginInvoke on the Form
this.BeginInvoke(mi);
Thread.Sleep(500) ;
}
}
//Thrown when the thread is interupted by the main
// thread - exiting the loop
catch (ThreadInterruptedException e)
{
//Simply exit....
}
catch (Exception we)
{
}
}
//…
Note If you are making multiple cross-thread calls to a control, it is much more
efficient to create a new method that executes those calls and make a single
cross-thread call to the new method.
Module 14 (Optional): Threading and Asynchronous Programming 71
Start the application and observe the Microsoft Visual Studio® .NET Threads
window.
Note To make the Visual Studio .NET Threads window visible, while the
application is running, on the Debug menu, click Windows, and click Threads.
Click the form’s Start button, and when the program breaks, note the active
thread. Continue to the next breakpoint and again note the active thread. You
should observe that the BeginInvoke method marshaled the call to the
Windows Forms main thread.
72 Module 14 (Optional): Threading and Asynchronous Programming
! Performance issues can result when a static method in a class calls a static
method in the same class.
If these methods are not factored correctly, performance will suffer because
there will be a large amount of redundant synchronization. Excessive use of
synchronization may negatively affect performance. In addition, it may have
a significant negative effect on scalability.
! Be aware of issues with the lock statement (SyncLock in Visual Basic).
It is tempting to use the lock statement to solve all threading problems.
However, the System.Threading.Interlocked class is superior for updates
that must be made automatically. It executes a single lock prefix if there is
no contention.
In a code review, you should look for instances like the one shown in the
following example.
lock(this)
{
myField++;
}
The .NET Framework provides a design pattern that makes asynchronous calls
uniform across the different parts of the framework. This pattern is very useful
for making complex calls that take a considerable amount of time to complete.
User-created classes that support asynchronous calls should conform to this
design pattern.
76 Module 14 (Optional): Threading and Asynchronous Programming
Exceptions
If the begin operation method throws an exception, the caller can assume that
an asynchronous operation was not started and that the callback delegate will
not be called.
After an asynchronous operation starts, the client is notified of any exceptions
that are raised by the server when the client calls the end operation method.
Module 14 (Optional): Threading and Asynchronous Programming 79
The following code uses a synchronized call to read data from the file:
int byteCount = aStream.Read(buffer, 0, buffer.Length);
aStream.Close();
If the caller may issue multiple asynchronous calls, the caller must be able to
correlate each of the results to the original call. You can use the state parameter
of the method that makes the asynchronous call to store this information.
In this example, you store the name of the file being read in an instance of
MyState:
class MyState
{
public string filename;
public MyState(string filename) {
this.filename = filename;
}
}
// ...
MyState myState = new MyState(filename);
The BeginRead method returns and the thread can continue to execute while
the read operation proceeds. When the read operation completes, the
OnReadDone method is called, possibly on a separate thread. This method
performs the second part of the asynchronous operation, obtaining the results of
the operation as follows:
int byteCount = aStream.EndRead(ar); // data now in buffer
Console.WriteLine("Filename read: {0},
((MyState)(ar.AsyncState)).filename);
aStream.Close();
The BeginRead method returns and the thread can continue to execute while
the read operation proceeds. In this case, the thread periodically polls the
IsCompleted property of the IAsyncResult to determine when the read
operation is complete.
while (!ar.IsCompleted)
{
// do whatever
}
int byteCount = aStream.EndRead(ar); // data now in buffer
Console.WriteLine("Filename read: {0},
((MyState)(ar.AsyncState)).filename);
aStream.Close();
82 Module 14 (Optional): Threading and Asynchronous Programming
The output that is produced by running the code is similar to the following:
Doing Synchronous Read
Asynchronous Delegates
Topic Objective
To describe how to use
delegate objects to make ! Delegate object provides the ability to call a
asynchronous calls. synchronous method in an asynchronous manner
Lead-in # Compiler generates synchronous invoke method and
You can make an
asynchronous method call
asynchronous methods: BeginInvoke and EndInvoke
on an object even if the ! Asynchronous calls follow the design pattern
object’s class does not
provide explicit support for # Start operation with BeginInvoke
asynchronous operations by
using the asynchronous # Use callback, polling, call to EndInvoke, or wait to
methods of a delegate determine completion
object.
# Call EndInvoke to get results
When the compiler emits the FactorizeDelegate delegate class after parsing its
definition, it generates the BeginInvoke and EndInvoke methods, in addition
to the Invoke method. The BeginInvoke and EndInvoke methods follow the
asynchronous design pattern’s method signatures, as follows:
public class FactorizeDelegate: delegate
{
public bool Invoke(
int factorizableNum,
ref int primefactor1,
ref int primefactor2);
// Output results.
Console.WriteLine(
"On CallBack: Factors of {0} : {1} {2}",
_ulNumber, factor1, factor2);
}
}
//
// Do some other useful work.
//. . .
}
Module 14 (Optional): Threading and Asynchronous Programming 89
ar.AsyncWaitHandle.WaitOne(10000, false);
if (ar.IsCompleted)
{
int factor1=0, factor2=0;
// Output results.
Console.WriteLine(
"After Using Wait Handle: Factors of {0}: {1} {2}",
factorizableNum, factor1, factor2);
}
}
90 Module 14 (Optional): Threading and Asynchronous Programming
To launch the animation, This animation illustrates the .NET Framework common language runtime
click the button in the lower- support for asynchronous programming using Delegate objects.
left corner of the slide.
Module 14 (Optional): Threading and Asynchronous Programming 91
Lab Setup
Starter and solution files are associated with this lab. The starter files are in the
folder <install folder>\Labs\Lab14\Starter. The solution files for this lab are in
the folder <install folder>\Labs\Lab14\Solution.
Module 14 (Optional): Threading and Asynchronous Programming 93
Scenario
In this scenario, you use a Windows Forms client to invoke methods on a
logger server that writes messages to a log file. When starting the logger server
the client specifies the filename to use as a log file. After the logger server
starts, it opens the log file and begins two concurrent operations. In the first
operation, the server periodically writes the date and time to the log file; the
server does this by using a System.Thread.Timer object that uses a thread
from the thread pool.
In the second operation, the server periodically updates the client’s progress bar
to indicate to the user that the logger service is running. The server does this by
creating and starting a background thread. When the user stops the logger
server, the server terminates both concurrent operations and closes the log file.
While the logger server is running, the client can invoke a synchronous or an
asynchronous write of a text string to the log file. The asynchronous write is
done according to the .NET Framework asynchronous design pattern. The client
starts the asynchronous write by calling the BeginInvoke method of a delegate
to the logger server’s write method. The client, as a parameter to this call,
supplies an AsyncCallback delegate object that refers to the client’s method
that is called when the write operation completes.
Because multiple client calls to the server can execute concurrently, the server’s
methods must be implemented in a thread-safe manner.
Exercise 1
Creating Thread-safe Methods
In this exercise, you will add thread-safe code to the MyLogger static methods
to start the logger, stop the logger, and write to the log file.
Note You can use the Visual Studio .NET Task List window to quickly
locate this code. To display this window, on the View menu, click Show
Tasks, and click All.
3. Use a lock statement to ensure that only one thread at a time executes the
method’s code.
Because StartLogger is a static method, you lock on the System.Type
object of the MyLogger class. You can obtain this object by using the
following expression:
typeof(MyLogger)
Place the remainder of the StartLogger method’s code within the lock
statement block.
4. Create a conditional expression that evaluates whether the logger is running.
If the logger is running, throw an InvalidOperationException exception. If
the logger is not running (loggerRunning is false):
a. Initialize numberOfWrites to zero.
b. Create a FileStream object for the file that is specified in the filename
parameter of the StartLogger method. The new FileStream object also
takes the filename, FileMode.OpenOrCreate and FileAccess.Write
parameters.
c. Create a StreamWriter object and pass in the new FileStream object.
This new object should be assigned to the existing static member
variable w.
d. Set the file pointer to the end of the new stream by calling the
StreamWriter object’s seek method as follows:
w.BaseStream.Seek(0, SeekOrigin.End);
e. Write to the stream by using the following format and supplying the
current time and date as the parameters:
"\nStartLogger – Time: {0} {1} \n\n"
Module 14 (Optional): Threading and Asynchronous Programming 95
d. Write to the stream by using the following format and supplying the
current time and date as the parameters:
"{0} {1} \n\n"
Exercise 2
Periodically Writing to a Log File
In this exercise, you will add code to the MyLogger class to use a
System.Thread.Timer object. This object is used to periodically write a
message to the log file indicating that the logger is alive when the logger is
running.
2. Locate the line of code that sets loggerRunning to true, and after this line
assign to the static member variable timer a new object of type
System.Threading.Timer.
The new object should call the MyLogger class’s LogStatus method every
5 seconds. LogStatus is a static method whose delegate type is
TimerCallback.
2. Locate the line of code that writes the string "\nStopLogger - Time:"
to the log file and before this line add code that invokes the Dispose
method on the timer object.
! Add the Timer object that writes logger alive messages periodically to
the log file
1. In Form1.cs, locate the following comment for the LogStatus method of the
MyLogger class:
// TODO - Exercise 2.3: Add Timer callback method code to!
write the date and time to the log
3. Once again, write to the stream by using the following format and supplying
the current time and date as the parameters:
"{0} {1} \n\n"
Module 14 (Optional): Threading and Asynchronous Programming 99
Exercise 3
Providing the User with Status
In this exercise, you will add code to the MyLogger class to use a background
thread that periodically advances the Progress Bar in the user interface
whenever the logger is running.
2. Locate the line of code that assigns to the static member variable timer a
new object of type System.Threading.Timer and after this line, add code
to do the following steps.
3. Create a new object of type Thread
The Thread object is initialized with a delegate object of type ThreadStart
that refers to the ThreadProc method of the MyLogger class. This new
object should be assigned to the existing static member variable
timerThread.
4. Make timerThread a background thread by using its IsBackground
property.
5. Start the timerThread background thread.
2. Locate the line of code that invokes the Dispose method on the timer object
and before this line, set up a conditional expression that checks whether the
background thread is not null. If the background thread named
timerThread is not null:
a. Call the timerThread Interrupt method.
b. Assign timerThread, form, and mi to null.
Module 14 (Optional): Threading and Asynchronous Programming 101
7. Use Visual Studio .NET to view the file Log.txt that was created in the same
folder as the multithreading application’s executable program:
<install folder>\Labs\Lab14\Starter\Multithreading\bin\Debug
You should see output that is similar to the following:
StartLogger - Time: 11:56:44 AM Wednesday, September 19,
2001
Exercise 4
Making an Asynchronous Method Call
In this exercise, you will add code that uses a delegate object to begin an
asynchronous invocation of the WriteLog method of the MyLogger class. The
code will specify a method to be called when the WriteLog method completes.
You will add code to this method to obtain the results of the WriteLog method
and post the results to the form’s status bar.
! Create the event handler code that initiates the asynchronous write
1. In Form1.cs, locate the following comment for the button4_Click method
of the Form1 class:
// TODO - Exercise 4.1: Add code to begin asynchronous!
log write
! Create the code that is called when the asynchronous method call
completes
1. In Form1.cs, locate the following comment for the
AsynchronousWriteResults method of the Form1 class:
// TODO - Exercise 4.2: Add code to this callback method to handle !
the results of asynchronous log write
2. Create a delegate object name wld of type WriteLogDelegate and set wld
to refer to the method that was previously specified in the button4_Click
method’s BeginInvoke method call by doing the following:
a. Explicitly cast the parameter that is named ar of type IAsyncResult to
type AsyncResult and get its AsyncDelegate property.
b. Explicitly cast the result of the preceding step to type
WriteLogDelegate and assign this value to wld.
3. Create a try/catch block and in the try section, add code to do the
following:
a. Initialize a variable named count of type int to the result of calling the
wld object’s EndInvoke method with the single parameter named ar.
b. Assign to the existing variable named resultString of type string the
following value:
"Log written asynchronously, " + count.ToString()
5. To update the form’s control on the thread that originally created the
control, call the BeginInvoke method of the current Form1 object.
BeginInvoke takes a single parameter that is a delegate of type
MethodInvoker that refers to the current Form1 object’s
UpdateAsynchronousWriteStatus method.
4. Click Asynchronous Write, and note that the progress bar continues to
advance.
After a pause of 2 seconds, the following message is displayed in the status
bar:
“Log written asynchronously, 1”
5. Click Asynchronous Write, and note that after a pause of 2 seconds the
message in the status bar changes to:
“Log written asynchronously, 2”
6. Click Asynchronous Write twice in quick succession, and after the
message “Log written asynchronously, 4” is displayed in the status bar.
Click Stop Logger.
Note that the Logger State Indicator progress bar stops advancing and note
that the following message is displayed in the status bar:
“Logger stopped”
7. Use Visual Studio .NET to view the file Log.txt that was created in the same
folder as the multithreading application’s executable program:
<install folder>\Labs\Lab14\Starter\Multithreading\bin\Debug
You should see output that is similar to the following:
StartLogger - Time: 12:04:27 PM Wednesday, September 19,
2001
If Time Permits
Demonstrating a Race Condition
In this exercise, you will remove the lock in the WriteLog method of the
MyLogger class. You will note the errors resulting from the existence of a race
condition that occurs when multiple asynchronous calls cause multiple threads
to concurrently access the static variables of the MyLogger class.
7. Use Visual Studio .NET to view the file Log.txt that was created in the same
folder as the multithreading application’s executable program:
<install folder>\Labs\Lab14\Starter\Multithreading\bin\Debug
You should see output that is similar to the following:
StartLogger - Time: 12:40:24 PM Wednesday, September 19,
2001
Note Because of the race condition during the last two asynchronous
writes, the write counter is the same for both of these writes.
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Introduction to Threading
Lead-in ! Using Threads in .NET
The review questions cover
some of the key concepts ! Thread Safety
taught in the module.
! Special Thread Topics
! Asynchronous Programming in .NET
2. Write the code to execute a thread on the static method in a class named
MyClass that is declared: static void MyMethod().
Thread t1 = new
Thread(new ThreadStart(MyClass.MyMethod));
t1.Start();
5. In the second part of an asynchronous call operation, name the four ways
that the caller can know when the asynchronous operation has completed.
Callback method, poll, call end method, wait for event.
THIS PAGE INTENTIONALLY LEFT BLANK
Module 15 (Optional):
Interoperating Between
Managed and
Contents
Unmanaged Code
Overview 1
Integration Services 2
Platform Invoke 7
Lab 15.1: Calling Win32 APIs 16
Calling COM Objects from Managed Code 20
Lab 15.2: Calling COM Objects 39
Calling .NET Objects from COM Objects 43
Review 55
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, places or events is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code iii
Instructor Notes
Presentation: After completing this module, students will be able to:
90 Minutes
! State the need for interoperability between Microsoft® .NET assemblies and
Lab: COM components.
60 Minutes
! Use platform invoke to call a function in a dynamic-link library (DLL).
! Expose the methods and properties of a COM object to an assembly.
! Describe the three ways to generate runtime callable wrappers.
! Use Microsoft Visual Studio® .NET to call a COM object.
! Use the Type Library Importer to generate metadata from a type library.
! Expose the methods and properties of a .NET Framework class to a COM
client.
! Use the Type Library Exporter to generate a type library for an assembly.
! Use the ClassInterfaceAttribute to control and modify the type of interface
that is generated for a .NET Framework class.
Required Materials
To teach this module, you need the Microsoft PowerPoint® file 2349B_15.ppt.
Preparation Tasks
To prepare for this module, you should:
! Read all of the materials for this module.
! Complete the lab.
iv Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
Demonstrations
The following demonstrations are used to show how to create a managed
assembly from an unmanaged DLL file, and how to create a COM component
from a managed assembly.
In this module, use a Visual Studio .NET Command Prompt window to obtain a
command prompt window with the appropriate environment values that are
required for .NET tools.
In this demonstration, students will see how to use the Type Library Importer to
generate metadata for a DLL, and then use the metadata to create a managed
wrapper for the component.
2. Exit CalcUI.exe.
3. In a Visual Studio .NET Command Prompt window, run the Microsoft
intermediate language (MSIL) Disassembler on Calculator.dll by typing the
following command:
ildasm /adv Calculator.dll
Module Strategy
Use the following strategy to present this module:
! Integration Services
This module provides an introduction to COM interoperability and platform
invoke. Ensure that students understand the difference between calling an
API function that is implemented in a DLL and calling a COM component.
! Platform Invoke
Concentrate on the information in the slides titled “How Platform Invoke
Works” and “Calling Unmanaged Functions”.
! Calling COM Objects from Managed Code
Concentrate on the procedure for generating runtime callable wrappers, the
use of the type library importer, and the process for signature translation and
error handling.
! Calling .NET Objects from COM Objects
Ensure that students understand the export process when the Type Library
Exporter is used to generate a type library.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Integration Services
Lead-in ! Platform Invoke
In this module, you will learn
about interoperating ! Calling COM Objects from Managed Code
between managed and
unmanaged code. ! Calling .NET Objects from COM Objects
Note The ActiveX Control Importer (Aximp.exe) can be used to convert type
definitions in a COM type library for an ActiveX control into a Microsoft
Windows® Forms control. For additional information, see “Tools and
Debuggers; Windows Forms ActiveX Control Importer (Aximp.exe)” in the
.NET Framework SDK documentation.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code 3
In most cases, the standard RCW or CCW that is generated by the runtime
provides adequate marshaling for calls that cross the boundary between COM
and the .NET Framework. Using custom attributes, you can optionally adjust
the way the runtime represents managed and unmanaged code.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code 7
If the DLL has both an ANSI and a Unicode implementation of the same
function, then the CharSet parameter specifies which version of the function is
called.
10 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
There are two general approaches when declaring methods that match
unmanaged functions:
! You can declare the method to call the unmanaged DLL without providing
any implementation for the method, as shown in the following example:
using System;
using System.Runtime.InteropServices;
…
[DllImport("msvcrt.dll", CharSet=CharSet.Ansi)]
public static extern int puts(String str);
…
static void Main()
{
String Str = "Hello World!";
puts(Str);
}
The compiler uses the method declaration to generate the metadata that the
runtime needs to locate and correctly marshal the call to the DLL. When
declaring the method in your managed code, you can substitute the
equivalent runtime types for the function’s types. In the previous example, a
string object is substituted for a character string.
! You can also declare a .NET Framework class that is a collection of
declarations for an API exported by an unmanaged DLL. The advantage of
creating such a class is that you do not have to declare and annotate the
methods for the unmanaged DLL that you want to call in all the applications
that you create. After it is created, you can include the class in your
application, and you can call the unmanaged functions that are declared in
the class as if they were .NET Framework methods.
Pinning
Topic Objective
To define pinning.
Lead-in ! Data Is Temporarily Locked in Its Current Memory
When data is marshaled Location to Keep It from Being Relocated by the
between managed and Common Language Runtime’s Garbage Collector
unmanaged code, it can
either be copied from one
! Pinning Is Performed When Data Has to Be Passed
memory location to another,
Between Managed and Unmanaged Code and
or it can be pinned. # Has a fixed layout and common data representation in
both managed and unmanaged memory
- or -
# Has a fixed layout but the data representation is different
in managed and unmanaged memory and the class is
marshaled by reference
Marshaling
Topic Objective
To describe how
marshalling is performed by
platform invoke. ! Platform Invoke Marshals Simple Data Types Between
Managed and Unmanaged Code
Lead-in
Platform invoke ! Custom Marshalling Can Be Specified by Using the
automatically marshals data MarshalAs Attribute
between unmanaged types
and managed types.
public
public static
static extern
extern int
int MessageBoxW(
MessageBoxW(
int h,
int h,
[MarshalAs(UnmanagedType.LPWStr)]
[MarshalAs(UnmanagedType.LPWStr)] string
string m,
m,
…);
…);
HANDLE int
BYTE byte
SHORT short
WORD ushort
INT int
UINT uint
LONG int
ULONG uint
BOOLEAN int
CHAR char
LPSTR (and most other string types) String for in, StringBuilder for inout
FLOAT float
DOUBLE double
For example, the GetUserNameEx Win32 API function has the following
declaration:
BOOLEAN GetUserNameEx(
EXTENDED_NAME_FORMAT NameFormat, // name format
LPTSTR lpNameBuffer, // name buffer
PULONG nSize // size of name buffer
);
To call this from managed code, you would use the following declaration:
[DllImport("secur32.dll", CharSet=CharSet.Auto)]
public static extern int GetUserNameEx (int nameFormat,
StringBuilder userName, ref uint userNameSize);
Objectives
After completing this lab, you will be able to call a Win32 API from managed
code.
Exercise 1
Calling a Win32 API from Managed Code
In this exercise, you will call Win32 APIs from managed code. This includes
adding DllImport attributes to methods in your class, and then invoking those
methods. The first unmanaged function you call retrieves the user name, and the
second unmanaged function you call displays the user name in a message box.
! Open the Visual Studio .NET project for this exercise and examine the
application UI
1. In Microsoft Windows® Explorer, move to <install folder>\Labs\
Lab15\Lab15.1\Starter.
2. Double-click CallingUnmanagedCode.csproj to open the project for this
exercise in Visual Studio .NET.
3. In the Solution Explorer pane, double-click ManagedCode.cs. The UI
design for the Windows Forms application appears. Examine the UI for a
moment to become familiar with it.
4. Press F7 to edit the code that implements the Windows Form application.
! Add the DllImport attribute for the method used to retrieve the user
name
• GetUserNameEx is the Win32 API to be called. The signature for this
function is as follows:
BOOLEAN GetUserNameEx(
EXTENDED_NAME_FORMAT NameFormat, // name format
LPTSTR lpNameBuffer, // name buffer
PULONG nSize // size of name buffer
);
For information about the managed data types to use in your method
declaration, see Marshaling earlier in this module. Notice that you can use
the task list tab in the lower-left hand pane to find the ‘TODO’ comments.
Click View, click Show Tasks, and then click All if the ‘TODO’ comments
do not appear in the task list.
18 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
! Add the DllImport attribute for the method used to display the user
name
• MessageBox is the Win32 API to be called. The signature for this function
is as follows:
int MessageBox(
HWND hWnd, // handle to owner window
LPCTSTR lpText, // text in message box
LPCTSTR lpCaption, // message box title
UINT uType // message box style);
In the ManagedCode.cs file, notice the next ‘TODO’ comment near the
beginning, instructing you to add the declaration for a method that is used to
call MessageBox. Add the declaration for the method, including the
DllImport attribute. Your method should also be named MessageBox.
Some key information you need in order to add the declaration is listed in
the following table.
Information Value
For information about the managed data types to use in your method
declaration, see Marshaling earlier in this module. Notice that the strings
passed to MessageBox are input-only parameters.
3. On the Debug menu, click Start, and then click Retrieve User Name. The
user name should be displayed in a message box. Click OK to dismiss the
message box.
4. To close the application, click Exit.
20 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
The runtime callable wrapper also consumes the interfaces listed in the
following table.
Interface Description
Visual Studio .NET generates an assembly containing metadata when you add a
reference to a specific type library.
Adding the /out: switch produces an assembly with an altered name, such as
Loanlib_RCW.dll. Altering the runtime callable wrapper assembly name can
help distinguish it from the original COM DLL. The following example uses
the /out: switch of the Type Library Importer to alter the generated assembly’s
name:
tlbimp Loanlib.dll /out: Loanlib_RCW.dll
In the previous example, inputFile is the name of the file that contains the COM
type library. This file can be either a stand-alone type library (.TLB) file or a
DLL. The following command imports a type library file and generates a .NET
assembly named myTest.dll:
tlbimp myTest.tlb
26 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
The /out: option specifies the name of the assembly that is created as a result of
running the Type Library Importer. The following command creates
myNewTest as a DLL:
tlbimp myTest.tlb /out:myNewTest.dll
If the output assembly’s file name is equivalent to the input type library’s file
name, the Type Library Importer will generate an error, because the input file
cannot be overwritten.
The /delaysign option delays signing of the assembly. The /delaysign option
must be used with the /keycontainer:, /keyfile:, or /publickey: option. For a
complete list of all the options that can be used with the Type Library Importer,
see “Type Library Importer (Tlbimp.exe)” in the .NET Framework SDK
documentation.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code 27
Threading Models
Topic Objective ! COM Components Use Apartments to Synchronize Access to
To describe the threading Managed Resources
models in managed and
unmanaged code. ! Runtime Creates/Initializes Apartment When Calling a COM Object
using
using System.Threading;
System.Threading;
Lead-in
The threading models that using
using APTOBJLib;
APTOBJLib;
are supported by COM ……
components and the .NET Thread.CurrentThread.ApartmentState
Thread.CurrentThread.ApartmentState ==
Framework are different. ApartmentState.STA;
ApartmentState.STA;
While managed objects use AptSimple
AptSimple obj
obj == new
new AptSimple
AptSimple ();
();
synchronized regions… obj.Counter
obj.Counter == 1;
1;
! To ensure that the main thread of an application is STA
……
[STAThread]
[STAThread]
static
static void
void Main()
Main()
……
The following table lists the ApartmentState enumeration values and shows
the comparable COM apartment initialization call.
ApartmentState
enumeration value COM apartment initialization
Whenever the COM object and the managed thread are in incompatible
apartments, all calls on the object are made through a COM created proxy. For
example, calls between Windows Forms controls whose COM objects must
reside in an STA and managed code whose thread’s ApartmentState is MTA.
The following example shows how to create an STA apartment-threaded COM
object, AptSimple, from managed code:
using System.Threading;
using APTOBJLib;
…
AptSimple obj = new AptSimple ();
obj.Counter = 1;
A thread can only initialize a COM apartment once. Since the runtime
initializes the apartment before making the very first call to unmanaged code on
that thread, you should set the ApartmentState as early as possible. Changing
the ApartmentState after the apartment has been initialized has no effect. You
can neither un-initialize nor re-initialize an apartment. In some situations, the
thread may already have called into unmanaged code before the ApartmentState
could be set. In such cases, you cannot change the apartment type after the
thread is initialized. Your only option is to create a new thread.
As an alternative to setting the ApartmentState enumeration, you can apply
the System.STAThreadAttribute or System.MTAThreadAttribute to the
main entry point of the application. By applying these attributes you ensure that
the main thread of an application is in the proper state. For example:
…
[STAThread]
static void Main()
…
After setting the apartment state, you can check the state programmatically, as
in the following example:
Thread.CurrentThread.ApartmentState = ApartmentState.STA;
if (Thread.CurrentThread.ApartmentState == ApartmentState.STA)
//STA apartment state
else
//incompatible apartment state
30 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
Unmanaged signature:
short DoSomething ([in] short i);
32 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
Marshaling
Topic Objective
To describe how COM types ! Wrappers perform data marshaling
relate to .NET Framework # Support for marshaling data to and from COM almost
types and classes. always provides the correct marshaling behavior
Lead-in
Types used in COM have ! Table shows corresponding COM and C# types
corresponding .NET ! MarshalAsAttribute to change the marshaling behavior
Framework built-in value
types or classes.
public
public void
void M1
M1
([MarshalAs(UnmanagedType.LPWStr)]String
([MarshalAs(UnmanagedType.LPWStr)]String msg);
msg);
Direct students to the
Student Notes and explain
! Two ways to customize the RCW to handle types
that the table that is referred # Edit the interop assembly
to in the slide may be found
in the Student Notes. # Create a wrapper manually
The following table shows data types used in COM and their corresponding
.NET Framework built-in value types or classes. Any type not explicitly
identified in this table is converted to an Int32 system type.
COM value type COM reference type C# Data Type
The following table lists COM value and reference types that convert to
corresponding element types. For example, a COM coclass automatically maps
to a managed class with the same name.
COM value type COM Reference type Element type
If you must customize the runtime callable wrapper with additional or different
marshaling instructions, you can either:
1. Edit the interop assembly, searching for problematic syntax and replacing it
with alternative syntax.
This option is best for minor marshaling changes.
2. Create a wrapper manually, based on an existing Interface Definition
Language (IDL) file or type library.
Declaring COM types manually is a difficult activity that requires working
knowledge of the Type Library Importer (Tlbimp.exe), the default behavior
of the interop marshaler, and COM. This approach is best used when you
have an entire library of specialized types or require the RCW source code.
For more information about implementing these choices, see the .NET
Framework Software Development Kit (SDK) documentation.
36 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
Best Practices
Topic Objective
To list some best practices
to be followed when calling
COM components from ! The MSIL Disassembler can be used on the generated
managed code. assembly to determine the exact names of the
namespace and classes that are generated
Lead-in
Let’s look at some best ! Any parameter passed by reference in C++ or
practices that you should Visual Basic 6.0 will generate a parameter that needs
use when calling COM to be passed by using the ref keyword in C#
components from managed
code.
Objectives
After completing this lab, you will be able to call a COM object from managed
code.
Exercise 1
Calling a COM Object From Managed Code
In this exercise, you will call a COM object from managed code. This includes
registering the COM DLL, adding a reference to the COM object in a
Visual Studio .NET project, and then adding code to call the COM object.
! Open the Visual Studio .NET project for this exercise and examine the
application UI
1. In Windows Explorer, move to <install folder>\Labs\Lab15\Lab15.2\
Starter.
2. Double-click CallingComFromDotNet.csproj to open the project for this
exercise in Visual Studio .NET.
3. In the Solution Explorer pane, double click CalcUI.cs. The UI design for
the Windows Forms application appears. Examine the UI for a moment to
become familiar with it.
4. Press F7 to edit the code that implements the Windows Form application.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code 41
! Add the reference to the COM object and attempt to build the project
1. On the Project menu, click Add Reference.
2. In the Add Reference dialog box, click the COM tab. In the list of
registered COM objects, click VBUnmanagedCalculator.
3. To add VBUnmanagedCalculator to the Selected Components window,
click Select.
4. To add the reference, click OK. Notice that the VBUnmanagedCalculator
DLL is added to the project references.
5. On the Build menu, click Build Solution. Your application does not build
successfully yet, but the runtime callable wrapper assembly for the
VBUnmanagedCalculator.dll is generated.
6. In a Visual Studio .NET Command Prompt window, change the current
folder to <install folder>\Labs\Lab15\Lab15.2\ Starter\bin\Debug.
7. To view the metadata in the runtime callable wrapper assembly, at the
command prompt, type ildasm /adv Interop.VBUnmanagedCalculator.dll
Use the MSIL Disassembler to view the namespace and classes created for
the COM object.
3. On the Debug menu, click Start. When the calculator appears, check the
version number. It should read “Calculator – VB6 Unmanaged Component”.
Enter some equations to test the application.
4. Close the application.
Note If you wish to test the solution project, you will first need to follow the
steps in the “Register the COM object”, “Open the Visual Studio .NET project
for this exercise and examine the application UI”, and “Add the reference to the
COM object and attempt to build the project” procedures above.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code 43
Caution If you plan to export a managed object, be aware that the COM client
determines the apartment of the object. A managed object called by a COM
client initialized in an MTA must ensure thread safety.
46 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
Note You cannot use the Type Library Exporter to produce a type library from
an assembly that was imported by using the Type Library Importer
(Tlbimp.exe). Instead, you should refer to the original type library that was
imported with the Type Library Importer. You can export a type library from an
assembly that references assemblies that were imported by using the Type
Library Importer.
You must use the Type Library Exporter to generate a type library for an entire
assembly and not just a subset of the types that are defined in the assembly. A
single assembly may cause several type libraries to be generated, and these type
library files are placed in the current working directory or the directory
specified for the output file when running the Type Library Exporter.
The Type Library Exporter generates a type library but does not register the
types it exports with the system registry. To generate and register a type library
with COM, use the Assembly Registration tool (Regasm.exe). For information
about using the Assembly Registration tool to register a type library, see
Registering a .NET Framework class with the System Registry in this module.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code 47
When a COM client attempts to load the assembly in which the class is
implemented, the runtime reads the assembly value from the registry and passes
it on to the runtime assembly resolver. The assembly resolver attempts to locate
the assembly based on the assembly information, such as the name and version
number. Before the assembly resolver can locate the assembly, however, the
assembly must be signed and installed in the global assembly cache, or it must
be in the application’s root directory or a subdirectory of the application’s root
directory.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code 49
In the preceding example, COM clients can access the LoanApp class only
through the IExplicit interface.
50 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
To avoid breaking late-bound COM clients when using the class interface, set
the Value property of the ClassInterfaceAttribute to
ClassInterfaceType.AutoDispatch. This value implements a dispatch-only
class interface, but omits the interface description from the type library.
Without an interface description, clients are unable to cache dispatch identifiers
(DISPIDs) at compile time. Although this is the default interface type for the
class interface, you can apply the attribute value explicitly, as shown in the
following example:
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class LoanApp : IAnother
{
void M();
}
To get the DISPID of an interface member at run time, COM clients can call
IDispatch.GetIdsOfNames. To invoke a method on the interface, pass the
returned DISPID as an argument to IDispatch.Invoke.
A dual interface that is automatically generated (ClassInterface.AutoDual)
might be appropriate in rare cases. However, a dual interface that is
automatically generated often creates version-related complexities. For
example, COM clients that are using the class interface of a derived class can
easily break when there are changes to the base class. When a third party
provides the base class, the layout of the class interface is out of your control.
Further, unlike a dispatch-only interface, a dual interface provides a description
of the class interface in the exported type library. Such a description encourages
late-bound clients to cache DISPIDs at run time.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code 51
4. Use the methods and properties of the class, as shown in the following
example:
Dim Count As Integer
Count = Server.Count
To use a .NET Framework class from a Microsoft Visual C++® 6.0 application,
use the #import directive to reference the type library, as shown in the
following example:
#import "c:\Samples\SampleClassLibrary\SampleClassLib.tlb"
52 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
Best Practices
Topic Objective
To list some best practices
when using managed
classes from COM clients. ! Define an Explicit Interface for COM Clients to Use
Rather Than Generating the Class Interface
Lead-in
When exposing managed ! Avoid Caching Dispatch Identifiers
code to COM clients, follow
the best practices listed on ! Restrict Using the Dual Interface Option for the Class
the slide. Interface
To avoid breaking late-bound COM clients when using the class interface,
set the Value property of the ClassInterfaceAttribute to
ClassInterfaceType.AutoDispatch. This value implements a dispatch-only
class interface, but it omits the interface description from the type library.
Without an interface description, clients are unable to cache DISPIDs at
compile time. Although this is the default interface type for the class
interface, you can apply the attribute value explicitly.
! Restrict using the dual interface option for the class interface.
Dual interfaces enable early and late binding to interface members by COM
clients. At design time and during testing, you might find it useful to set the
class interface to dual. For a managed class and its base classes that will
never be modified, this option is also acceptable. In all other cases, avoid
setting the class interface to dual.
Module 15 (Optional): Interoperating Between Managed and Unmanaged Code 55
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Integration Services
Lead-in ! Platform Invoke
The review questions cover
some of the key concepts ! Calling COM Components from Managed Code
taught in the module.
! Calling .NET Objects from COM Objects
2. What is pinning?
Pinning is a technique in which data, in its current memory location, is
temporarily locked to keep it from being relocated by the common
language runtime’s garbage collector.
3. List the tasks that are performed when the Type Library Importer is run on a
type library file.
The Type Library Importer converts unmanaged COM coclasses to C#
classes with a constructor (that does not have parameters) and no other
methods, converts unmanaged COM vtable interfaces to C# interfaces,
and converts unmanaged COM structures to C# structures with public
fields.
4. Which attribute must you use to suppress runtime security checks that are
preformed when managed code calls unmanaged code?
SuppressUnmanagedCodeSecurityAttribute
56 Module 15 (Optional): Interoperating Between Managed and Unmanaged Code
5. List some best practices when using .NET code from COM clients.
Define an explicit interface for COM clients to use rather than
generating the class interface, and avoid caching dispatch identifiers
(DISPIDs).
6. Which must you use to prevent the class interface from being generated?
Set the Value property of the ClassInterfaceAttribute to
ClassInterfaceType.None
Module 16 (Optional):
Using Microsoft
ADO.NET to Access
Contents
Data
Overview 1
Overview of ADO.NET 2
Connecting to a Data Source 10
Accessing Data with DataSets 12
Using Stored Procedures 26
Lab 16: Using ADO.NET to Access Data 34
Accessing Data with DataReaders 42
Binding to XML Data 50
Review 56
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, places or events is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 16 (Optional): Using Microsoft ADO.NET to Access Data iii
Instructor Notes
Presentation: This module focuses on using ADO.NET to access data from various data
120 Minutes sources.
Lab: After completing this module, students will be able to:
60 Minutes
! Describe the ADO.NET object model.
! Connect to a data source by using ADO.NET.
! Retrieve data from a database by using DataReaders and DataSets.
! Display the data from a database on the client by using DataGrid controls.
! Use stored procedures to read data from a data source.
! Read data from an XML file into DataSets.
Required Materials
To teach this module, you need the Microsoft® PowerPoint® file 2349B_16.ppt.
Preparation Tasks
To prepare for this module, you should:
! Read all of the materials for this module.
! Complete all of the demonstrations.
! Complete the lab.
! Go through the animation.
iv Module 16 (Optional): Using Microsoft ADO.NET to Access Data
Multimedia Presentation
This section provides multimedia presentation procedures that do not fit in the
margin notes or are not appropriate for the student notes.
Start animation There are two ways to access data from a database by using
ADO.NET: by using a DataSet or by using a DataReader.
This animation demonstrates how these two methods work
and highlights their differences.
Click Start
Click DataSet The DataSet method is a disconnected way to access data
from a database.
In this method, when a user requests data from a database, the
DataAdapter object is used to create a DataSet, which is
basically a collection of data tables from the database that
also retains the relationships between these tables. Notice
that, after a DataSet is populated, it is disconnected from the
database.
To display the data from the DataSet, you set up a DataView
for the desired table. The DataView is then bound to a list-
bound control for displaying purposes. You can use any of
the three list-bound controls, DataGrid, Repeater, or
DataList, to display data.
The data in the list-bound control is then displayed on the
client.
An important point to make here is that the use of a
DataView to display data is necessary only in ASP.NET
Beta 1. From the Beta 2 version onward, you can directly
bind the DataSet to a list-bound control.
Click DataReader This method is similar to the Microsoft ActiveX® Data
Objects (ADO) way of accessing data by using recordsets.
In this method, when a user requests data from a database, the
Command object retrieves the data into a DataReader. A
DataReader is a read-only/forward-only view of the data. A
DataReader works similarly to a Recordset in ADO,
allowing you to simply loop through the records. Like the
ADO Recordset, the DataReader is connected to the
database. You must explicitly close the connection when you
are finished reading data.
Module 16 (Optional): Using Microsoft ADO.NET to Access Data v
Module Strategy
Use the following strategy to present this module:
! Overview of ADO.NET
This section provides students with an overview of ADO.NET. The section
begins a description of the objects used when connecting to a database both
with a DataReader and a DataSet. Point out to students that there are
Microsoft SQL Server™ and ADO versions of many of these objects. After
describing the process of accessing data through a DataReader and a
DataSet, show the animation. Because students may be familiar with ADO,
this may be an ideal time to discuss some of the main differences between
ADO and ADO.NET.
When talking about using namespaces, explain their significance to the
students.
! Connecting to a Data Source
From this point onward, students will actually start working with
ADO.NET. Tell them that all of the examples in this module use
SqlConnection objects rather than OleDbConnection objects. Direct the
students to the Microsoft .NET Framework software development kit (SDK)
documentation for more information.
! Accessing Data with DataSets
ADO.NET provides two ways to access data, the DataSet and the
DataReader. This section focuses on accessing data by using the DataSet.
The DataSet represents a new concept, so spend additional time on this
section. The demonstrations actually show every aspect of data access with
ADO.NET. Go through the demonstrations carefully, and make sure that the
students understand the details.
! Using Stored Procedures
Most students who have worked with a SQL Server database and ADO will
have experience with using stored procedures. This section provides the
students with information about how to use stored procedures and
parameterized stored procedures with ADO.NET.
! Lab16: Using ADO.NET to Access Data
The lab for this module is encountered in the middle of the module. This is
because the module is long and also because the lab does not use material
from the last two sections in the module.
vi Module 16 (Optional): Using Microsoft ADO.NET to Access Data
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Overview of ADO.NET
Lead-in ! Connecting to a Data Source
In this module, you will learn
about the data binding ! Accessing Data with DataSets
features in ASP.NET.
! Using Stored Procedures
! Accessing Data with DataReaders
! Binding to XML Data
DataSet List-Bound
List-Bound
Control
Control
.ASPX Page
Connection Objects
Connection objects are used to talk to databases. They have properties, such as
DataSource, UserID, and Password, which are needed to access a particular
DataSource. Commands travel over connections, and result sets are returned in
the form of streams that can be read by DataReaders or pushed into DataSet
objects.
There are two kinds of connection objects in ADO.NET: SqlConnection and
OleDbConnection.
Command Objects
Command objects contain the information that is submitted to a database. A
command can be a stored procedure call, an update statement, or a statement
that returns results. You can also use input and output parameters and return
values. In ADO.NET, you can use two kinds of command objects:
SqlCommand and OleDbCommand.
4 Module 16 (Optional): Using Microsoft ADO.NET to Access Data
DataReader Objects
A DataReader is somewhat synonymous with a read-only/forward-only view
of the data. The DataReader API supports flat as well as hierarchical data. A
DataReader object is returned after executing a command against a database. It
works similarly to a recordset in ADO; however the format of the returned
DataReader object is different from a recordset. For example, you may use the
DataReader to show the results of a search list in a Web page.
ADO.NET includes two types of DataReader objects: the SqlDataReader for
Microsoft SQL Server™ version 7.0 (or later) data, and the OleDbDataReader
for ADO data. The DataReader object is database-specific. The behavior of the
SqlDataReader may differ from the behavior of the OleDbDataReader and
additional DataReader objects that are introduced in the future.
You use the OleDbCommand and SqlCommand objects and the
ExecuteReader method to transfer data into a DataReader.
DataSet Objects
The DataSet object is similar to the ADO Recordset object, but more
powerful, and with one other important distinction: the DataSet is always
disconnected. The DataSet provides a rich object model to work with when
passing data between various components of an enterprise solution. The
DataSet object represents a cache of data, with database-like behavior. It
contains tables, columns, relationships, constraints, and data. Data coming from
a database, an XML file, code, or user input can be entered into DataSet objects
and converted into files, forms, or databases. The behavior of a DataSet is
completely consistent regardless of the underlying database, SQL Server or
OLE DB. As changes are made to the DataSet, they are tracked in a way
similar to the way changes are tracked in a word processing document.
The DataSet object has a collection of DataTable objects. A DataTable
represents one table of in-memory data. It contains a collection of columns that
represents the table's schema. A DataTable also contains a collection of rows,
representing the data contained in the table.
You use the OleDbDataAdapter and SqlDataAdapter objects and the Fill
method to get data into a DataSet.
DataView Objects
A DataView enables you to create different views of the data stored in a
DataTable, a capability that is often used in data-binding applications. By
using a DataView, you can expose the data in a table with different sort orders,
and you can filter the data by row state or based on a filter expression.
A DataView provides a dynamic view of data whose content, ordering, and
membership reflect changes to the underlying DataTable as they occur. This is
different from the Select method of the DataTable, which returns a DataRow
array from a table per a particular filter and/or sort order, and whose content
reflects changes to the underlying table, but whose membership and ordering
remain static. The dynamic capabilities of the DataView make it ideal for data-
binding applications.
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 5
DataAdapter Object
While the DataSet object provides a tool for in-memory data storage, you need
another tool to create and initialize the various tables. This tool is the
DataAdapter object. It represents a centralized console that hides the details of
working with connections and commands. The DataAdapter object allows for
the retrieval and saving of data between a DataSet object and the source data
store. It is responsible for pulling out data from the physical store and pushing it
into data tables and relations. The DataAdapter object is also responsible for
transmitting any update, insertion, or deletion to the physical database. You can
use four command objects to make any updates: UpdateCommand,
InsertCommand, DeleteCommand, and SelectCommand.
The DataAdapter object exists in two forms: SqlDataAdapter objects and
OleDbDataAdapter objects. The data source is SQL Server for
SqlDataAdapter objects and any other OLE DB provider for
OleDbDataAdapter objects.
The following illustration shows the use of a SQLDataAdapter object to
transfer data between a SQL Server database and a DataSet object.
6 Module 16 (Optional): Using Microsoft ADO.NET to Access Data
Number of Tables
An ADO recordset looks like a single table. If a recordset is to contain data
from multiple database tables, it must use a JOIN query, which assembles the
data from the various database tables into a single result table.
In contrast, an ADO.NET DataSet is a collection of one or more tables. The
tables within a data set are called data tables; specifically, they are DataTable
objects.
8 Module 16 (Optional): Using Microsoft ADO.NET to Access Data
Relationships
Typically, a DataSet also contains relationships. A relationship within a
DataSet is analogous to a foreign-key relationship in a database. In ADO.NET,
a DataRelation represents the relationship.
Data Connections
In ADO.NET, the DataSet provides disconnected access to database data. In
ADO, the recordset can provide disconnected access, but is typically used to
provide connected access.
Transmitting Data
To transmit an ADO disconnected recordset from one component to another,
you use COM marshalling. To transmit an ADO.NET data set, you simply
transmit an XML file. Because components exchange ADO.NET datasets by
using XML, firewalls can allow datasets to pass.
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 9
Using Namespaces
Topic Objective
To describe the new
namespaces used with
ADO.NET. ! Namespaces Used with ADO.NET Include:
Lead-in # System.Data
In.NET, you must specify
the namespace that you # System.Data.OleDb
want to use.
# System.Data.SqlClient
# System.Data.SqlTypes
! Using OleDbConnection
OleDbConnection
OleDbConnection myOleDbConnection
myOleDbConnection == new
new
OleDbConnection("server=(local)\\NetSDK;
OleDbConnection("server=(local)\\NetSDK; !
!
Trusted_Connection=yes;database=northwind;
Trusted_Connection=yes;database=northwind; !
!
provider=sqloledb");
provider=sqloledb");
Using SqlConnection
The following code illustrates how to create and open a connection to a
Delivery Tip Microsoft SQL Server database by using the SqlConnection object.
Point out to students that in
ADO.NET you do not SqlConnection mySqlConnection = new
always need to explicitly SqlConnection("server=(local)\\NetSDK;!
open and close the
Trusted_Connection=yes;database=northwind");
connection to the database.
Using OleDbConnection
For the OLE DB Managed Provider, the connection string format is quite
similar to the connection string format used in OLE DB.
The following code illustrates how to create and open a connection to a
Microsoft SQL Server database by using OleDbConnection.
OleDbConnection myOleDbConnection = new
OleDbConnection("server=(local)\\NetSDK;!
Trusted_Connection=yes;database=northwind;!
provider=sqloledb");
Typed DataSet
Along with late bound access to values through weakly typed variables, the
DataSet provides access to data through a strongly typed metaphor. By using
user-friendly names and strongly typed variables, you can access tables and
columns that are part of the DataSet. You can also transport a strongly typed
DataSet by using an XML Web service.
A typed DataSet is a class that derives from a DataSet. As such, it inherits all
of the methods, events, and properties of a DataSet. Additionally, a typed
DataSet provides strongly typed methods, events, and properties. This means
that you can access tables and columns by name, instead of using collection-
based methods. Aside from the improved readability of the code, a typed
DataSet also allows the Microsoft Visual Studio® .NET code editor to
automatically complete lines as you type.
Additionally, a strongly typed DataSet provides access to the correct types for
values at compile time. With a strongly typed DataSet, type mismatch errors
are caught when the code is compiled rather than at run time.
Using an XML Schema that complies with the XML Schema definition
language (XSD) standard, you can generate a strongly typed DataSet by using
the XSD.exe tool that is provided with the .NET Framework SDK. The use of
this tool is outside the scope of this module.
You will see how to easily create and use a typed DataSet using Visual Studio
.NET in this module’s lab.
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 15
DataSet: Customers
Orders
Data Tables
Note You can store tables from different databases in the same DataSet.
The following code shows how you can add two tables from two different
queries, one for authors and the other for titles, to the same DataSet.
// create connection to database
string strConn =
"server=(local)\\NetSDK;!
Trusted_Connection=yes;database=northwind";
SqlConnection mySqlConnection = new SqlConnection(strConn);
Using DataViews
Topic Objective
To explain the role of
DataViews in accessing
data from a database by ! DataViews Can be Customized to Present a Subset of
using DataSets. Data from a DataTable
Lead-in ! The DefaultView Property Returns the Default DataView
To display data in a for the Table
DataSet, you can use a
DataView. DataView
DataView myDataView
myDataView ==
myDataSet.Tables["Customers"].DefaultView;
myDataSet.Tables["Customers"].DefaultView;
myDataView.Sort
myDataView.Sort == "Country";
"Country";
myDataView.RowFilter
myDataView.RowFilter == "Country
"Country == 'Argentina'";
'Argentina'";
Note The DataSet object contains a Tables collection. You reference the
DataTable you are interested in by name.
You can sort the data. For example, you can sort the customers by country.
myDataView.Sort = "Country";
18 Module 16 (Optional): Using Microsoft ADO.NET to Access Data
For more information about the properties of the DataView object, see the
Microsoft .NET Framework SDK documentation.
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 19
Before you can submit the update back to the database, you must set up the
InsertCommand, UpdateCommand, and DeleteCommand to reconcile the
changes to the database. For limited scenarios you can use the
SqlCommandBuilder to automatically generate those for you:
SqlCommandBuilder mySqlCommandBuilder = new
SqlCommandBuilder(mySqlDataAdapter);
20 Module 16 (Optional): Using Microsoft ADO.NET to Access Data
Because Fill will not cause primary key and unique key information to be
retrieved unless AddWithKey is specified, you must set the
MissingSchemaAction property to AddWithKey:
mySqlDataAdapter.MissingSchemaAction =
MissingSchemaAction.AddWithKey;
mySqlDataAdapter.Fill(myDataSet, "Customers");
DataRow myDataRow;
myDataRow = myDataSet.Tables["Customers"].NewRow();
The DataTable must return a DataRow through the NewRow method. The
method returns a DataRow object with the appropriate schema of the
DataTable. The new DataRow is independent of the table until it is added to
the RowsCollection.
myDataRow["CustomerId"] = "NewID";
myDataRow["ContactName"] = "New Name";
myDataRow["CompanyName"] = "New Company Name";
myDataSet.Tables["Customers"].Rows.Add(myDataRow);
To submit the data from the DataSet into the database, use the Update method
on the SqlDataAdapter.
mySqlDataAdapter.Update(myDataSet, "Customers");
You can change data in a DataRow by accessing the DataRow. You can use
the index of the row in the RowsCollection that is accessed through the Rows
property:
myDataSet.Tables["Customers"].Rows[0]["ContactName"]="Peach";
You can also access a specific row by the primary key value:
DataRow myDataRow1 =
myDataSet.Tables["Customers"].Rows.Find("ALFKI");
myDataRow1["ContactName"]="Peach";
The original and new values are maintained in the row. The RowChanging
event allows you to access both original and new values to decide whether you
want the edit to proceed. Because original and new values are maintained, you
can establish scenarios such as optimistic locking and key changes.
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 21
Tip You can examine the database tables and stored procedures by using the
Server Explorer window Data Connections entries.
22 Module 16 (Optional): Using Microsoft ADO.NET to Access Data
Regions:
ID: 1 Description: Eastern
ID: 2 Description: Western
ID: 3 Description: Northern
ID: 4 Description: Southern
DataView
DataView myDataView
myDataView ==
myDataSet.Tables["Customers"].DefaultView;
myDataSet.Tables["Customers"].DefaultView;
myDataView.RowFilter
myDataView.RowFilter == "Country
"Country == 'Argentina'";
'Argentina'";
dataGrid2.DataSource
dataGrid2.DataSource == myDataView;
myDataView;
Alternatively, you can use the Tables collection of the DataSet to assign the
DataTable directly to the DataSource of the DataGrid, as in the following
example:
dataGrid1.DataSource = myDataSet.Tables["Regions"];
If you want to display a different view of data in the DataGrid control, create a
new DataView object from the DataSet and bind that to the control. For
example, the following code will display only those customers in Argentina.
Note You can directly set the connection and command text when creating the
SqlDataAdapter object:
SqlDataAdapter mySqlDataAdapter = new
SqlDataAdapter(
"GetProducts", mySqlConnection);
You then set the CommandType property before you call the Fill method.
mySqlDataAdapter.SelectCommand.CommandType =
CommandType.StoredProcedure;
After you have filled a DataTable with the results of a Select stored procedure,
you can bind it to a list-bound control to display the data. For example, to bind
to a Windows Forms DataGrid control named dataGrid1:
dataGrid1.DataSource =
myDataSet.Tables["Products"];
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 29
Passing Parameters
Topic Objective
To show students how to ! Create Parameter, Set Direction and Value, Add to the
use parameterized stored Parameters Collection
procedures.
SqlParameter
SqlParameter workParam
workParam == new
new
Lead-in SqlParameter("@ProductName",SqlDbType.NChar,
When using Microsoft SqlParameter("@ProductName",SqlDbType.NChar, 40);
40);
SQL Server, or other
workParam.Direction
workParam.Direction ==
procedure-based
databases, you can use ParameterDirection.Input;
ParameterDirection.Input; //
// Input
Input is
is default
default
parameters to pass and workParam.Value = textBox1.Text;
workParam.Value = textBox1.Text;
retrieve information from the
database. mySqlDataAdapter.SelectCommand.Parameters.Add(
mySqlDataAdapter.SelectCommand.Parameters.Add(
workParam);
workParam);
Creating a Parameter
To create a parameter for the SqlDataAdapter object, create a new
SqlParameter object with the name and data type of the parameter. Next, set
the Direction property of the new parameter to indicate how the parameter is
used by the stored procedure. If the parameter is an input parameter, set the
Value property to specify the data that should be sent to the server.
For example, the GetProductData stored procedure takes one input parameter:
PROCEDURE GetProductData !
@ProductName nchar(40) as select * from Products !
where @ProductName = ProductName
After you have created the parameter, use the Add method of the Parameters
collection of the SelectCommand object. The Add method takes a
SqlParameter as an argument. If a stored procedure has more than one
parameter, it does not matter in which order you add them because you create
them by name.
mySqlDataAdapter.SelectCommand.Parameters.Add(workParam);
Use the Fill method to run the stored procedure and retrieve the records.
DataSet myDataSet = new DataSet();
mySqlDataAdapter.Fill(myDataSet,"ProductData");
// bind to a DataGrid
dataGrid.DataSource = myDataSet.Tables["ProductData"];
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 31
Because this stored procedure does not return a set of records, you do not need
to use a DataAdapter object. Instead, you can use a Command object directly,
and call the ExecuteNonQuery method to run the stored procedure.
To call this stored procedure, create an output parameter named
@ProductCount, add it to the Parameters collection of a Command object,
and then call ExecuteNonQuery to run the stored procedure:
SqlCommand mySqlCommand = new
SqlCommand("GetProductCount", mySqlConnection);
mySqlCommand.CommandType = CommandType.StoredProcedure;
Tip You can examine the database tables and stored procedures by using the
Server Explorer window Data Connections entries.
To create and execute a stored procedure that returns the product names of all
the entries in the Products table, click the Load Product Names button.
Typing a name in the text box that is labeled Enter Product Name allows you
to click on the Load Product Data button. This button creates and executes a
stored procedure that takes the product name as an input parameter and returns
all the fields of that product.
To create and execute a stored procedure that has an output parameter, which
gets set to the number of products in the database’s Products table, click the
Get Number of Products button.
34 Module 16 (Optional): Using Microsoft ADO.NET to Access Data
Lab Setup
Only solution files are associated with this lab. The solution files for this lab are
in the folder <installfolder>\Labs\Lab16\Solution.
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 35
Scenario
This lab is based on the Visual Studio .NET Framework SDK Walkthrough:
Creating a Distributed Application. In this lab, you will create a multi-tiered,
distributed application.
The application consists of three logical tiers: data, business object, and user
interface. The data tier is a SQL Server database. The business object tier
handles the tasks of accessing the data and distributing it to the clients. The user
interface tier consists of a Windows-based application.
You will create the Authors XML Web service and the Windows Client
Application. The following diagram shows the architecture of the distributed
application:
As part of the distributed application, you will build a simple data application
with look-up and update functionality. You will create an XML Web service to
retrieve data from the Authors table in the SQL Server Pubs sample database.
You will also build a Windows-based client application to display the results of
the query by the XML Web service. The communication between the client and
the XML Web service is handled by using HTTP and XML.
For this lab, the data has already been generated and is available in the Pubs
sample database. Therefore, you will begin by creating the business object, the
XML Web service, followed by building the Windows Form user interface.
Exercise 1
Creating the Middle-Tier Business Object
In this exercise, you will create a business object that runs on a Web server.
You will implement the business object as an XML Web service that holds the
data connections and dataset definition.
After first creating an ASP.NET Web Service project in Visual Studio .NET,
you will use the Visual Studio .NET design environment to add a data
connection, a data adapter, and a dataset class definition to the XML Web
service. You will add two methods to the XML Web service: GetAuthors,
which returns a dataset from the database, and UpdateAuthors, which updates
the database with changes from the user.
6. Find the authors node and expand it to show the fields in the authors table.
7. Using CTRL+Click, select the au_id, au_lname, au_fname, and city fields.
8. Drag these fields from Server Explorer onto the design surface.
A SqlConnection that is paired with a SqlDataAdapter appears in the
designer. A connection has now been created to the database, with the
transfer of information to be handled by the SqlDataAdapter. These
components are configured to move a dataset with the selected fields of the
authors table in and out of the database.
Exercise 2
Creating a Windows User Interface
In this exercise, you will create a Windows Forms client application. The
application consists of one Windows Form that contains a reference to
AuthorsWebService. The data in the database is displayed in a DataGrid
control when a Load button on the form is clicked.
To implement the display of data in the DataGrid, you call the XML Web
service’s GetAuthors method. The DataGrid control enables direct editing of
the data, with changes being passed directly to the underlying dataset.
In addition to a Load button, the form has a save button. The code for this
button calls the XML Web service's UpdateAuthors method to save the
changes back to the database.
XML Web service methods are called by first creating an instance of the
service class, and then calling the service methods. In this case, the
GetAuthors method is called. The dataset returned is merged with the
AuthorData dataset.
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 41
2. On the View menu, click Designer. Double-click the button labeled Save to
create an empty event handler for the Click event. Add the following code
to the SaveData_Click method:
private void SaveData_Click(
object sender, System.EventArgs e)
{
if (AuthorData.HasChanges())
{
AuthorsWinClient.localhost.AuthorsService
ws = new
AuthorsWinClient.localhost.AuthorsService();
ws.Credentials =
System.Net.CredentialCache.DefaultCredentials;
AuthorsWinClient.localhost.authors1 diffAuthors =
new AuthorsWinClient.localhost.authors1();
diffAuthors.Merge(AuthorData.GetChanges());
ws.UpdateAuthors(diffAuthors);
AuthorData.Merge(diffAuthors);
}
}
If there are changes in the dataset, a new dataset of type authors1 is created
to hold just the changed data. This dataset is then passed to the XML Web
service's UpdateAuthors method. The dataset is returned with the changes
accepted, and the AuthorData dataset is updated to reflect these new
changes.
If you do not require the functionality that is provided by the DataSet, you can
improve the performance of your application by using the DataReader to
return your data in a forward-only read-only fashion. Although the
DataAdapter uses the DataReader to fill the contents of a DataSet, by using
the DataReader instead, you can receive the following performance gains:
! The saving of memory that would be consumed by the DataSet.
! The saving of the processing that would be required to create and fill the
contents of the DataSet.
In this section, you will learn how to read data from a data source by using
DataReaders.
44 Module 16 (Optional): Using Microsoft ADO.NET to Access Data
Creating a DataReader
Topic Objective ! Create and Open the Database Connection
To describe how to retrieve
data from a database by SqlConnection
SqlConnection mySqlConnection
mySqlConnection == new
new
using a DataReader. SqlConnection("server=(local)\\NetSDK;
SqlConnection("server=(local)\\NetSDK; !
!
Trusted_Connection=yes;database=northwind");
Trusted_Connection=yes;database=northwind");
Lead-in mySqlConnection.Open();
You can also use a mySqlConnection.Open();
DataReader object to read ! Create the DataReader From a Command Object
data from a database.
SqlCommand
SqlCommand mySqlCommand
mySqlCommand == new
new SqlCommand(
SqlCommand(
"select
"select * from customers", mySqlConnection);
* from customers", mySqlConnection);
SqlDataReader
SqlDataReader myReader
myReader ==
mySqlCommand.ExecuteReader();
mySqlCommand.ExecuteReader();
if (mySqlConnection.State == ConnectionState.Open)
mySqlConnection.Close();
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 45
try
{
mySqlConnection.Open();
myReader = mySqlCommand.ExecuteReader();
//…
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
finally
{
if (myReader != null)
myReader.Close();
if (mySqlConnection.State == ConnectionState.Open)
mySqlConnection.Close();
}
46 Module 16 (Optional): Using Microsoft ADO.NET to Access Data
You can also reference the fields of data in the current record of the data reader
by name, and then call an appropriate conversion function, as shown in the
following example code:
string customerID = myReader["CustomerID"].ToString();
string companyName = myReader["CompanyName"].ToString();
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 47
if (mySqlConnection.State == ConnectionState.Open)
mySqlConnection.Close();
48 Module 16 (Optional): Using Microsoft ADO.NET to Access Data
Overview of XML
Topic Objective
To provide an overview of
XML data.
! Machine-Readable and Human-Readable Data
Lead-in
XML is a common language ! Defines the Data Content and Structure
used for exchanging
information between ! Separates Structure from Presentation
business applications.
! Allows You to Define Your Own Tags and Attributes
<employee>
<employee>
<name>Jake</name>
<name>Jake</name>
<salary>25000</salary>
<salary>25000</salary>
<region>Ohio</region>
<region>Ohio</region>
</employee>
</employee>
Note You cannot read XML data into a DataReader. You can read it only into
a DataSet.
For XML data, the DataSet supports a ReadXml method that takes a
FileStream as its parameter. The DataSet expects data to be in the following
format:
<DocumentElement>
<TableName>
<ColumnName1>column value</ColumnName1>
<ColumnName2>column value</ColumnName2>
<ColumnName3>column value</ColumnName3>
</TableName>
<TableName>
<ColumnName1>column value</ColumnName1>
<ColumnName2>column value</ColumnName2>
<ColumnName3>column value</ColumnName3>
</TableName>
</DocumentElement>
The following example shows how to read the schema and data from an XML
file by using the ReadXml method, the FileStream object, and the
StreamReader object. Note that after the data is read into the DataSet, it is
indistinguishable from SQL data—the DataGrid binds to it in the same way.
You can perform the following steps to read a file named myFile.xml that
contains XML data and displays it in a DataGrid.
First open the XML file and create a StreamReader:
FileStream fs = File.OpenRead("myFile.xml");
StreamReader myStreamReader = new StreamReader(fs);
After the data has been read into a DataSet, the repeated elements in the XML
become the columns in the DataSet and can be bound to any control to be
displayed on the client.
The Windows Forms code, including try/catch/finally blocks, that is used in
Demonstration: Reading XML Data into a DataSet, is as follows:
StreamReader myStreamReader = null;
statusBar1.Text = "";
try
{
FileStream fs = File.OpenRead(textBox1.Text);
myStreamReader = new StreamReader(fs);
DataSet myDataSet = new DataSet();
myDataSet.ReadXml(myStreamReader);
dataGrid1.DataSource = myDataSet.Tables[0];
statusBar1.Text = "Read file: " + textBox1.Text;
}
catch(Exception exception)
{
statusBar1.Text = exception.ToString();
}
finally
{
if (myStreamReader != null) myStreamReader.Close();
}
Module 16 (Optional): Using Microsoft ADO.NET to Access Data 55
Review
Topic Objective
To reinforce module
objectives by reviewing key
points. ! Overview of ADO.NET
Lead-in ! Connecting to a Data Source
The review questions cover
some of the key concepts ! Accessing Data with DataSets
taught in the module.
! Using Stored Procedures
! Accessing Data with DataReaders
! Binding to XML Data
Contents
Overview 1
Overview of Attributes 2
Defining Custom Attributes 13
Retrieving Attribute Values 22
Demonstration: Custom Attributes 26
Lab 17: Defining and Using Attributes 27
Review 36
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, places or events is intended or should be inferred. Complying with all applicable
copyright laws is the responsibility of the user. Without limiting the rights under copyright, no
part of this document may be reproduced, stored in or introduced into a retrieval system, or
transmitted in any form or by any means (electronic, mechanical, photocopying, recording, or
otherwise), or for any purpose, without the express written permission of Microsoft Corporation.
Microsoft may have patents, patent applications, trademarks, copyrights, or other intellectual
property rights covering subject matter in this document. Except as expressly provided in any
written license agreement from Microsoft, the furnishing of this document does not give you any
license to these patents, trademarks, copyrights, or other intellectual property.
The names of actual companies and products mentioned herein may be the trademarks of their
respective owners.
Module 17 (Optional): Attributes iii
Instructor Notes
Presentation: Teach this module if time permits. Module 17 is a stand-alone module that is
60 Minutes not dependent upon any other module.
Lab: This module provides students with the details about how to use attributes in
45 Minutes code. It describes the predefined attributes that are provided by the Microsoft®
.NET Framework and provides some simple examples of how to use some
common attributes. The concept of custom attributes is introduced. This
introduction is followed by a detailed explanation of how to define and use
custom attributes. The process used to compile code that has custom attributes
is also explained. Finally, the module describes how to retrieve attribute values
during run time by using reflection. The procedure that is used to retrieve
attribute information into an array and query the array to obtain the required
values is explained.
After completing this module, students will be able to:
! Use common predefined attributes.
! Create simple custom attributes.
! Query attribute information at run time.
Required Materials
To teach this module, you need Microsoft PowerPoint® file 2349B_17.ppt.
Preparation Tasks
To prepare for this module, you should:
! Read all of the materials for this module.
! Complete the lab.
! Read the instructor notes and margin notes for the module.
! Practice using the Microsoft Intermediate Language disassembler to
examine the metadata of an assembly.
iv Module 17 (Optional): Attributes
Demonstration
This section provides demonstration procedures that will not fit in the margin
notes or are not appropriate for 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.
Custom Attributes
In this demonstration, you will show students how to declare and apply custom
attributes and how to use reflection to retrieve custom attribute metadata.
The code for this demonstration is contained in one project and is located in
<install folder>\Democode\Mod17.
Module Strategy
Use the following strategy to present this module:
! Overview of Attributes
Begin by explaining that attributes are only annotations to classes and
perform no function themselves. Before attributes can cause an action,
certain code must be implemented. This code is in the runtime for the
predefined attributes and is written by the developer for custom attributes.
Explain the syntax used to apply an attribute, and, after covering the lists of
predefined attributes briefly, discuss the three attributes—Conditional,
DllImport, and Transaction—using examples.
! Defining Custom Attributes
Introduce the need for creating custom attributes, and explain the procedures
involved in defining a custom attribute. Explain the use of AttributeUsage
and how to create an attribute class. Then explain the details of the
procedure used to compile code that uses custom attributes. Finish the
section by explaining how to use multiple attributes in code.
! Retrieving Attribute Values
In this section, introduce the concept of retrieving attribute values at run
time by using reflection. Explain how to use the MemberInfo class and the
typeof operator to obtain attribute values. Finally, discuss how to iterate
through the stored attribute values in an array to retrieve the required values.
To end the discussion about attributes, use the review slide to recapitulate
the main concepts covered in the module.
Module 17 (Optional): Attributes 1
Overview
Topic Objective
To provide an overview of
the module topics and
objectives.
! Overview of Attributes
Lead-in ! Defining Custom Attributes
In this module, you will learn
about using attributes in ! Retrieving Attribute Values
Microsoft Visual C# .NET.
Introduction to Attributes
Topic Objective
To define attributes.
Lead-in ! Attributes Are:
The concept of an attribute
is simple. # Declarative tags that convey information to the runtime
# Stored with the metadata of the element
Applying Attributes
Topic Objective
To explain the syntax for
using attributes. ! Syntax: Use Square Brackets to Specify an Attribute
Lead-in
[attribute(positional_parameters,named_parameter=value,
[attribute(positional_parameters,named_parameter=value, ...)]
...)]
Attributes can be applied to
element
element
several different types of
programming elements.
! To Apply Multiple Attributes to an Element, You Can:
# Specify multiple attributes in separate square brackets
# Use a single square bracket and separate attributes with
commas
# For some elements such as assemblies, specify the
element name associated with the attribute explicitly
You specify an attribute name and its values within square brackets ([ and ])
before the programmatic element to which you want to apply the attribute. Most
attributes take one or more parameters, which can be either positional or
named.
You specify a positional parameter in a defined position in the parameter list, as
you would specify parameters for methods. Any named parameter values
follow the positional parameters. Positional parameters are used to specify
essential information, whereas named parameters are used to convey optional
information in an attribute.
Example
As an example of using attributes, consider the following code, in which the
DefaultEvent attribute is applied on a class by using a positional string
parameter, ShowResult:
[DefaultEvent("ShowResult")]
public class Calculator: System.Windows.Forms.UserControl
{
...
}
class MyClass
{
...
}
6 Module 17 (Optional): Attributes
General Attributes
The following list summarizes some of the general attributes that are provided
by the .NET Framework.
Attribute Applicable to Description
Example
The following example shows how to use the Conditional attribute. In this
example, the MyMethod method in MyClass is tagged with the Conditional
attribute by the symbol DEBUGGING:
class MyClass
{
[Conditional ("DEBUGGING")]
public static void MyMethod( )
{
...
}
}
10 Module 17 (Optional): Attributes
class AnotherClass
{
public static void Test( )
{
MyClass.MyMethod( );
}
}
As long as the symbol DEBUGGING remains defined when the method call is
compiled, the method call will operate normally. When DEBUGGING is
undefined, the compiler will omit calls to the method. Therefore, when you run
the program, it will be treated as though that line of code does not exist.
You can define the symbol in one of two ways. You can either add a #define
directive to the code as shown in the preceding example, or define the symbol
from the command line when you compile your program.
Restrictions on Methods
The methods to which you can apply a Conditional attribute are subject to a
number of restrictions. In particular, they must have a return type of void, they
must not be marked as override, and they must not be the implementation of a
method from an inherited interface.
Note The Conditional attribute does not cause conditional compilation of the
method itself. The attribute only determines the action that will occur when the
method is called. If you require conditional compilation of a method, then you
must use the #if and #endif directives in your code.
Module 17 (Optional): Attributes 11
public
public class
class MyClass(
MyClass( ))
{{
...
...
int
int result
result == MyFunction("Hello
MyFunction("Hello Unmanaged
Unmanaged Code");
Code");
...
...
}}
(continued)
Member name Attribute can be applied to
Parameter parameter
Property property
ReturnValue return value
Struct struct
It is a good practice to append the name of a custom attribute class with the
suffix “Attribute,” as in DeveloperInfoAttribute. This makes it easier to
distinguish the attribute classes from the non-attribute classes.
Module 17 (Optional): Attributes 17
To be completely accurate, the compiler actually verifies that it could create the
attribute, and then stores the information to do so in the metadata. The compiler
does not create attribute instances at compile time.
Module 17 (Optional): Attributes 19
Example
To learn more about how the compiler handles attributes, consider the
following example:
[AttributeUsage(AttributeTargets.Class)]
public class DeveloperInfoAttribute: System.Attribute
{
...
}
.....
{
.....
}
[DeveloperInfo("Bert", Date="08-28-2001")]
public class MyClass
{
...
}
Tip If you need more detailed information, for example, if you want to
discover the values of attributes that a method has, you can use a MethodInfo
object. In addition, there are other “Info” classes: ConstructorInfo, EventInfo,
FieldInfo, ParameterInfo, and PropertyInfo. Detailed information about how
to use these classes is beyond the scope of this course. For more information,
search for “System.Reflection namespace” in the .NET Framework SDK.
Note MemberInfo is actually the abstract base class of the other “Info” types.
24 Module 17 (Optional): Attributes
For Your Information You can then iterate through the array to find the values of the attributes that
GetCustomAttribute is an
overloaded method. The
you are interested in.
parameter specifies whether
to search the inheritance
chain.
Module 17 (Optional): Attributes 25
Note You can use the Microsoft Intermediate Language Disassembler to see
these attributes inside the assembly.
26 Module 17 (Optional): Attributes
MyClass1 members:
member name: GetHashCode has 0 custom attributes:
member name: Equals has 0 custom attributes:
member name: ToString has 0 custom attributes:
member name: MyMethod has 1 custom attributes:
attribute has type: MyAttribute
Name Property: This is an example attribute associated!
with the method MyMethod in MyClass1
member name: GetType has 0 custom attributes:
member name: .ctor has 0 custom attributes:
Module 17 (Optional): Attributes 27
Prerequisites
Before working on this lab, you should be familiar with the following:
! Creating classes in C#
! Defining constructors and methods
! Using the typeof operator
! Using properties and indexers in C#
Exercise 1
Using the Conditional Attribute
In this exercise, you will use the predefined Conditional attribute to
conditionally execute your code.
Conditional execution is a useful technique if you want to incorporate testing or
debugging code into a project but do not want to edit the project and remove the
debugging code after the system is complete and functioning correctly.
During this exercise, you will add a method called DumpToScreen to the
BankAccount class. This method will display the details of the account. You
will use the Conditional attribute to execute this method depending on the
value of a symbol called DEBUG_ACCOUNT.
5. Save your work, compile the project, and correct any errors.
6. Run the test harness.
Notice that nothing happens. This is because the DumpToScreen method
has not been called.
7. Use the MSIL disassembler (ildasm), from the Visual Studio .NET
command prompt to examine install folder\Labs\Lab17\Starter\
Bank\Bin\Debug\Bank.dll.
Exercise 2
Defining and Using a Custom Attribute
In this exercise, you will create a custom attribute called
DeveloperInfoAttribute. This attribute will allow the name of the developer
and, optionally, the creation date of a class to be stored in the metadata of that
class. This attribute will permit multiple use because more than one developer
might be involved in the coding of a class.
You will then write a method that retrieves and displays all of the
DevloperInfoAttribute values for a class.
7. Modify the constructor so that it takes a single string parameter that is also
called developerName, and add a line of code to the constructor that assigns
this parameter to this.developerName.
8. Add a public string read-only property called Developer that can be used to
get the value of developerName. Do not write a set accessor.
32 Module 17 (Optional): Attributes
9. Add another public string property that is called Date. This property should
have a get accessor that reads dateCreated and a set accessor that writes
dateCreated.
10. Compile the class and correct any errors.
Because the class is in a class library, the compilation process will produce
a DLL (CustomAttribute.dll) rather than a stand-alone executable program.
The complete code for the DeveloperInfoAttribute class follows:
namespace CustomAttribute
{
using System;
/// <summary>
/// This class is a custom attribute that allows
/// the name of the developer of a class to be stored
/// with the metadata of that class.
/// </summary>
[AttributeUsage(AttributeTargets.Class |
!AttributeTargets.Enum | AttributeTargets.Struct,
!AllowMultiple=true)]
public class DeveloperInfoAttribute: System.Attribute
{
private string developerName;
private string dateCreated;
// Optional parameter
public string Date
{
get
{
return dateCreated;
}
set
{
dateCreated = value;
}
}
}
}
Module 17 (Optional): Attributes 33
2. You can use a MemberInfo object to hold information about the members
of a class. Assign the Rational type to the MemberInfo object by using the
typeof operator, as follows:
attrInfo = typeof(Rational);
3. The attributes of a class are held as part of the class information. You can
retrieve the attribute values by using the GetCustomAttributes method.
Create an object array called attrs, and use the GetCustomAttributes
method of attrInfo to find all of the custom attributes used by the Rational
class, as shown in the following code:
object[ ] attrs = attrInfo.GetCustomAttributes(false);
4. Now you need to extract the attribute information that is stored in the attrs
array and print it. Create a variable called developerAttr of type
CustomAttribute.DeveloperInfoAttribute, and assign it the first element
in the attrs array, casting as appropriate, as shown in the following code:
CustomAttribute.DeveloperInfoAttribute developerAttr;
developerAttr =
!(CustomAttribute.DeveloperInfoAttribute)attrs[0];
Note In production code, you would use reflection rather than a cast to
determine the type of the attribute.
// Test harness
public class TestRational
{
public static void Main( )
{
System.Reflection.MemberInfo attrInfo;
attrInfo = typeof(Rational);
object[ ] attrs = attrInfo.GetCustomAttributes(false);
CustomAttribute.DeveloperInfoAttribute developerAttr;
developerAttr =
!(CustomAttribute.DeveloperInfoAttribute)attrs[0];
Console.WriteLine("Developer: {0}\tDate: {1}",
!developerAttr.Developer, developerAttr.Date);
developerAttr =
!(CustomAttribute.DeveloperInfoAttribute)attrs[1];
Console.WriteLine("Developer: {0}\tDate: {1}",
!developerAttr.Developer, developerAttr.Date);
}
}
}
foreach (CustomAttribute.DeveloperInfoAttribute
! devAttr in attrs)
{
Console.WriteLine("Developer: {0}\tDate: {1}",
!devAttr.Developer, devAttr.Date);
}
}
8. When you run this program, it will display the names and dates that you
supplied as DeveloperInfoAttribute information to the Rational class.
36 Module 17 (Optional): Attributes
Review
Topic Objective
To reinforce module
objectives by reviewing
key points. ! Overview of Attributes
Lead-in ! Defining Custom Attributes
The review questions cover
some of the key concepts ! Retrieving Attribute Values
taught in the module.
6. Suppose that Widget from the previous question had a method called
LogBug. Could CodeTestAttributes be used to mark only this method?
No. CodeTestAttributes can only target whole classes.
THIS PAGE INTENTIONALLY LEFT BLANK