Aspnet and Vbnet Web Programming 0201734400 9780201734409 Compress
Aspnet and Vbnet Web Programming 0201734400 9780201734409 Compress
NET
and VB.NET
Web Programming
This page intentionally left blank
ASP.NET
and VB.NET
Web Programming
Matt J. Crouch
The author and publisher have taken care in the preparation of this book, but make no expressed or implied warranty of
any kind and assume no responsibility for errors or omissions. No liability is assumed for incidental or consequential
damages in connection with or arising out of the use of the information or programs contained herein.
The publisher offers discounts on this book when ordered in quantity for special sales.
For more information, please contact:
All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
in any form, or by any means, electronic, mechanical, photocopying, recording, or otherwise, without the prior consent
of the publisher. Printed in the United States of America. Published simultaneously in Canada.
For information on obtaining permission for use of material from this work, please submit a written request to:
ISBN: 0-201-73440-0
Text printed on recycled paper
1 2 3 4 5 6 7 8 9 10—MA—0605040302
First printing, May 2002
Contents
Preface xv
v
vi Contents
Bibliography 715
Index 717
This page intentionally left blank
Preface
xv
xvi Preface
productive, and responsive it needs to be. The .NET application platform can
make that happen.
Active Server Pages.NET (ASP.NET), an integral part of the .NET
Framework, is the key focus of this book. ASP.NET enables developers to
create dynamic Web applications much in the same way desktop applications
are created. Web applications can now share the same flow and feel as desktop
applications; thus, users can do more with the computer skills they already
have. For software developers, ASP.NET provides many advantages over
other Web application development models, in particular the speed at which
Web application and services can be developed.
This book also covers Web Services, the faceless applications that run on
Internet servers everywhere. You can write .NET applications that aggregate
Web Services. These Web Services, located in various locations in the Internet
cloud (as well as your local area network), all work together to deliver on the
promise of a rich and productive Internet experience for users.
This book follows a tutorial format and is geared toward readers with little
or no experience with ASP.NET and the .NET Framework. Discussions of
specific concepts are followed by lab exercises. Screenshots guide you through
every step of the development process.
In the text, an inline reference to the source code line would appear like
this: {. This allows you to quickly locate the source code under discussion.
Helpful Stuff
Occasionally I’ll mention special tips that will make your development efforts
easier. These are highlighted like this:
Tech Talk
Some discussions may not have direct relevance to the topic at hand but may
interest the more industrious programmer. Some folks prefer not to listen to
technical talk (like me—I enjoy simplicity), but I include it for the sake of
completeness. I segregate these discussions from the main text like this:
TECHTALK
Here’s where a geeky discussion happens. You can just
skip over it if you’ve forgotten your pocket protector or if
this sort of talk doesn’t interest you.
Miscellaneous
Certain unfamiliar terms in the text are set in italic text. Menu commands
(such as those in Windows and the VS.NET development environment)
appear in boldface text. Also note that some reference tables, particularly
long ones such as those for the .NET Framework Class Library, have been
placed in appendixes for better readability of the text.
Acknowledgments
This is the section where I thank people, and I can’t thank them enough. First,
thanks to my readers who sent all the kind words about my first book. You’ve
provided much motivation to continue my writing career. Grazie!
Addison-Wesley is full of many wonderful people, most notably my editor,
Mary O’Brien, whose continued support makes the long hours of putting
together a book worthwhile. Alicia Carey and Elizabeth Ryan were a pleasure
to work with as well; they always took care of the very important little details
that accompany a complex project such as this one.
Many thanks go to my mentor and friend, Mark Hayton. I owe him for his
brutal honesty, both at work and elsewhere.
The Addison-Wesley editorial group assembled a great team of reviewers
for the text: Brad Abrams of Microsoft Corporation, Doug Thews (thanks for
cleaning up my code and for your insightful submittals!), Daryl Richter, and
Don Browning. I’m very grateful for their extremely valuable input. These
individuals played a large part in the success of this project.
Copyeditors are the unsung heroes of the publishing world. My satisfac-
tion with this book comes from the efforts of my copyeditor, Chrysta Meadow-
brooke. She has an incredible talent for helping me to express what’s really
inside my head. Not to mention, she’s the best “nonprogrammer programmer”
I’ve met to date.
xxii Preface
Matt J. Crouch
Indianapolis, IN
December 2001
CHAPTER 1
1
2 Chapter 1 The .NET Platform and the Web
ranked as some of the most expensive software projects. Early Web applica-
tions were restricted mainly to the UNIX operating system, which confined
their development and maintenance to a small group of privileged individuals
with specialized skills. The road traveled to create highly interactive Web sites
was certainly treacherous, but it paved the way for wonderful technologies like
Active Server Pages.NET (ASP.NET) and the .NET platform.
form fields are encoded by the browser using the x-url-encoding system
before transmission. The data is sent by one of two methods:
■ Encoding the data in the body of an HTTP POST command (a POST
request)
■ Passing the data as arguments to a script file in the URL (a GET
request)
The Web server receives this data and passes it to a CGI application for pro-
cessing. The CGI application processing can include any programming logic
and code necessary to produce the desired output. The CGI application then
sends the results to the Web browser as HTML or other data that the browser
can render.
2. CGI programs run separately from the Web server process in a sepa-
rate application. When the Web browser makes a request for a CGI
program, the CGI executes in another system process independently
1.3 Components of ASP.NET and the .NET Framework 5
from the Web server. On the Windows platform, CGI applications are
typically implemented as executables (EXEs). The largest problem
with this is the CPU resources involved in launching the application.
In most cases, valuable CPU time and memory are stolen from the
Web server when resources are at a premium. This occurs because
one EXE process is created for each request of the CGI program—a
very costly operation in Windows. When coupled with a high number
of users requesting files from the Web server, the server’s resources
can be exhausted quickly. ASP.NET is designed to use minimal system
resources by executing in the process space of the Web server, thereby
sharing its system resources. The underlying runtime engine for
.NET also minimizes memory leaks, thus providing further stability.
ASP.NET also has the ability to execute in a separate process space,
much like traditional EXEs.
2. The Web server receives the command and requests the file in the
URL. This could be either a static HTML file or a server-side script or
program.
3. The server sends the content of the file (or output of the script pro-
gram) back to the client (browser), and the connection is closed.
When a Web server has an ISAPI filter, the procedure changes somewhat.
1. The user requests a URL, and the Web browser sends the appropriate
HTTP command to the Web server.
2. The Web server receives the request and passes that request data as
parameters to the ISAPI filter code. This step is transparent to the
user. The user has no knowledge of the ISAPI filter at work on the
server.
3. The ISAPI filter performs some server-side processing and then sends
back customized data through the IIS server and back out to the Web
browser. The connection is then closed.
ISAPI filters have many applications, including the following:
■ Customized logging of user activity on the server
■ Advanced security systems that examine the origin of each HTTP
request and determine whether the user is allowed to enter
■ On-the-fly decryption of files on the Web server based on a password
■ Modification of the output stream of the Web server
In essence, ISAPI filters do exactly as their name implies—they filter
incoming requests from Web clients.
2. ASP.NET ships with many reusable controls that make common pro-
gramming tasks easy, providing a framework that encourages a rich
third-party market of reusable controls for a variety of tasks. Basic user
interface controls like buttons, text fields, and drop-down lists are
included, plus advanced ones like calendar controls and editable data
grids. These controls can be used in a declarative manner; you can sim-
ply drag-and-drop the controls (or type in their definitions by hand) in
your ASP.NET applications and they’ll function with no or very little
supplemental code.
managing their own memory allocation and deallocation (a process that can
introduce errors in program execution). The CLR enables language code to
interact with code written in other languages at the object level. In addition,
the CLR can provide self-describing objects (making deployment and reuse
easier) and enable code to run on any CPU that provides an implementation
of the CLR.
The .NET Framework Class Library is an extensive collection of data
types and objects intended to give programmers a start in developing their
applications. The data type and objects are designed and categorized to make
accessing system functionality such as input/output (I /O), graphics, database
access, and other system-level services easy. The objects come with all the
benefits and features of object-oriented languages, such as inheritance and
polymorphism. We’ll talk more about inheritance and polymorphism in Chap-
ter 2; these features allow us to customize many of the objects in the .NET
Framework Class Library to make them most useful for the programming task
at hand. The .NET Framework Class Library also supports objects like basic
data types (for example, integers, strings, and so on) as well as more abstract
data types (for example, user interface controls). Also note that the .NET
Framework Class Library is available no matter what language you choose to
use, and it works for client and server applications. You’ll find yourself using it
quite often, so it’s worth learning all you can about its capabilities.
3. The system then calculates total cost and shipping charges and sends
the order to the company’s distribution warehouse via e-mail. The cus-
tomer’s credit card information is sent for processing. If credit is
approved, the system informs the customer that the order is now being
processed.
4. The order e-mail is received at the warehouse, and the products
needed are picked. Once the order is fulfilled, the system sends an
e-mail message to the customer that the order has been shipped.
Although the complexity involved in making a complete order-entry
system is not apparent in the preceding four steps, they nonetheless serve as
a good example of how the steps of this order-processing system can be
“wrapped up” into an order-entry component.
The .NET Framework helps us not only by making these components
easy to program but also by providing many code engineering and organiza-
tion benefits as well. By creating a component that performs the functionality
of the ordering system, we gain the advantage of having the code completely
hidden inside a compiled assembly. The component is object-oriented in the
true sense. The component has information hiding, which makes the details of
the component’s implementation unavailable to the user of the object. We can
enhance the functionality of the object through inheritance, and the compo-
nent can be reused in many different programming environments. The .NET
Framework also makes deployment of the object easy with the use of embed-
ded metadata that describe the details of the component to clients.
most likely have to resort to a manual process of cutting and pasting the data
into those applications. Then there’s the issue of the availability of Web sites
and services. Users are demanding that this information be available on
devices other than their desktop computers. Before .NET, getting Web ser-
vices data to PDAs, cell phones, and other Internet-enabled appliances
proved very difficult or even impossible in some cases.
XML Web Services takes a giant leap toward solving these problems. To
attack the communication dilemma, Web Services relies on using HTTP as
the network transport. This eliminates the need for proprietary communica-
tion protocols that are common with other distributed object models, plus it is
easier to operate across Internet firewalls since it uses the same network port
as normal Web traffic. Web Services also uses the Extensible Markup Lan-
guage (XML) to facilitate the formatting of requests and responses from Web
Services. Again, this eliminates the need for a proprietary solution since virtu-
ally any software system can understand a text-based language like XML. It
also provides a mechanism for describing the programming interface to poten-
tial clients of Web Services. These features allow many different applications
and devices to act as consumers of data from the Web Service without having
to navigate a user interface to extract data.
exchanges (HTTP, XML, SOAP, and WSDL), this opens the door for any com-
puter system to interface with any device the user has. For example, personal
information management (PIM) software, such as Microsoft Outlook, running
on a desktop computer can automatically sync with PIM software running on a
PDA. The PDA is Internet- and .NET-enabled, so it can consume information
from Web Services deployed throughout the Internet. The PIM software run-
ning on the PDA can receive an e-mail alert indicating a change in, say, a
travel itinerary due to a delayed airline flight. The PDA automatically takes
the information about the flight change and updates the user’s calendar in the
PIM software. Taking the process a step further, the PIM software can notify
the user’s colleagues via e-mail that the flight was delayed and the scheduled
meeting will have to be postponed. Web Services enables this type of seamless
integration and automation, and the sky’s the limit to what can be created
using the Web Services technology.
One particularly exciting initiative for Web Services, developed by
Microsoft, is called .NET My Services. It is often referred to as a “digital safe-
deposit box” for the user. Inside this personal information space the user can
store many things. In the initial rollout of .NET My Services, the following
features will be included:
■ .NET Profile—name, nickname, special dates, picture, and address
■ .NET Contacts—electronic relationships/address book
■ .NET Locations—electronic and geographical locations
■ .NET Alerts—subscription, management, and routing of alerts
■ .NET Presence—connection status (online, offline, busy, free) and
specification of which device(s) to send alerts to
■ .NET Inbox—inbox items like e-mail and voice mail, including existing
mail systems
■ .NET Calendar—time and task management
■ .NET Documents—raw document storage
■ .NET ApplicationSettings—application settings
■ .NET FavoriteWebSites—favorite URLs and other Web identifiers
■ .NET Wallet—receipts, payment instruments, coupons, and other
transaction records
■ .NET Devices—device settings and capabilities
■ .NET Services—services provided for an identity
■ .NET Lists—general-purpose lists
■ .NET Categories—a way to group lists
14 Chapter 1 The .NET Platform and the Web
The most important fact about .NET My Services is that the user is in
direct control of this information at all times. Since other Web sites, individu-
als, and Web services will request data from the user’s “safe-deposit box,”
there must be strict security controls in place that the user can adjust. The
user can designate who is allowed to gain access to his or her personal infor-
mation. Organizations accessing a user’s .NET My Services can also (with the
user’s consent) add items to the user’s personal information. For example, if
the user wants to purchase an airline ticket, the user can give a particular air-
line access to a credit card located in the .NET Wallet, make the purchase,
and add the flight itinerary to the .NET Calendar automatically. The airline
can then issue notifications about flight changes through the .NET Alerts sys-
tem and, if applicable, alter the .NET Calendar information to reflect time
and date changes to the itinerary.
In summary, Web Services and .NET My Services open up several oppor-
tunities for rich application integration that make the user’s online experience
more productive and more enjoyable.
background on the .NET CLR, the Common Type System, and other
general .NET platform topics. We’ll also explore COM+ Component
Services and how to program your .NET components to use these
services.
✔ Chapter 6: Building Web Services. As mentioned before, Web Ser-
vices is the most important feature of the .NET platform. In Chapter 6,
we’ll discuss the construction of Web Services and review code samples
and labs to help you get a jump start into making your own Web
Services.
✔ Chapter 7: Accessing Data with ActiveX Data Objects.NET. Data
access is probably the single most important task that a Web applica-
tion or service performs. This chapter shows you how to use a powerful
data access method to work with a variety of data stores.
✔ Chapter 8: Securing Your .NET Applications. This chapter covers
miscellaneous security topics as they relate to application development.
We’ll also briefly discuss cryptography and how you can implement it in
your applications.
■ Further Reading
Here are some helpful resources for further study of the topics discussed in
this chapter.
■ Microsoft COM+ Web site (http://www.microsoft.com/complus): This
site provides an executive overview of COM+ and also includes links to
white papers on COM+.
■ Microsoft IIS Web site (http://www.microsoft.com/windows2000/
technologies/web/default.asp): This site offers resources related to IIS
and other Web and application services included in Windows 2000/ XP.
■ Microsoft .NET Web site (http://www.microsoft.com/net): This is
Microsoft’s Web site dedicated to all things .NET. You’ll find resources
for developers, information technology personnel, and business
professionals.
■ CGI Web site (http://hoohoo.ncsa.uiuc.edu/cgi): This site at the Uni-
versity of Illinois explains CGI very well.
This page intentionally left blank
CHAPTER 2
The VB.NET
Crash Course
17
18 Chapter 2 The VB.NET Crash Course
It’s important to note that this chapter is no substitute for a good book or
reference manual on VB. Documenting every feature of the language is
beyond the scope of this book. The purpose of this chapter is to bring you up
to speed with VB.NET if you are a new programmer and to introduce VB vet-
erans to the new features of the language. My recommendation is to read sev-
eral books on VB to increase your understanding of its abilities. Of course,
there is also no substitute for hands-on experience developing applications
with VB.
LAB 2-1
YOUR FIRST VB APPLICATION
(and many of the subsequent programs in this book) because of its low
complexity. This allows you to concentrate on the core language features
of VB.NET and the relevant .NET Framework concepts. Highlight the Con-
sole Application icon in the New Project dialog; you may need to scroll
down to find it (Lab Figure 2-2).
b. Once you locate and highlight the Console Application icon, you need to
give your new project a name. To do this, enter a name for the project in the
Name text box. Call your project “HelloWorld.” You can select a location for
the project files by clicking the Browse button or you can use the default
location.
c. Now click on the OK button to create the new project.
20 Chapter 2 The VB.NET Crash Course
Imports System
Module Module1
Sub Main()
Dim strUserName As String
strUserName = Console.ReadLine()
22 Chapter 2 The VB.NET Crash Course
End Module
c. Click the Save All button on the tool bar. This saves your code module and
all other modified files associated with the project.
b. To run the program, click the Start button on the tool bar. You can also sim-
ply press the F5 key. After a moment or two, the console window will
appear with your running program. So, introduce yourself. . . . (See Lab Fig-
ure 2-5.)
c. When the program terminates (after you press <enter> to continue), the
system returns to VS.NET.
we may need temporary data storage for our programs. That’s when variables
are used.
Constants are similar to variables. They hold data, but unlike variables,
their data cannot be modified once the constant is first defined in a program.
For example, if you are writing a program to compute the area of a circle, you
could use a constant to hold the value of pi (the ratio of the circumference of a
circle to its diameter—remember high school math?), which does not change
regardless of the circle’s size. Using a constant allows you to assign a friendly
name to a value that could otherwise easily be forgotten. (Which is easier to
remember: “pi” or “3.14159 . . .”?)
Performing arithmetic operations is central to almost any program, so
most programming languages provide arithmetic operators. The operators in
VB.NET basically correspond to their mathematical counterparts (+ for addi-
tion, – for subtraction, * for multiplication, and / for division).
name and data type. This makes VB.NET set aside memory to hold values in
the variable.
As mentioned before, variables can hold many different types of data.
VB.NET natively provides a selection of variable types that can accommodate
most storage tasks. Let’s look at the different data types available.
First, there are numeric data types. VB.NET has numeric data types to
handle integer numbers (for example, 1, 2, –5, 23) and fractional data types
(for example, 4.23, 3.14, –0.12). Depending on your program’s requirements,
you may need different levels of precision for your numbers. Table 2-1 shows
the different integral types. Pay special attention to the range of valid values.
Use integral data types in your programs for storing only whole number
values (no decimals, no fractions). Watch out; storing fractional values causes
VB.NET to either round or truncate values, which could lead to unexpected
results.
VB.NET also provides data types for noninteger numbers (decimals and
fractions). According to your programming requirements, you may need to
use fractional numeric data types that offer varying levels of precision. The
fractional data types are listed in Table 2-2.
The Char data type in VB.NET is used to hold a single alphanumeric Uni-
code character. Unicode is a standard for encoding most of the symbols used
by languages around the world. It’s an important element in the multilingual
capabilities of VB.NET and of Windows itself. Older software systems repre-
sented characters from the ASCII character set, which includes symbols used
1.401298e-45 to
3.402823e38 for positive
values
4.94065645841247e-324 to
1.79769313486232e308 for
positive values
by the English language only. This makes Unicode a better solution for appli-
cations targeted for international markets. A Unicode character uses 16 bits
(2 bytes) of memory storage.
The String data type is used to hold text information. The data in a string
is stored as a series of Unicode characters. Strings can be any length; their
storage is managed automatically for you by VB.NET.
The Date data type is used to store calendar date and time information. A
Date type holds both a date and a time in a 64-bit format. The Date type has a
resolution of 100 nanoseconds and can keep dates as far back as January 1,
1 CE, 12:00 A.M. (based on the Gregorian calendar). The maximum date is
December 31, 9999 CE. The Date data type maps to the System.DateTime
structure. Yes, the Date type is Y2K compliant, in case you’re wondering!
Another class of VB.NET data types is the binary data types. These
include the Boolean type and the Byte type. The Boolean type holds data
such as true/false, yes/no, on/off, and so on. The Byte type holds 8 bits of
unsigned data. Typically, the Byte data type is used to store arbitrary binary
data. Several bytes clumped together as an array (see Section 2.3.4) can be
used by your program to store things such as images, audio, and so on. The
Byte and Boolean types map to .NET Framework structures System.Byte
and System.Boolean, respectively.
The Object type is a special data type used to reference any other type.
It maps to the System.Object class. Any class that you create in VB.NET
inherits from the System.Object class. (Inheritance is discussed in Section
2.7.4.)
This tells VB.NET to create storage for a String data type and to call it
strUserName.
When declaring a variable, you can also assign it an initial value. To do
this, declare a variable with the Dim command and then add an assignment
operator (=) along with the value you wish to assign to the variable, as shown
in the example below:
Imports System
Module Module1
Dim g_intTestGlobal As Integer
Sub Main()
Dim strUserName As String
strUserName = Console.ReadLine()
AnotherSubroutine()
Console.WriteLine("AnotherSubroutine() has been executed")
Console.WriteLine("The value of g_intTestGlobal is: {0}", _
g_intTestGlobal)
Sub AnotherSubroutine()
g_intTestGlobal = 100
Console.WriteLine(_
"We have set the g_intTestGlobal variable")
End Sub
End Module
When you run this program, you’ll see the output shown in Figure 2-1.
2.3.4 Arrays
Arrays are a collection of data elements that all have the same data type.
Arrays are useful for processing large sets of data without having to declare a
separate variable for each data element.
Arrays have dimensionality, which refers to the number of subscripts used
to access each element in the array. All arrays have at least one dimension and
can support up to sixty dimensions, but you’ll probably deal with arrays that
have a maximum of only three dimensions since we tend to conceptualize data
(and our physical world) that way.
Arrays also have defined minimums and maximums for the subscripts used
to reference the array elements. Array dimensions usually begin with 0 and
have a maximum value of what an Integer (Int32) data type can hold.
Figure 2-2 shows a representation of a one-dimensional array. It contains
five elements, each element a string.
When we declare an array, we usually give it an initial size. In the follow-
ing two code examples, one declares an array of strings with five initial ele-
ments, and the other a two-dimensional array of Boolean values (100 values
arranged in 10 rows and 10 columns):
Once you declare an array, you can either increase or decrease its size.
The ReDim statement is used to change the size of an array after it has been
declared using Dim:
When ReDim is used in this fashion, all the data contained in the array are
lost. However, you can retain the contents of an array you are resizing by sup-
plying the Preserve keyword after the ReDim command, like this:
You can resize any dimension of an array. However, you can use the
Preserve keyword only on the last dimension of the array.
You may not always know the size of an array, but you can determine it by
using the UBound() function:
lngArraySize = UBound(aryMyArray)
You can also initialize the contents of an array in your code at the time the
array is declared. Here’s how it’s done:
This sample shows how to declare two arrays, one for holding String
variables and the other for holding Integer variables. Notice that there is
no explicit size declared for the arrays. This is not allowed by VB.NET when
explicit array initialization is used as shown above.
lngB = intA
The variable lngB now contains the value “3” stored in a Long data type.
A conversion like this is considered “safe” because a Long data type has
greater precision than the Integer data type. If we did the reverse (converted
a Long variable to an Integer variable), we’d run the risk of losing data since
the value that the Long variable is holding may be beyond the maximum range
of an Integer variable. In many cases, VB.NET won’t even allow this type of
implicit conversion.
Explicit conversion may also be used to convert data types. Explicit con-
version involves the use of special VB.NET functions to convert one data type
to another.
32 Chapter 2 The VB.NET Crash Course
Constants can be strings or numbers. The data type must also be specified.
Strings must be enclosed in double quotation marks:
You can also specify date and time values by enclosing a properly format-
ted date and time within pound signs (#):
Operator Use
Mod operator Divides two numbers and returns only the remainder
– operator Finds the difference between two numbers or indicates the negative value of
a numeric expression
All arithmetic operators are binary, meaning that they operate on two
expressions. The subtraction operator (–) can also be applied in a unary fash-
ion to negate the value of an expression:
Variable = –numericExpression
Assignment Operators
There are several forms of assignment operators, as shown in Table 2-4.
Past versions of VB had only one type of assignment operator, the equal
sign (=). To perform certain operations, such as incrementing a value, you had
to write code such as this:
intMyVar = intMyVar + 1
Code like this can be overly verbose. VB.NET allows you to shorten this
operation to:
intMyVar += 1
The other assignment operators work similarly, such as the division assign-
ment operator. This line of code divides an Integer variable’s value by 2:
intMyVar /= 2
34 Chapter 2 The VB.NET Crash Course
Operator Use
^= operator Raises the value of a variable to the power of an exponent and assigns the
result back to the variable
*= operator Multiplies the value of a variable by the value of an expression and assigns the
result to the variable
/= operator Divides the value of a variable by the value of an expression and assigns the
result to the variable
\= operator Divides the value of a variable by the value of an expression and assigns the
integer result to the variable
+= operator Adds the value of an expression to the value of a variable and assigns the
result to the variable
–= operator Subtracts the value of an expression from the value of a variable and assigns
the result to the variable
&= operator Concatenates a string expression to a string variable and assigns the result to
the variable
Bit-Wise Operators
Many languages allow bit-wise operations. Bit-wise operations compare the bit
values of numeric expressions and evaluate them according to the rules of
Boolean logic: AND, OR, NOT, and XOR (Exclusive OR). Tables 2-5 through
2-8 present the truth tables for these rules.
2.3 Variables, Constants, and Operators 35
Value Result
False True
True False
36 Chapter 2 The VB.NET Crash Course
Logical Operators
In VB.NET code there is another group of similar Boolean operators called
logical operators—And, Or, Not, and Xor. Like their counterparts, the bit-
wise operators, they perform the same Boolean operations. However, instead
of performing Boolean operations on the bits themselves, logical operators
compare true/false expressions.
For example, suppose we want to take the XOR of two separate Boolean
expressions. We can write two such expressions like this:
This code fragment outputs a value of “true” since the left-hand expres-
sion in the boldface code line is true and the right-hand expression is false.
Comparison Operators
Comparison operators test whether or not expressions are equal to, less than,
greater than, less than or equal to, or greater than or equal to each other (see
Table 2-10). Expressions can hold numeric, string, date/time, and object data.
VB.NET includes two more comparison operators, Like and Is. These
special comparison operators work on strings and objects, respectively. The
Like operator is especially useful for matching string patterns. Comparing
<= (less than or equal to) expression1 <= expression2 expression1 > expression2
>= (greater than or equal to) expression1 >= expression2 expression1 < expression2
against string patterns has several advantages over simply testing for equality.
For example, suppose you are searching through an array of strings to match
names that begin with a certain letter combination. In the following example,
we’ll compare various string values against a string pattern.
The string pattern used is designed to match strings that begin with “Cro.”
The asterisk (*) instructs VB.NET to match any number of characters. It’s
called the wildcard character. In addition to matching strings by wildcards,
you can also use character ranges and character lists (see Table 2-11).
You can change how string patterns operate with two different options.
Two statements, Option Compare Text and Option Compare Binary,
determine whether string comparisons are treated with case sensitivity in
mind. If Option Compare Text is placed in your code before your string pat-
tern comparisons, VB.NET will disregard case sensitivity and follow the rules
[!charlist] Matches any single character not in a "Z" Like "[!A-C]" (true)
character list
2.4 Modularizing Your Code—Functions and Subroutines 39
While we’re on the subject of strings, you should be aware of the very use-
ful concatenation operators. Concatenation takes two strings and combines
them into one string. The concatenation operator is the ampersand (&). Thus,
concatenation is performed as follows:
was more of a problem back in the first days of BASIC, when functions and
subroutines were not supported. You can still write spaghetti code today, but
using functions and subroutines makes this less likely.
End Function
dblArea = TriangleArea(3, 8)
Console.WriteLine(dblArea)
Notice the use of the keyword ByVal in the function code. This tells the
program that the parameter that follows should be treated as call by value.
2.4 Modularizing Your Code—Functions and Subroutines 41
Call by value means that the actual value of the parameter supplied in the
invocation of the function is passed into the function. Any updates made to
the value passed into the function will be discarded.
Parameters can also be call by reference. Call by reference passes the
memory location of the variable used for the parameter. To designate a pa-
rameter as call by reference, use the ByRef keyword before the parameter
name. Be sure when you call a function with the call by reference parameter
that you supply a variable for the parameter instead of a constant expression.
This gives VB.NET a location to hold data for the parameter. Call by refer-
ence parameters are useful when you want your function to return more than
one value to the invoking code and also for performance reasons when passing
objects or structures of large size.
Functions, unlike subroutines, return a value to the caller. You set that
value by making an assignment to the function name. In the TriangleArea
function, we assigned the return value to the area of the triangle (based on the
length of the base and height).
Sub DisplayHeader()
Console.WriteLine("Welcome to .NET Web Programming with VB")
Console.WriteLine("Enjoy your stay!")
End Sub
When defining parameters for a subroutine or function, you may find that
some parameters are not used in all calls to that subroutine or function. When
this is the case, you can designate such parameters as optional parameters. To
mark a parameter as optional simply supply the Optional keyword before
ByRef or ByVal.
If expression1 Then
statements1
ElseIf expression2
statements2
. . . more ElseIf statements
Else
statements3
End If
program flow resumes with the statement following the End Select line. If
the comparison of test-expression and expression1 is false, then test-expression
is compared against expression2, expression n, and so on. If test-expression
does not match any of the expressions in any of the Case clauses, the state-
ments after the Case Else line are executed.
Exit Statements
Exit is used to leave a function, subroutine, or loop (see Section 2.5.3). Use
Exit when you want to stop code execution within these code structures
based on some circumstances that happened previously. Exit takes the fol-
lowing keywords: Do, For, Sub, Function, Property, and Try. For now,
let’s look at Sub and Function. These statements cause code execution to
flow out of a subroutine or function, respectively.
2.5 Controlling Program Flow 45
Goto Statements
The other unconditional branch function is Goto. It transfers execution to a
labeled line of code. Here’s an example of code using Goto. Notice the code
label Here.
Sub DisplayHeader()
Console.WriteLine("Welcome to Web Programming with .NET")
Goto Here
Here:
Console.WriteLine("How’d we get here??")
End Sub
This function will never display “Enjoy your stay” since the Goto statement
skips over that code line.
2.5.3 Loops
Loops execute a block of code a predetermined number of times or until a
particular test condition has been met.
Do . . . Loop Loops
The Do . . . Loop comes in two flavors. It can execute statements either until
the test expression is true (Do Until) or as long as the test expression is true
(Do While).
Here’s an example using Do While.
Do
WriteInBook()
If BookComplete() Then
Exit Do
End If
Loop While EnergyLevel() > 50
End Sub
Sub CounterDemo()
Console.WriteLine()
Console.WriteLine()
End Sub
You can write the following code to access each element in the array.
Dim strSingleString As String
Notice that a For Each . . . Next loop contains an iterator (in the
example, strSingleString ) used to store an array element for each iteration
through the loop. Generally, this iterator variable can be of any type, but it is
usually set to whatever data type matches the elements in the array.
The For Each . . . Next statement is also used for looping through col-
lections (see Section 4.3).
While ImNotDone()
' do something here
End While
The expression following the While keyword is evaluated, and if true, the pro-
gram executes the loop’s code block.
erroneous code will most likely fail, especially if the subsequent code relies
on accurate results from the previous code. What’s needed is an efficient,
straightforward process for identifying errors and handling subsequent code
execution gracefully.
As you can see, handling errors can be quite complex and can complicate
your code considerably. What’s worse is that many programmers skip placing
error-handling code altogether because of the complexity it adds to their code.
That’s clearly not a good thing since this would make finding bugs a tedious
process.
Fortunately, VB.NET provides a few options for error handling. Suppose
you want to tell VB.NET to execute a common error-handling routine when-
ever an error occurs in the code. You want this to be as automatic as possible
since you want to avoid the code abomination discussed previously. VB.NET
50 Chapter 2 The VB.NET Crash Course
Sub ErrorHandlingDemo()
On Error Goto Err_handler
Done:
Exit Sub
Err_handler:
'* Handle error
Console.WriteLine(Err.Description)
Goto Done
End Sub
Sub StructuredErrorHandler()
Dim intA As Integer = 3
Dim intB As Integer = 0
Dim intResult As Integer
Try
' Division is futile...
intResult = intA \ intB
Catch e As DivideByZeroException
Console.WriteLine("EXCEPTION CAUGHT: " & (e.toString))
Finally
Console.WriteLine("Division attempt complete.")
End Try
End Sub
Try
If intTestValue >= 1000 Then
Throw New Exception("x is out of range")
End If
Catch
Console.WriteLine("Error!")
2.7 Object-Oriented Programming 53
Finally
Console.WriteLine("Executing finally block.")
End Try
m_intRPMs = 0
m_intNumberOfCylinders = intCylinders
End Sub
End Sub
g Public Sub StartEngine()
m_intRPMs = 1500
End Sub
End Class
This is a simple example of how an entity (in this case, a simple gasoline
engine) can be modeled in software with a class declaration. It describes the
characteristics of the gasoline engine (tachometer, horsepower, serial number,
and number of cylinders), plus the actions that can be applied to the gasoline
engine (starting, stopping, and adjusting the throttle). The characteristics
become class member variables and the actions become member functions of
the class.
Creating classes starts with a class definition. In line e, the Class key-
word starts the class definition. Notice the use of the keyword Public. This is
an access modifier that designates the type of access allowed on the class.
Public indicates that the class doesn’t have any access restrictions in regards
to where it can be used in the code (that is, the class can be used anywhere
in the current module). There are other access modifiers such as Private,
Protected, and Friend; Table 2-12 shows the complete list.
The class block terminates with the End Class statement.
Inside the class block are member variable and member function declara-
tions. The example above defines member variables for each of the gasoline
engine’s characteristics. In line f, the horsepower member variable is defined
as an Integer data type. The Private access modifier also appears, making
the variable accessible only to code inside the class declaration. The VB.NET
compiler will not allow any other attempted access, for example, from the
main program code. The code block defines member variables for the other
engine characteristics (serial number, number of cylinders, and tachometer) in
a similar manner.
Defining member functions is similar to defining regular functions. Line
g shows how to define the StartEngine() member function. As with the
56 Chapter 2 The VB.NET Crash Course
Private Member can be used only from within the class in which the member
is defined.
Public Member can be used globally (within the current code module).
Protected Member can be used within the class in which the member is defined
plus any derived classes.
Friend Member can be accessed from modules that are outside the class but
part of the project/assembly within which the class is defined.
Property keyword just like a function whose value is being returned. The
property name, SerialNumber, is assigned to the value in the private class
member variable m_strSerialNumber. The Set code is just as simple: assign
the private member variable m_strSerialNumber to the value that was
included in the assignment. The code in the Set block is invoked whenever
an assignment is made to the property. The value used in the assignment is
kept in the special reserved variable called Value.
Class methods, member variables, and properties are accessed using the
dot (.) operator. It follows these general forms:
Variable = object.membervariable
Returnvalue = object.functionname()
Object.membervariable = value
Module Module1
End Sub
End Property
End Set
End Property
End Class
Sub Main()
j Dim objEngine As GasolineEngine
k objEngine = New GasolineEngine(100, 4)
objEngine.SerialNumber = "123"
objEngine.StartEngine()
Console.WriteLine("Started Engine No. {0} ", _
objEngine.SerialNumber)
objEngine.AdjustThrottle(100)
Console.WriteLine("Speed: {0}", objEngine.Tachometer)
objEngine.StopEngine()
Console.ReadLine()
End Sub
End Module
command calls the constructor on the base class. Don’t forget to include it so
VB.NET can properly instantiate the class. Inside the New() subroutine, you
can place additional code to execute upon creation of a new class instance. In
the GasolineEngine class example, we set the initial RPMs of the engine to
zero on line i.
Lines j and k show how to create the class. First, the Dim command
declares a new variable that is the type of the class. Then, the New command
actually creates the new instance of the class. Two parameters are used as part
of the constructor: the horsepower and the number of cylinders. These are
used to complete the initialization of the class.
Invoking the destructor for the class can occur in two ways.
1. If the class object falls out of scope (for example, a locally declared
class in an exiting function or subroutine), the Finalize() subroutine
is called.
2. The destructor can be called immediately when the class object is set
to a special constant called Nothing :
myClassObject = Nothing
2.7.4 Inheritance
Inheritance is an important topic in object-oriented programming. Inheri-
tance allows one class to take on the characteristics of another class. The new
class, called the derived class, assumes the behavior of the base class (the orig-
inal class). Derived classes can also contain new class members, which act as a
superset of the base class.
Why and how should inheritance be used? Inheritance enables code
reuse. When designing systems, think about common operations that are per-
formed on different classes. If you find lots of operations in common, it’s best
to make a generic class that covers the functionality of all those classes.
2.7 Object-Oriented Programming 61
Suppose that we work for a retailer who sells different pieces of furniture,
say, chairs and tables. We want to be able to track the merchandise by stock
number, color, and price. We also want a function to display that data. We
could treat a chair and a table as separate classes with member functions and
variables that include the tracking information, but this isn’t necessary. Since
both a chair and a table are pieces of furniture, they share common character-
istics. Stock number, color, and price all describe a piece of furniture.
Inheritance eliminates redundant class definitions. We could begin the
furniture program with a generic furniture class, as shown below.
End Class
This class, FurniturePiece, is the base class. The New constructor in line l
contains initialization code for the common furniture characteristics. We’ve also
defined the member function that displays the furniture data. There’s a new
keyword in line m, Overridable, that we’ll discuss further in the next section.
Let’s define the Chair and Table classes, using inheritance from the
base class.
FabricStyle = strFabricStyle
ChairType = strChairType
End Sub
Wood = strWood
End Sub
End Class
Sub Main()
Dim myChair As Chair
myChair = New Chair("123", "Brown", 299.99, _
"Paisley", "Rocker")
myChair.DisplayInfo()
Console.ReadLine()
End Sub
Sometimes you’ll need to access base class members inside a derived class.
Use the MyBase keyword for that. As an example, let’s modify the overridden
DisplayInfo() function of the Chair class to include a call to the base class
DisplayInfo() function.
64 Chapter 2 The VB.NET Crash Course
MyBase.DisplayInfo()
Now the test program will display the output shown in Figure 2-5.
Another special keyword used in inheritance is MyClass. Use it when you
want to refer to the class you are currently “in”—that is, if you wish to call a
2.7 Object-Oriented Programming 65
Modifier/Statement Use
Inherits classname Designates that the current class will inherit classname
NotInheritable Specifies that the current class can’t be inherited by another class
MustInherit Specifies that the class cannot be created on its own (using
New)—a derived class must be created from this class
Modifier Use
function or subroutine that is inside a class block and you are currently writing
code within that block, use the MyClass keyword to reference it. Here’s how it
works in this example class.
66 Chapter 2 The VB.NET Crash Course
Figure 2-5 Output of the furniture class demo with call to base class
DisplayInfo() function
FabricStyle = strFabricStyle
ChairType = strChairType
End Sub
MyBase.DisplayInfo()
MyClass.SomeFunction()
End Class
You can also use the keyword Me in place of MyClass. These keywords are
equivalent, so use whichever form makes most sense to you.
2.7.6 Overloading
Normally, procedure and property names must have a unique name. However,
there might be circumstances in which you must create duplicate procedure
and property names. This OOP concept is known as overloading.
Overloading a function is necessary when you want to have a common
name for a procedure or property that operates on different data types.
This allows simplification of code since you don’t have to write separate
procedures with different names for each data type you’re handling. Here’s
an example.
As Boolean
' Do something here with the string parameter . . .
End Function
When the overloaded function is called, VB.NET invokes the function for
the correct parameter type passed to it. Semantically, these functions should
perform the same type of operation. In other words, both of these example
functions should contain the same application logic.
Imports System
Module Module1
End Class
End Class
u objVehicle.StartEngine()
v blnDidEngineDied = objVehicle.Accelerate(5)
w objVehicle.StopEngine()
End Sub
Sub DoPolymorphismDemo()
x DoVehicleOperations(objMinivan)
y DoVehicleOperations(objTruck)
End Sub
Sub Main()
DoPolymorphismDemo()
Console.ReadLine()
End Sub
End Module
It’s no surprise that we’re using inheritance here. It makes sense in this
case since a truck and a minivan are both vehicles. But unlike the previous
inheritance examples, the base class Vehicle provides no implementation of
its own, hence the class modifier MustInherit in line o. We define member
functions here, but we do not implement them. That’s the job of the derived
classes, Truck and Minivan.
Now comes the inheritance part. Truck and Minivan both inherit from
Vehicle in the usual way using the Inherits keyword in lines p and s.
Since the Vehicle class is marked as MustInherit, we need to make imple-
mentations for each function that we define in Vehicle. That’s a requirement
of a class marked as MustInherit. We create those implementations in lines q
and r. For the sake of this demonstration, the implementations are very sim-
ple. The only goal is to provide console output that identifies whether we are
dealing with a truck or a minivan.
The subroutine DoPolymorphismDemo() does the real work of the demon-
stration program. We begin by declaring and instantiating new Truck and
Minivan class objects. We then call the DoVehicleOperations() function in
line t. Pay close attention to the parameter of this function, objVehicle. Its
type is Vehicle, which is the name of the base class. We then call each method
of the objVehicle object. Then the magic of polymorphism happens (see lines
u through y). Without any logic on our part, VB.NET determines the type of
object passed to DoVehicleOperations() and calls the appropriate overridden
subroutine or function based on the “real” type of objVehicle.
The output of the polymorphism demonstration program appears in Fig-
ure 2-6.
This type of polymorphism is called inheritance polymorphism. This is not
the only way you can implement polymorphism in VB.NET. You can also
implement polymorphism by using interfaces, a technique covered in the next
two sections.
2.7 Object-Oriented Programming 71
2.7.8 Interfaces
Interfaces are similar to classes; they group together members, properties, and
methods but do not provide any implementations of those members, proper-
ties, and methods. Interfaces allow you to implement a contract that specifies
how a programmer can communicate with a class. Interfaces have been a cen-
tral part of Microsoft’s component strategy, in particular the popular Compo-
nent Object Model (COM). All the design advantages that interfaces brought
to COM have been carried over into the .NET Framework.
Interfaces specify a protocol of communication between the implementer
and the caller of the class. An interface is a contract that cannot be broken
(without consequences, like breaking the application). This may seem limiting,
but in reality it is quite powerful.
To illustrate, let’s imagine that we designed a class with some particular
features. Afterward, the class is coded, tested, and deployed in a production
environment. After the customers have used the application for a while, they
request that new features be implemented. Also, testing after deployment dis-
covers some bugs due to logic errors. The features and bugs are tied to our
class. Our job is to implement the new features and fix the bugs.
72 Chapter 2 The VB.NET Crash Course
Interface IMyClassInterface
Sub MyProc(ByVal intParam1 As Integer)
Sub YourProc(ByVal strText1 As String)
Function AnybodysProc(ByVal intSomeParam As Integer) _
As Boolean
End Interface
End Function
End Class
objMyClass.MyProc(1)
objMyClass.YourProc("test")
blnReturnValue = objMyClass.AnybodysProc(1)
We start with the Dim statement in line ~. This creates a variable to hold
an object reference to our interface IMyClassInterface. We create an
instance of CMyClass in line Ö, but instead of assigning the return value
of New to a variable of type CMyClass, we assign it to a variable of type
IMyClassInterface. This causes VB.NET to use the interface we defined
rather than the default one provided by CMyClass.
Now let’s go back to the code modification scenario we discussed previ-
ously. We want to define an alternative interface to our class to allow client
software (program code that uses the class) to use either interface depending
on design requirements. We can define an alternative interface as shown
below.
Interface IMyAlternativeClassInterface
Inherits IMyClassInterface
74 Chapter 2 The VB.NET Crash Course
Sub MyAltSub()
End Interface
Now we can reference the new interface and call the new subroutines.
Since the new interface inherited from IMyClassInterface, we can still call
all of the subroutines and functions from that interface.
Å objMyClass.MyAltSub()
objMyClass.MyProc(1)
2.7 Object-Oriented Programming 75
objMyClass.YourProc("test")
blnReturnValue = objMyClass.AnybodysProc(1)
Console.ReadLine()
Interface IGameWeapon
ReadOnly Property NumOfRounds() As Double
Function Fire(ByVal TargetLocationX As Double, _
ByVal TargetLocationY As Double, _
ByVal TargetLocationZ As Double) _
As Boolean
Sub Reload(ByVal Rounds As Integer)
End Interface
m_intMagazine += Rounds
End If
End Sub
End Class
End Function
End Sub
End Class
Weapon.Reload(5)
If Not Weapon.Fire(1, 2, 3) Then
Console.WriteLine("Run for cover!")
End If
End Sub
Sub Main()
Dim objMachineGun As New CMachineGun()
Dim objRocketLauncher As New CRocketLauncher()
ReloadAndAttack(objMachineGun)
ReloadAndAttack(objRocketLauncher)
Console.ReadLine()
End Sub
2.8 Multithreaded Programming 79
In the main subroutine, we create two objects, one for each weapon. The
subroutine ReloadAndAttack() demonstrates the polymorphism of interfaces.
The subroutine takes a single parameter, Weapon, which is of type
IGameWeapon (the interface we defined). We call ReloadAndAttack() with
both objMachineGun and objRocketLauncher. Remember that this is legal
since both classes implement the IGameWeapon interface.
Inside the ReloadAndAttack() function, we call Fire() and Reload()
for Weapon. VB.NET polymorphism ensures that the correct implementations
for these procedures are called (see Figure 2-7).
VB.NET and the .NET Framework include provisions for making free-
threaded applications. The .NET Framework is massive and contains hun-
dreds of class objects that perform many functions. For now, we will consider
a particular class, System.Threading.Thread, which is used to “spawn,” or
create, a new thread.
To understand the concept of free-threading, it helps to see a visual
example of how code follows an execution path when it is running on a separate
thread. Let’s create a program with two threads. Each thread prints out a mes-
sage that identifies itself 200 times. This is handled in two separate functions,
ThreadOneProc() and ThreadTwoProc(), which execute simultaneously.
Imports System
Module Module1
Sub Main()
! Dim thd1 As New _
System.Threading.Thread(AddressOf ThreadOneProc)
# thd1.Start()
$ thd2.Start()
End Sub
End Module
address in memory of the procedure to run for the thread. We use the
VB.NET statement AddressOf to determine the address in memory for a
procedure.
82 Chapter 2 The VB.NET Crash Course
Calling the Start() method of the thread object, as shown in lines # and
$, starts execution of the thread. The current thread (in this case, the main
program) continues and starts the second thread. When both threads have
finished, the program exits.
same set of data. Sometimes a program must wait until termination of a thread
so the other thread will have accurate data that was processed by the first
thread. Coordinating threads is called thread synchronization.
Generally two methods are used to synchronize threads in VB.NET: by
using the IsAlive() function of System.Threading.Thread or by using
events. Let’s start by looking at IsAlive(). (We’ll explore events in the next
section.)
In this example, we will create a large array of random numbers and sort
them in ascending order using a sort procedure. If you were ever a computer
science student, you most certainly have been exposed to the bubble sort algo-
rithm. The bubble sort works by visiting each element in the array and com-
paring its value to the adjacent element’s value. If one is greater than (or less
than, depending on how the elements are to be sorted) the other, the values
are swapped. This process repeats throughout the array until all the elements
are ordered correctly. There are many sort algorithms, but the bubble sort is
the easiest to understand. It is also the slowest. Choosing bubble sort enables
the sample program to run slowly enough so we can observe its behavior easily
while the program runs.
The code example below contains a class named CNumberList. This class
contains an array of integers to sort and two member subroutines called
Sort() and PrintList(), which are self-explanatory. The constructor for
CNumberList takes a parameter for the size of the array to create. The array is
then filled with random numbers in the range of 0 to 10,000. The program
creates a large array so the program will run long enough for us to observe its
execution in the console window.
Imports System
Imports Microsoft.VisualBasic
Module Module1
Dim objList As CNumberList
ReDim m_aryNumbers(intSize + 1)
Next
Next
End Sub
End Sub
End Class
Sub Main()
â thdSortThread.Start()
( Do While thdSortThread.IsAlive()
Console.Write(“.”)
Loop
objList.PrintList()
End Sub
End Module
The main program creates a new CNumberList object with 1,500 integers
in line %. Then, a thread is created for the Sort() function in line &. In line
â, the thread is started. Before we call the PrintList() method to display
the sorted list, we need to wait until the Sort() function/thread is finished
sorting the numbers. So, we make a Do . . . While loop in line ( that contin-
ually checks to see if the sort thread is still running. If the thread is still alive,
the program will output a period (.) to the console to visually indicate that the
sort is running. On termination of the thread, the Do . . . While loop exits
and the sorted array is displayed. In effect, we’ve synchronized the sort thread
with the main thread of the application.
Using IsAlive() is easy, but it is not very efficient. A better way to syn-
chronize threads is to use events.
When you want to raise an event (and subsequently notify the hosting
code of the event), simply call the RaiseEvent statement:
RaiseEvent SomethingHappened()
WithEvents tells VB.NET that you wish to use the events defined by the
class. Using Dim WithEvents works only on nonlocal declarations. In other
words, declarations like this need to be made at the global level or at the
module level.
Let’s modify the previous example to synchronize the threads by using
events. The boldface lines indicate the changes made to the previous code.
Imports System
Imports Microsoft.VisualBasic
Module Module1
Dim WithEvents objList As CNumberList
ReDim m_aryNumbers(intSize + 1)
Next
End Sub
Next
RaiseEvent Progress(CInt(intCounter2 / _
UBound(m_aryNumbers) * 100))
Next
RaiseEvent Done()
End Sub
End Sub
End Class
Sub Main()
Console.WriteLine(_
"Starting sort . . . Press <enter> to cancel")
Console.WriteLine("Percent Complete:")
thdSortThread.Start()
Console.ReadLine()
Console.WriteLine("Ending . . .")
thdSortThread.Abort()
End Sub
The modified example contains two new features, thanks to the conve-
nience that free-threading and events provide.
1. The user can cancel a sort operation already in progress by hitting the
Enter key. After the sort thread is started, main execution continues on
to a call to Console.ReadLine() in the main thread. The program
waits for the user to hit the Enter key. If this happens, the program
calls thdSortThread.Abort() to immediately terminate execution of
the sort thread.
2. The user sees a visual indicator about the progression of the sort.
The Progress() event is raised periodically to indicate progression
of the sort operation. Finally, when the Done() event is raised, the
user knows that the sort thread has ended and can print out the
sorted list.
Figure 2-9 shows the program in action.
2.9 Summary
Take a deep breath. We covered quite a lot in this VB.NET crash course,
including basic concepts about:
■ The role of VB.NET as part of Microsoft VS.NET and as the
.NET-enabled version of Visual Basic, a language with a rich
history on the Windows platform
■ The VS.NET Integrated Development Environment
■ Variables and data types
■ Conditional processing, looping, and flow control statements
■ Object-oriented programming techniques
■ Simple free-threading concepts
As a result, by working through this chapter you have learned how to:
■ Create a new project, enter code, compile code, and run sample
programs
■ Make console applications
■ Use the Console.WriteLine() and Console.ReadLine() statements
to display output to and get keyboard input from users, respectively
■ Write procedures (functions and subroutines) to modularize your code
and make it more readable
■ Convert variables from one type to another
■ Control program flow
■ Use classes, inheritance, overloading, polymorphism, interfaces, and
free-threading
Congratulations! You’re ready to move on to the next step in Web pro-
gramming with VB.NET.
■ Further Reading
ASP.NET is the framework you’ll use to build Web applications for the .NET
Framework. One of the design goals of ASP.NET was to bring to the Web the
same rich application features (as close as possible) used in traditional desktop
applications. ASP.NET achieves this by providing a flexible development
methodology that allows the use of any .NET-capable language to code
dynamic Web pages. ASP.NET also frees up the Web application developer
from many mundane programming tasks by providing built-in code objects
for many common Web-programming tasks.
Compiled Code
Many Web application development environments don’t provide an environ-
ment that takes advantage of features available to desktop applications,
primarily because Web development languages are generally interpreted.
Prior versions of ASP are an example of this. ASP in its previous incarnations
93
94 Chapter 3 Working with ASP.NET
tion state. ASP.NET has several offerings for maintaining application state,
and some are even compatible with older versions of ASP. And, of course,
ASP.NET offers advanced state management that improves on the legacy
methods of state management.
<html>
<body>
<form id=WebForm1
method=post
f runat="server">
g <asp:TextBox id=txtEnteredVal
runat="server">
</asp:TextBox><br>
3.2 The Anatomy of ASP.NET Pages 97
h <asp:Button id=cmdSend
runat="server"
Text="Send">
</asp:Button><br>
i <asp:Label id=lblDisplay
runat="server"
Width="101"
Height="19">
</asp:Label>
</form>
</body>
</html>
At first glance, this .aspx file looks much like an ordinary HTML file, but
on closer inspection, you’ll see several items that you won’t recognize as stan-
dard HTML (see the numbered lines). This .aspx file contains three new
items of interest:
1. ASP.NET page directives (shown in line e)
2. The runat="server" attribute (shown in line f)
3. Web Controls (shown in lines g, h, and i)
Page directives provide ASP.NET with information about the code con-
tained in the file. They can be located anywhere in the file, but they are gener-
ally placed at the top. Page directives allow for customization of compiler
settings. We’ll investigate page directives in detail in Section 3.16.
I stated earlier that ASP.NET allows you to separate content (HTML)
from application logic. Often you will want to expose some HTML elements
to the ASP.NET object model. These HTML items, in a sense, are executed
on the server. The runat="server" attribute instructs the page compiler to
preprocess these HTML elements on the server rather than simply serving up
the HTML text back to the browser. The HTML <form> tag that appears just
above line f shows the use of the runat="server" attribute.
Web Controls are server-side code pieces that perform a variety of func-
tions. We’ll talk about Web Controls in depth in Sections 3.8 through 3.14, but
for now, let’s say that the Web Controls defined in lines g through i are user-
interface elements that interact with the server.
When a browser requests the .aspx file shown above, the result returned
to the browser looks something like Figure 3-1.
98 Chapter 3 Working with ASP.NET
The HTML delivered to the browser should look familiar since it is plain
HTML 3.2 (some formatting has been added for readability).
<html>
<head>
<title>Example .ASPX File</title>
</head>
3.2 The Anatomy of ASP.NET Pages 99
<body>
<form name="WebForm1" method="post"
action="Webform1.aspx" id="WebForm1">
<input type="hidden" name="__VIEWSTATE"
value="YTB6LTEwNzAyOTU3NjJfX1949e1355cb" />
<input name="txtEnteredVal"
type="text" id="txtEnteredVal" /><br>
<span id="lblDisplay"
style="height:19px;width:101px;"></span>
</form>
</body>
</html>
can provide immediate feedback from form input. This type of feedback is
generally limited to simple data validation and is handled using client-side
scripts. Data validation using this method can check for conditions such as
form completeness, numerical ranges, and correct data formatting. Functions
such as searching a database require a round-trip to the server since the data
to be searched is stored on the server.
I mentioned in Chapter 1 that an inherent characteristic of Web servers
is their stateless nature. This means that once a request of a document or
program is made of the Web server, the Web server normally discards all
information that was sent as input. As a result, the Web page must be regen-
erated from scratch for every round-trip. Keeping state is valuable because
subsequent requests to other pages may want to access data values returned
from other pages. Traditional desktop applications never had a problem
keeping state. Because desktop applications are typically loaded into mem-
ory once and are kept in memory until the user exits the application, the
program can freely store any values it needs in the memory allocated for
the application. As Web applications become more advanced and function
more like desktop applications, a reliable state-management system is
required.
Fortunately, many state-management tasks in ASP.NET are done for you,
and other state-management tasks can be accomplished in a number of ways.
The ASP.NET Web Controls and HTML Controls, for instance, can maintain
their associated values between round-trips without any coding effort on your
part. This is called the view state.
View state is maintained using the __VIEWSTATE hidden form field, which
is automatically generated by ASP.NET for every .aspx file that contains a
server-side form. In the previous section, the source generated by ASP.NET
showed the __VIEWSTATE hidden field with an encoded text string as its value.
This encoded text string contains information about the state (values) of the
server-side controls on the form. When the form is posted back to the server,
the __VIEWSTATE will be posted along with the other form values. Form values
that haven’t been changed by the user are restored with values encoded in the
__VIEWSTATE value from the previous post.
You can specify event-handling code for these events in your .aspx file.
Consider the following .aspx file with code in place for responding to the
Page_Load and Page_Unload events.
<body>
<form id="WebForm2"
method="post"
runat="server">
Page state:
<asp:Label id=lblSampleLabel
runat="server">
</asp:Label>
</form>
</body>
</html>
When we request this page, we get the output shown in Figure 3-2.
The Page_Load event is fired when the page and all its controls are ren-
dered. The code then displays the message “Loaded!” in the lblSampleLabel
Control. Page_Unload is fired when the page is about to be discarded. This is
where cleanup code is placed (freeing objects and so on). Any references
made to visual elements in this event are not recognized since Page_Unload is
fired after page processing is complete.
102 Chapter 3 Working with ASP.NET
top application development, but ASP.NET Web Forms deliver, for the first
time, this type of functionality to the Web browser.
Web Forms allow for the separation of application logic from content. On
older Web-development systems, application code (typically script code) was
interspersed with HTML. The main advantage of this separation is to facilitate
better team-based development. Designers who work with layout and content
can create the visual look and feel of the page without interrupting the work of
the Web programmers who place the application logic that drives the page’s
functionality.
Web Forms work closely with the VS.NET Integrated Development Envi-
ronment (IDE) to provide an easy design-time development experience.
Users of Visual Studio have long enjoyed the benefits of rapid application
development (RAD) by combining event-based programming with easy-to-use
form design tools. With VS.NET, you can use those same RAD features to
construct ASP.NET pages with greater ease than ever before. In addition, if
you’ve programmed applications using Visual Basic’s Forms Designer in the
past, you’ll be pleased to find a similar interface in VS.NET.
ASP.NET frees developers from having to write less routine code typically
associated with Web applications. It accomplishes this by providing a standard
set of server-based controls for many common tasks, such as data entry valida-
tion. We’ll investigate these great timesaving controls in coming sections.
End Sub
End Sub
#End Region
End Sub
End Class
This code-behind module defines a new class for the Web Form and cre-
ates plumbing code. Notice that VS.NET assigned the class the same name
106 Chapter 3 Working with ASP.NET
given to the Web Form in Figure 3-5, MyWebForm (see line j). This class
inherits from the Page class (see line k), which is a predefined ASP.NET class.
This exposes the Page class’s events and other properties and methods so they
can be used within the new class. Two inherited Page event handlers are
defined for us, Page_Init and Page_Load, in lines l and m, respectively.
As you develop a Web Form using the VS.NET IDE, you will see code
added to the code-behind module. In particular, code will be generated in
response to new Web Controls placed on the Web Form. During the discus-
sions of Web Controls that appear later in this book, we will constantly be
referring back to the code-behind file, so it’s important to familiarize yourself
with its structure.
3.5 Separating Content and Code—the Code-Behind Feature 107
When you use the VS.NET IDE to create Web applications, the IDE is
configured to generate the above code for you. Whenever you create a new
Web Form (from the New menu), this and other “boilerplate” Web Form
code is placed in the file. The code-behind module (the .vb file) is also gener-
ated with some event-handling code (we’ll discuss this in a moment).
You have other options when specifying a code-behind class. You may also
specify an Src attribute, which tells ASP.NET where your class file is located.
If omitted, ASP.NET assumes that the class is located in the /bin directory of
the Web application. Looking at the previous example, we can represent the
same thing using this form.
Imports System.Web
Imports System.Web.SessionState
End Sub
End Sub
3.7 Using HTML Controls 109
End Sub
End Sub
End Sub
End Sub
End Class
HTML and pre-.NET ASP pages can be migrated over to ASP.NET easily by
simply adding a runat="server" attribute to each tag.
The method for programming with HTML Controls should be familiar to
anyone who has worked with the corresponding HTML elements. In effect,
an HTML Control becomes an object you can reference using the usual
HTMLAnchor <a>
HTMLButton <button>
HTMLForm <form>
HTMLImage <img>
HTMLSelect <select>
HTMLTable <table>
HTMLTableCell <td>
HTMLTableRow <tr>
HTMLTextArea <textarea>
3.7 Using HTML Controls 111
txtMyTextField.Text = “sometext"
<form
runat="server"
id="programmaticID"
method=POST | GET
action="srcpageURL"
>
other HTML and server controls go here
</form>
In most cases you should set the method attribute to POST. ASP.NET
relies on values posted back to the server in a hidden form variable for control
state management. The server recognizes this hidden data only when it is sent
via the POST mechanism.
<a
runat="server"
id="programmaticID"
href="linkurl"
name="bookmarkname"
OnServerClick="onserverclickhandler"
target="linkedcontentframeorwindow"
title="titledisplayedbybrowser"
>
linktext
</a>
The href, name, target, and title properties can be set at runtime. The
OnServerClick procedure is fired when the anchor link text is clicked. For
example, here’s how to dynamically generate anchor tags and change the
title attribute based on the anchor clicked.
</script>
</head>
<body>
<form id="HtmlAnchorSample"
method="post"
runat="server">
<h1>HtmlAnchor Example</h1>
<p><a href="htmlanchorsample.aspx"
id=AChoice1
onserverclick="AChoice1_click"
runat="server">Choice 1</a>
</p>
<p><a href="htmlanchorsample.aspx"
id=AChoice2
onserverclick="AChoice2_click"
runat="server">Choice 2</a>
</p>
<p><a href="htmlanchorsample.aspx"
id=AChoice3
onserverclick="AChoice3_click"
runat="server">Choice 3</a>
</p>
</form>
</body>
</html>
Notice in Figure 3-6 that the title attribute is not the default title string we
set in the Page_Load event but the new “CLICKED” string set by the
OnServerClick event-handler code. In most current Web browsers, the
HTML title attribute text serves as the floating “tool-tip” text for the anchor.
<button
runat="server"
id="programmaticID"
OnServerClick="onserverclickhandler"
>
inner HTML goes here
</button>
Cascading Style Sheet (CSS) styles change the default appearance of the
button. You can use many different style combinations to achieve the exact
3.7 Using HTML Controls 115
look you desire. Here’s code for a button that is yellow with bold, italic blue
text.
<form id="HTMLButtonExample"
method="post"
runat="server">
<h1>HTML Button Sample</h1>
<button runat="server"
style="FONT-WEIGHT:
bolder;
COLOR: blue;
FONT-STYLE:
italic;
FONT-FAMILY:
Verdana;
BACKGROUND-COLOR: yellow">
Click this button
</button>
</form>
</body>
</html>
strOutputString = "<OL>"
For intCount = 1 To 5
strOutputString &= "<LI>Numbered list"
Next
strOutputString &= "</OL>"
lblMyText.InnerHTML = strOutputString
End Sub
</script>
</head>
<body>
<form id="HTMLGenericControl"
method="post"
runat="server">
<h1>HTMLGenericControl Example</h1>
3.7 Using HTML Controls 117
Span text:
<span id=lblMyText
runat="server">
</span>
</form>
</body>
This example builds a simple HTML ordered list and puts the HTML text
into a string when the Page_Load event fires. Then the InnerHTML property is
set for the HTMLGenericControl lblMyText. This dynamically inserts the
ordered list between the <span> tags. The output appears in Figure 3-7.
<img
id="programmaticID"
runat="server"
alt="alttext"
align= top | middle | bottom | left | right
border="borderwidth"
height="imageheight"
src="imageURI"
width="imagewidth"
>
img2.width *= 0.50
img2.alt = "Image at 50%"
End Sub
</script>
</head>
<body>
<form id="HTMLImageSample"
method="post"
runat="server">
<h1>HTMLImage Sample</h1>
<p>This will display an image at three
different sizes from the original: 25%,
50%, and 75%
</p>
<p>
<table cellspacing=1 cellpadding=1 width=300 border=1>
<tr>
<td><img id=imgOriginal height=266
alt="mountain (Original Size)"
src="mountain.jpg"
width=366
runat="server"></td>
<td><img id=img1 height=266
alt=""
src="mountain.jpg"
width=366
runat="server"></td>
</tr>
<tr>
<td><img id=Img2 height=266
alt=""
src="mountain.jpg"
width=366
runat="server"></td>
<td><img id=Img3
120 Chapter 3 Working with ASP.NET
height=266
alt=""
src="mountain.jpg"
width=366
runat="server"></td>
</tr>
</table>
</p>
</form>
</body>
</html>
<input
type=button | submit | reset
runat="server"
id="programmaticID"
OnServerClick="onserverclickhandler"
>
In HTML 3.2, submit buttons cause the contents of the form to be sent to
the server at the location specified in the enclosing <form>’s action URL.
Reset buttons cause all the values entered in input elements on the form to be
erased or set back to their default values. General-purpose buttons are used
for customized actions that don’t necessarily behave like form submittals, typi-
cally in conjunction with client-side script.
3.7 Using HTML Controls 121
</script>
</head>
<body>
<form id="HTMLInputButtonSample"
method="post"
runat="server">
<h1>HTMLInputButton Example</h1>
<p>
<input type=button
value="Value One"
id="btnInputButton"
OnServerClick="btnReset_Click"
runat="server">
</p>
</form>
</body>
</html>
3.7 Using HTML Controls 123
<input
type=checkbox
runat="server"
id="programmaticID"
checked
>
Let’s make a form with some sample checkbox entries and a submit
button.
If ckbRed.Checked Then
strResponse &= "Red "
End If
If ckbYellow.Checked Then
strResponse &= "Yellow "
End If
If ckbGreen.Checked Then
strResponse &= "Green "
End If
If ckbBlue.Checked Then
strResponse &= "Blue "
End If
124 Chapter 3 Working with ASP.NET
If Page.IsPostBack Then
lblText.InnerHTML = "You selected: " & strResponse
End If
End Sub
</script>
</head>
<body>
<form id="HTMLInputCheckBoxSample"
method="post"
runat="server">
<h1>HTMLInputCheckBox Example</h1>
<p>Please make your color selections:</p>
<p>
<input id=ckbRed
type=checkbox
runat="server"> Red</p>
<p>
<input id=ckbYellow
type=checkbox
runat="server"> Yellow</p>
<p>
<input id=ckbBlue
type=checkbox
runat="server"> Blue</p>
<p>
<input id=ckbGreen
type=checkbox
runat="server"> Green</p>
<p>
<input id=btnSubmit
runat="server"
type=submit
onserverclick="btnSubmit_Click"
value=Submit>
</p>
</form>
<div id="lblText" runat="server"></div>
</body>
</html>
3.7 Using HTML Controls 125
This page displays a series of four checkboxes (see Figure 3-9). The user
can select any number of these boxes. By using the Boolean Checked property
of the HTMLInputCheckBox Control the program tests each checkbox to see if
it was selected. The property is true if the user checks the box.
<input
type=file
runat="server"
id="programmaticID"
accept="MIMEencodings"
maxlength="maxfilepathlength"
size="widthoffilepathtextbox"
postedfile="uploadedfile"
>
A simple form that accepts a file for posting illustrates this three-step
process. Let’s start with the posting form.
End Function
strFileName = GetFileNameFromPath(_
filSelectFile.PostedFile.FileName)
strSavePath = Server.MapPath("\Samples2")
p filSelectFile.PostedFile.SaveAs(strSavePath & "\" & _
strFileName)
End Sub
</script>
</head>
<body>
q <form id="HTMLInputFileSample"
method="post"
enctype="multipart/form-data"
runat="server">
<h1>HTMLInputFile Example</h1>
<p>Please select a file to upload to the server:</p>
<p>
<input id=filSelectFile
type=file
runat="server">
</p>
<p>
r <INPUT id=btnSubmit
type="submit"
value="Submit"
OnServerClick="btnSubmit_Click"
runat="server">
</p>
<p>
128 Chapter 3 Working with ASP.NET
<span id=lblFileInfo
runat="server">
</span>
</p>
</form>
</body>
</html>
The form resulting from this code looks similar to that shown in
Figure 3-10.
The file is uploaded with a post-back to the server (that is, when the user
clicks the submit button). The btnSubmit_Click event procedure coded in
line o handles that form-submission event. In this procedure, retrieving the
file data that was posted and saving it to the server’s storage area is a two-step
process.
1. Obtain the file name from the posted file. Information about the
posted file is contained in the PostedFile object (see line p), which
is a member of the HTMLInputFile Control. FileName holds the com-
plete pathname of the file selected on the user’s workstation. The
GetFileNameFromPath() function defined on line n extracts the file
name from the absolute path in FileName.
3.7 Using HTML Controls 129
2. Save the file on the server. To save the file, we need to obtain the
absolute, physical path to the location to which we wish to save
the file. We obtain this location by using the MapPath() method of
the ASP.NET Server object. I’ll explain this object in detail in
Section 3.23, but for now I’ll just explain the MapPath() method.
It returns the physical path for a given virtual path (for example,
c:\inetpub\wwwroot\images for \images). Then, the SaveAs()
method of the PostedFile object saves the actual file with the file
name extracted from the POST request into the directory obtained
from MapPath().
<input
type="hidden"
runat="server"
id="programmaticID"
value="contentsofhiddenfield"
>
Whatever the purposes for using hidden form variables, ASP.NET makes
it just as easy to use them as it is to use other HTML Controls. The quick
example below provides a simple demonstration of the HTMLInputHidden
form variable, showing how to increment the value of a hidden variable with
each post-back to the server.
<form id="HTMLInputHidden"
method="post"
runat="server">
<h1>HTMLInputHidden Example</h1>
<p>
<input id=hdnHiddenField
type=hidden
runat="server"
value="0">
</p>
<p>
<input type="submit"
runat="server"
value="Submit">
</p>
<p>
<span id=lblCounter
runat="server">
</span>
</p>
</form>
</body>
</html>
<input
type=image
runat="server"
id="programmaticID"
src="imagepath"
align="imagealignment"
alt="alttext"
OnServerClick="onserverclickhandler"
width="borderwidthinpixels"
>
End Sub
</script>
</head>
<body>
<form id="WebForm1"
method="post"
runat="server">
<h1>HTMLInputImage Example</h1>
<p>Click a button below to highlight your choice:</p>
<input id=imgImage1
type=image
src=wb1.gif
runat="server"
OnServerClick="imgImage1_Click">Choice 1
<br>
<input id=imgImage2
type=image
src=wb1.gif
runat="server"
OnServerClick="imgImage2_Click">Choice 2
<br>
<input id=imgImage3
type=image
src=wb1.gif
runat="server"
OnServerClick="imgImage3_Click">Choice 3
</form>
</body>
</html>
This example presents the user with three graphical buttons. Each of
the buttons responds to a user click, which in turn causes a post-back to
the server. The event-handling procedure for each button changes the
button’s graphic to an alternate image (showing that the button has been
selected). The other buttons’ images are then reverted back to their original
images.
134 Chapter 3 Working with ASP.NET
<input
type=radio
runat="server"
id="programmaticID"
checked
name="radiobuttongroup"
>
If rdbYearlyIncome1.Checked Then
strResults &= "Less than $25,000/yr"
End If
If rdbYearlyIncome2.Checked Then
3.7 Using HTML Controls 135
If rdbYearlyIncome3.Checked Then
strResults &= "$51,000 or more/yr"
End If
If Radio1.Checked Then
strResults &= "E-mail newsletter"
End If
If Radio2.Checked Then
strResults &= "Magazine Ad"
End If
If Radio3.Checked Then
strResults &= "Other"
End If
End Sub
</script>
</head>
<body>
<form id="HTMLInputRadio"
method="post"
runat="server">
<h1>HTMLInputRadio Example</h1>
<p>Please answer our short survey:</p>
<ol>
<li><b>What is your yearly income?</b><br>
<input id=rdbYearlyIncome1
checked name="YearlyIncome"
type=radio
runat="server">Less than $25,000/yr<br>
<input id=rdbYearlyIncome2
name="YearlyIncome"
type=radio
runat="server">$26,000 - $50,000/yr<br>
<input id=rdbYearlyIncome3
136 Chapter 3 Working with ASP.NET
name="YearlyIncome"
type=radio
runat="server">$51,000 or more/yr<br>
<li><b>How did you hear about our Web site?</b><br>
<input id=Radio1
name="HearAboutUs"
type=radio
checked runat="server">E-mail newsletter<br>
<input id=Radio2
name="HearAboutUs"
type=radio
runat="server">Magazine Ad<br>
<input id=Radio3
name="HearAboutUs"
type=radio
runat="server">Other<br>
<li>
<INPUT id=cmdSendSurvey
type="submit"
value="Send Survey"
runat="server"
onserverclick="cmdSendSurvey_Click">
</form>
</LI>
</OL>
<p>
<span id=lblResults
runat="server">
</span>
</p>
</body>
</html>
The results of this sample code are shown in Figure 3-11. The code
has two groups of radio buttons: YearlyIncome and HearAboutUs. This way,
only one choice can be made for each question. We set the subroutine
cmdSendSurvey_Click to be the event handler for the OnServerClick
event for the Send Survey button. The Checked property of the
HTMLInputRadioButton Control is of particular interest. This is how the
program checks to see which option was selected for a particular radio
button group. The code in the subroutine checks each button individually
3.7 Using HTML Controls 137
and simultaneously builds a result string. This result string contains the text
of the options that were selected. Finally, the result string is assigned to the
InnerHTML property of lblResults, which displays the result.
<input
type=text | password
runat="server"
id="programmaticID"
maxlength="max#ofcharacters"
size="widthoftextbox"
value="defaulttextboxcontents"
>
If Page.IsPostBack Then
If Len(txtPassword.Value) <= 4 Then
lblResults.InnerHTML = _
"<font color=red>Password must be longer than 4 characters</font>"
Else
lblResults.InnerHTML = "Welcome, " & _
txtUsername.Value
End If
End If
End Sub
</script>
</head>
3.7 Using HTML Controls 139
<body>
<form id=frmMain
runat="server">
<h1>HTMLInputText Example</h1>
<span id=lblResults
runat="server">
</span>
<ol>
<li>Choose a username
(maximum of 10 characters)<br>
<INPUT id=txtUsername
type="text"
maxlength=10
runat="server">
<INPUT id=txtPassword
type="password"
maxlength=8
runat="server">
<li><INPUT id=cmdSubmit
type="submit"
value="Submit"
runat="server"></li>
</ol>
</form>
</body>
</html>
list box. Each of these types of input elements is implemented with the
HTMLSelect Control.
The difference between the two types of lists is controlled by the size
attribute of the control. If the size attribute is set to 1 or is not specified, a
drop-down list is rendered. If the size attribute is greater than 1, a list box is
rendered that displays size number of items at a time.
The HTMLSelect Control also supports a new type of event: the
OnServerChange event. This event is fired when the user makes a change in
the selection. Note that a selection change does not cause a post-back to the
server. The event handler subroutine specified in the OnServerChange event is
executed only upon a post-back to the server. The post-back can occur due to
any event designed to perform a post-back, such as clicking a submit button,
or due to an OnServerClick event from another control.
The HTMLSelect Control can also be bound to a data source. We’ll explore
data access in Chapter 7, where I’ll provide a demonstration of binding data to
the HTMLSelect Control as well as others. For now, here is the complete syn-
tax for the HTMLSelect Control.
<select
runat="server"
id="programmaticID"
OnServerChange="onserverchangehandler"
DataSource="databindingsource"
DataTextField="fieldtodatabindoptiontext"
DataValueField="fieldtodatabindoptionvalue"
Multiple
Items="collectionofoptionelements"
SelectedIndex="indexofcurrentlyselecteditem"
Size="#ofvisibleitems"
Value="currentitemvalue"
>
<option>value1</option>
<option>value2</option>
</select>
</script>
</head>
<body>
<h1>HTMLSelect Example</h1>
<form id=HTMLSelect
method=post
runat="server">
<p>
<span id=lblResults
runat="server">
</span>
<select id=ddlbDropDown
runat="server">
142 Chapter 3 Working with ASP.NET
<option selected></option>
</select>
<select id=lstListBox
size=2
runat="server">
<option></option>
</select>
</p>
<p>
<input id=txtItem
type=text
runat="server">
</p>
<p>
<input id=btnAddToDDLB
type=button
value="Add to Drop-Down List Box"
runat="server"
onserverclick="btnAddToDDLB_Click">
<input id=btnAddToLB
type=button
value="Add to List Box"
runat="server"
onserverclick="btnAddToLB_Click">
</p>
<p>
<input id=btnDisplaySelection
type=button
value="Display Selection"
runat="server"
onserverclick="btnDisplaySelection_Click">
</p>
</form>
</body>
</html>
3.7 Using HTML Controls 143
Dim tr as HTMLTableRow
Dim td as HTMLTableCell
Dim intRowCounter As Integer
Dim intCellCounter As Integer
tr = New HTMLTableRow()
144 Chapter 3 Working with ASP.NET
u tr = New HTMLTableRow()
z tblGridTable.Rows.Add(tr)
Next
End Sub
</script>
</head>
<body>
<form id="HTMLTable"
method="post"
runat="server">
<h1>HTMLTable Example</h1>
<INPUT id=btnGenerateGrid
type="button"
value="Generate Table Grid"
onserverclick="btnGenerateGrid_Click"
runat="server">
3.7 Using HTML Controls 145
<table id=tblGridTable
border=2
runat="server">
</table>
</form>
</body>
</html>
This page begins with a Web Form that contains two text boxes for enter-
ing a number of rows and a number of columns. The Web Form also includes
a blank HTML table with no rows. The values that the user enters for rows
and columns in the text boxes specify the dimensions of the table to create
when the user clicks the Generate Table Grid button.
The subroutine btnGenerateGrid_Click handles the generation of the
new table. The HTML table is made up of rows and cells generated by two
separate HTML Controls called HTMLTableRow and HTMLTableCell, respec-
tively. These types of HTML Controls are known as child controls since they
exist only within the context of a parent control, in this case HTMLTable. The
subroutine uses nested For . . . Next loops to create new cells and rows.
The inner loop that begins in line v creates new table cells. The loop runs as
many times as specified by the value entered by the user for the number of
cells. On each iteration through the loop, the New operator creates a new
HTMLTableCell. Then we set the align and InnerHTML properties for the
newly created cells.
Notice that before we entered the cell creation loop, we created an
HTMLTableRow Control in line u. This serves as the container for the
HTMLTableCell Controls. As the table cells are created, they are added to
a table row through its Cells collection (see line w).
Once the row is filled with the specified number of cells, it is added to the
HTML table through the Rows object in line x. Then the nested loop repeats
until the remaining rows are added to the table.
</script>
</head>
<body>
<form id="HTMLTextArea"
method="post"
runat="server">
<h1>HTMLTextArea Example</h1>
<textarea id=txaFeedback
rows=10
cols=30
runat="server">
[Type your comments here]
</textarea>
<br>
<INPUT id=cmdSendComments
type="submit"
value="Send Comments"
onserverclick="cmdSendComments_Click"
runat="server">
<p>
<span id=lblResults
runat="server"></span>
</p>
3.8 Using Web Controls 147
</form>
</body>
</html>
Property Description
AccessKey Sets the control’s accelerator key, used to jump to a control (set focus)
by pressing an ALT + key combination. Specify a single letter for this
property, such as A. Access keys are not supported on all browsers.
(continued)
148 Chapter 3 Working with ASP.NET
Property Description
BackColor Sets the background color of the control. You can specify the name
of standard Web colors (for example, red, yellow, green) or an RGB
hex value (for example, #3F3023).
BorderWidth Specifies the width of the control’s border in pixels. Not compatible
with some down-level browsers (those other than Microsoft Internet
Explorer).
BorderStyle Sets the style of the control’s border. Can be one of the following:
NotSet, None, Dotted, Dashed, Solid, Double, Groove, Ridge,
Inset, or Outset.
Font.Names Specifies a list of fonts to use for the control. Starting from the
beginning of the list, if a particular font isn’t available, the text is
rendered using the next available font.
Font.Overline Sets whether a line is displayed above the text (true/false value).
Font.Size Specifies the HTML size of the font (a number from 1 to 7).
ForeColor Sets the color of the text, specified as an HTML color or hex
value.
Property Description
TabIndex Specifies the tab order of the control; defaults to 0. Supported only in
Microsoft Internet Explorer 4.0 or greater.
ToolTip Specifies the text to use as a “floating” tool tip. Does not work with
down-level browsers.
Figure 3-12 VS.NET Control Toolbox with the Label Control option selected
generated code for the Label Control you placed on the Web Form. The code
below in boldface shows the Label Control code.
%>
<html>
<head>
<title>Web Control - Label Control</title>
</head>
<body>
<asp:Label
id=lblTestLabel
runat="server">Label
</asp:Label>
</p>
</form>
</body>
</html>
or
As you can see from the syntax example, the Label Control can have two
different forms. The first has a Text attribute that specifies the text to display.
The second syntax form has a closing tag, and any text placed inside the tags
becomes the text for the label. VS.NET uses the first syntax form.
152 Chapter 3 Working with ASP.NET
Imports System
Imports System.Web
Imports System.Drawing
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.HtmlControls
y lblTestLabel.BorderStyle = BorderStyle.Dashed
z lblTestLabel.BorderWidth = Unit.Pixel(5)
lblTestLabel.Height = Unit.Pixel(30)
lblTestLabel.Width = Unit.Pixel(100)
{ lblTestLabel.BackColor = Color.Yellow
lblTestLabel.Enabled = False
| lblTestLabel.Font.Name = "Arial"
} lblTestLabel.Font.Bold = True
lblTestLabel.ToolTip = "This is a tool tip"
lblTestLabel.Text = "This is a test of the Label Web Control"
End Sub
End Class
The Font class controls the appearance of the Label Control’s text. This
includes the font face as well as text styles (bold, italic, underline, and so on).
Lines | and } set the label text for the Arial font in bold.
The rendered Label Control from this code appears in Figure 3-15.
Many of the shared properties can be set at design time for Web Controls.
Also, being able to programmatically set them is a powerful feature. Program-
matically set control properties will override properties set at design time.
regardless of the video hardware used to display them. Web designers often
refer to Web-safe palette charts such as the one we’re about to construct.
Each color swatch in our chart will contain tool-tip text signifying the hex
color value used in HTML.
The Web form is simple. The boldface text in the sample code below
shows how to declare a Panel Control on a Web Form. For visual clarity, we
give the panel for the color chart a width equal to the maximum width of the
browser window.
<form id="WebControlPanel"
method="post"
runat="server">
<p>
<asp:Panel id=pnlColorPanel
runat="server"
Width="100%">
</asp:Panel>
</p>
</form>
</body>
</html>
Imports System
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports Microsoft.VisualBasic
End If
End Sub
End Class
The Page_Load event contains the code to create the color chart. This
code demonstrates two important concepts: creating new Web Controls
158 Chapter 3 Working with ASP.NET
dynamically and working with child controls. First, I’ll explain the logic for
generating the color values.
An HTML color is an RGB value. Each component (red, green, and blue)
of the color has a number assigned to it (0–255). To iterate through the entire
RGB color space, we create three nested For . . . Next loops beginning in
line ~. The program steps through the loop every 51 iterations. That gives
us hex values of 00, 33, 66, 99, CC, and FF. Every color in the Web-safe
palette contains RGB values that are from this set of hex values. When all
three loops have exited, the program has covered each RGB combination.
In the code block beginning in line Ö, each RGB integer value is converted
to a two-character hexadecimal string and concatenated to form a complete
color string.
Line Ä starts the creation of a new Label Control. This label will become
a color swatch. In line Å, we begin a With . . . End With block to set the
properties of the newly created label. These include setting the tool-tip text to
the color string, sizing the label to a 10 × 10 pixel rectangle, and setting the
background color with the current RGB values.
The Panel Control is used as a container for other Web Controls. Recall
the discussion about the HTMLTable Control (see Section 3.7.14) and how it
contained child controls (HTMLTableRow and HTMLTableCell). The Panel
Control works in a similar fashion. Take note of the code in line Ç. The
pnlColorPanel code contains a Controls collection. Part of that Controls
collection is an Add() method. The parameter to the Add() method is a con-
trol object (System.Web.UI.WebControls). Since the Label Control inherits
from System.Web.UI.WebControls, we can pass our dynamically created
Label Control to this method. At that point, each label is positioned sequen-
tially inside the panel we created.
The output of the code written above is shown in Figure 3-16.
New() command. The syntax for the TableRow and TableCell commands
appears below.
Using tables, you can construct some interesting shapes and define some
advanced page layouts. On some Web sites, you may see a figure that looks
like a desktop window. You can simulate this look by using HTML tables. The
Table, TableRow, and TableCell Controls make creating these windows easy
and allow you to control their style characteristics with just minor code
changes.
Here’s the example code, starting with the .aspx file that contains the
HTML. The boldface text shows the use of the Table Control.
TableCell Controls</TITLE>
</head>
<body>
<form id="WebControlTable"
method="post"
runat="server">
<p>
This page demonstrates how to
create HTML tables dynamically using
the Table, TableRow, and
TableCell Web Controls.
</p>
<p>
<asp:Table id=tblDisplayWindow
runat="server">
</asp:Table>
</p>
</form>
</body>
</html>
Notice that the initial Table Control does not have any rows, cells, or base
properties set. The following VB.NET code sets up those things.
Imports System
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports Microsoft.VisualBasic
162 Chapter 3 Working with ASP.NET
End Sub
É With tblDisplayWindow
.Width = Unit.Pixel(w)
.Height = Unit.Pixel(h)
.CellPadding = 2
.BackColor = Color.Gray
End With
# tblDisplayWindow.Rows.Add(trRow)
.VerticalAlign = WebControls.VerticalAlign.Top
.Text = "Content is displayed here"
End With
trRow.Cells.Add(tdCell)
$ tblDisplayWindow.Rows.Add(trRow)
End Sub
End Class
Figure 3-17 Output of the Table, TableRow, and TableCell Controls example
Bubbled-Up Events
The Command and CommandArgument properties bring up a new Web Control
concept called bubbled-up events. You’ve already seen with the Table,
TableRow, and TableCell Controls how you can embed child controls inside
another container control. If one of the child controls can fire events (such as
a button firing an OnClick event), you may want to notify the parent control
of that event occurring. The event fired by the child control event can be sent
or “bubbled up” to the parent control through a message contained in the
Command property. An optional command parameter can be passed in the
CommandArgument property. The Button Control example in Section 3.10.4
shows a sample implementation of bubbled-up events.
In the ImageUrl property, you can specify a URL to an image to use for
the button. The Command, CommandArgument, and OnClick properties function
the same way they do for the Button Control.
<head>
<title>Web Control - Button Example</title>
</head>
3.10 Web Controls for Creating Buttons 167
<body>
<form id="WebControlButtonSample"
method="post"
runat="server">
<p>Demonstration of Button,
LinkButton, and ImageButton:
</p>
<p>
<asp:Button id=btnWebControlButton
runat="server"
Text="Button">
</asp:Button>
</p>
<p>
<asp:LinkButton id=lbtWebLinkButton
runat="server">
LinkButton
</asp:LinkButton></p>
<p>
<asp:ImageButton id=igbWebImageButton
runat="server"
ImageUrl="mountain.jpg">
</asp:ImageButton>
</p>
<p>
<asp:Label id=lblResults
runat="server"
Width="202"
Height="84">
</asp:Label>
</p>
</form>
</body>
</html>
168 Chapter 3 Working with ASP.NET
The code-behind file provides some routines for handling the Click
events for each button.
Imports System
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports Microsoft.VisualBasic
<html>
<head>
<TITLE>Web Control - TextBox Example</TITLE>
</head>
<body>
<form id="WebControlTextBoxSample"
method="post"
runat="server">
<h1>Web Control - TextBox Example</h1>
<p>
<asp:Button id=btnSubmit
runat="server"
Text="Submit Data">
</asp:Button>
</p>
<p>
<asp:Label id=lblSingleTxtResult
runat="server">
</asp:Label>
</p>
<p>
<asp:Label id=lblPasswordTxtResult
runat="server">
</asp:Label>
</p>
<p>
<asp:Label id=lblMultiDelayedResult
maintainstate="False"
runat="server">
</asp:Label>
</p>
<p>
<asp:Label id=lblMultiAutoResult
runat="server">
</asp:Label>
</p>
</form>
</body>
</html>
This code demonstrates four different TextBox Controls, each one with
different TextMode and AutoPostBack attributes. The purpose of the example
is to show the behavior of these text boxes under different circumstances.
The OnTextChanged event of the TextBox Control shows, for the first
time, how client-side events can trigger a post-back to the server. In order to
trigger an immediate post-back when text changes in a text box, you need to
3.11 Web Control for Inputting Text 173
Property Description
AutoPostBack Indicates whether changes to the control’s text made by a user in his or
her browser will cause an immediate post-back to the server. True causes
a post-back. The default value is False.
Columns Specifies how many characters wide the control should be.
Rows Indicates for multiline text boxes the number of rows to display at one
time.
Text Sets the default text to display in the text box or the text that a user enters
into the text box.
Wrap Indicates for multi-line text boxes whether or not to let the text wrap
around to the next line when a line reaches the width of the text box; a
Boolean value.
use the client-side event to trigger a form post. Client-side JavaScript can
accomplish this. Whenever a Web Control like a text field loses focus (that is,
when the Web Control becomes unhighlighted because the user switches to
another one), its contents are checked for changes. If there is a client-side
event handler for that change, you can configure that client-side event handler
to trigger a form post if changes have occurred. That’s exactly what happens
when you set the AutoPostBack property to True as shown in line &.
The appearance of a text box is controlled by several factors: the TextMode
property, the Rows property, and the Columns property. The Rows and Columns
properties apply only to multiline text boxes. Conversely, some TextBox Con-
trol properties (for example, MaxLength) have meaning for only single-line
input text boxes.
The code-behind file for this HTML demonstrates the event-handling
mechanism of OnTextChanged, the event raised when the contents of the text
box have changed.
174 Chapter 3 Working with ASP.NET
Imports System
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
End Sub
3.12 Web Controls for Selecting Choices 175
The txtAutoPost text box in line â has the AutoPostBack attribute set, so
whenever text changes in the text box (and whenever the text box loses focus),
a post-back is executed. The txtDelayedEvent text box in line (, on the
other hand, does not cause an immediate post-back. The TextChanged event
is raised upon a post-back that is initiated from elsewhere, namely the
btnSubmit button.
Like the TextBox Control, the CheckBox Control can respond to changes
made to itself. A change event can be raised and handled by an event-handling
procedure passed into OnCheckedChanged. AutoPostBack works as described
before; when set to True, a post-back occurs when the box is checked or
unchecked.
Here is the HTML for a page that asks a few simple questions of the user.
<p>
<asp:CheckBox id=ckbKnowHTTP
runat="server"
Text='You know what "http://" really means'>
</asp:CheckBox>
</p>
<p>
<asp:CheckBox id=ckbCanCount
runat="server"
Text="You can count to 50 in binary">
3.12 Web Controls for Selecting Choices 177
</asp:CheckBox>
</p>
<p>
<asp:CheckBox id=ckbTransporter
runat="server"
Text='You can explain the physics of the
"Transporter"'>
</asp:CheckBox>
</p>
<p>
<asp:Button id=btnSubmit
runat="server"
Text="Geek Out!">
</asp:Button>
</p>
<p>
<asp:Label id=lblResponse
runat="server"
Width="393px">
</asp:Label>
</p>
</form>
</body>
</html>
The results of this example appear in Figure 3-19. Here is the code to
generate the page.
Imports System
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
System.Web.UI.WebControls.Label
Protected WithEvents btnSubmit As _
System.Web.UI.WebControls.Button
Protected WithEvents ckbTransporter As _
System.Web.UI.WebControls.CheckBox
Protected WithEvents ckbCanCount As _
System.Web.UI.WebControls.CheckBox
If ckbTransporter.Checked Then
lblResponse.Text = "It’s science fiction, remember?"
Else
lblResponse.Text = ""
End If
End Sub
If ckbCanCount.Checked Then
strResponse = strResponse & _
"Really? What's 3.14159 in binary? :-)<BR>"
End If
If ckbKnowHTTP.Checked Then
strResponse = strResponse & _
"Hypertext Transfer Protocol . . . very good . . . <BR>"
End If
If ckbTransporter.Checked Then
strResponse = strResponse & _
"A Trekkie, are you?!<BR>"
End If
lblResponse.Text = strResponse
End Sub
End Class
3.12 Web Controls for Selecting Choices 179
OnSelectedIndexChanged="OnSelectedIndexChangedMethod"
/>
</asp:CheckBoxList>
Property Description
DataTextField Designates the field or property of the object in the data source to be
used for the Text property of each control.
DataValueField Designates the field or property of the object in the data source to be
used for the Value property of each control.
RepeatColumns Sets the number of columns used to display the controls. The default
value is 1.
RepeatDirection Sets the direction, Vertical or Horizontal, that the controls are
displayed in the list. If Vertical, the checkboxes are ordered top to
bottom. If Horizontal, the checkboxes are ordered left to right.
RepeatLayout The list can be rendered using Flow or Table. Flow displays the
controls in-line, without formatting. Table displays the controls
inside cells of an HTML table. Default is Table. Set this property
using the RepeatLayout enumeration.
(continued)
182 Chapter 3 Working with ASP.NET
Property Description
SelectedItem Gets the Value property value for the currently selected control.
TextAlign Designates how text (the caption) should be displayed next to the
controls, to the Right or to the Left.
Although we won’t go into much detail about data sources and data bind-
ing yet (we’ll cover that topic further in Chapter 7), the example of the
RadioButtonList Control shown below contains data binding. We won’t actu-
ally bind to a database system, but we will use an array as our data source.
Individual items can also be added by inserting a ListItem object into each
list at design time. We’ll do examples of both.
<html><head>
<title>Web Control - CheckBoxList Example</title>
</head>
<body>
<form id="WebControlCheckBoxListSample"
3.12 Web Controls for Selecting Choices 183
method="post"
runat="server">
<p>
<asp:CheckBoxList id=cblTestCheckBoxList
maintainstate=False
runat="server">
<asp:ListItem Value="Item1">
Item #1
</asp:ListItem>
<asp:ListItem Value="Item2">
Item #2
</asp:ListItem>
<asp:ListItem Value="Item3">
Item #3
</asp:ListItem>
</asp:CheckBoxList>
</p>
<p>
<asp:Button id=btnSendResponse
runat="server"
Text="Send Response">
</asp:Button>
</p>
<p>
<asp:Label id=lblResponse
runat="server"
Width="36"
Height="19">
</asp:Label>
</p>
</form>
</body>
</html>
184 Chapter 3 Working with ASP.NET
This code uses the usual Web Form, with a submit button and a
CheckBoxList Control (the code for which is shown in boldface). A new
class object is introduced here: the ListItem object. The ListItem object
can be used in different Web Controls, like RadioButtonList, ListBox (see
Section 3.13.1), and DropDownList (see Section 3.13.2). The ListItem class
object allows you to programmatically reference any individual item. When
you have access to a ListItem object, you can query its Value, Text, and
Selected properties.
Each ListItem object placed inside the CheckBoxList Control contains a
value for Text and a value for Value. The text located between the opening
and closing asp:ListItem tags becomes the value for the Text property when
referenced programmatically. Remember that you can use the alternate nota-
tion for specifying the text label by assigning the Text property directly and
not use a closing asp:ListItem tag.
Now we’re ready to check the submitted data. The code-behind file iter-
ates through each ListItem and tests to see if the ListItem was checked.
Imports System
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
lblResponse.Text = strResponse
End Sub
End Class
Web Controls that deal with collections of ListItem objects have a prop-
erty called Items. This is the property used to test the items in the list. Items
is a collection, so beginning in line * the code uses a For . . . Each loop to
retrieve each ListItem. The Selected property, a Boolean value, is set to
True if the ListItem is selected. The response back to the user is formatted in
line + so the Text property of the ListItem is echoed back.
Data Binding to Web Controls Using Class Objects and the ArrayList
When you perform data binding, you are passing into Web Controls a set of
data—data in the general sense, since bindable data can come from a variety
of sources. A data-bound Web Control is usually bound to database data, but
ASP.NET is flexible enough to treat an ArrayList, XML data, or a class object
as a bindable data source.
Binding data from a class object to a Web Control is quite powerful yet
easy to do. In the example below, we first create a class object to contain mem-
bers we’ll use as data to bind to the Web Control. The class, CMyItemClass, is
very simple and contains two public string properties.
m_strMember1 = Member1
m_strMember2 = Member2
End Sub
Get
Member1 = m_strMember1
End Get
End Property
- With aryArray
.Add(New CMyItemClass("Item1", "Item #1"))
.Add(New CMyItemClass("Item2", "Item #2"))
.Add(New CMyItemClass("Item3", "Item #3"))
End With
. With cblTestCheckBoxList
.DataTextField = "Member2"
.DataValueField = "Member1"
.DataSource = aryArray
.DataBind()
End With
Else
3.12 Web Controls for Selecting Choices 187
lblResponse.Text = strResponse
End If
End Sub
In line , this code introduces a new object, the ArrayList object. The
ArrayList object is a class in the System.Collections namespace (see Chap-
ter 4) that encapsulates an array of objects that can be sized dynamically. The
ArrayList object is one of the data sources that Web Controls can bind
against.
Beginning in line - we add CMyItemClass objects to aryArray, the
ArrayList. When we defined the CmyItemClass objects, we defined a con-
structor that populated the two property values Member1 and Member2
(m_strMember1 and m_strMember2). We will use the values of those two prop-
erties to bind to the Web Control later.
In the next block of code beginning in line ., we call the necessary func-
tions to bind the class objects to the CheckBoxList Control. This is done when
the browser first requests the page. Beginning with the DataTextField and
DataValueField properties, we set each with the name of the CMyItemClass
properties. When the individual checkboxes are rendered in HTML, the
DataTextField property is used as shown below. (The white space in the
HTML has been edited for clarity.)
<span>
<input type="checkbox"
id="cblTestCheckBoxList_0"
name="cblTestCheckBoxList:0" />
<span>
188 Chapter 3 Working with ASP.NET
<input type="checkbox"
id="cblTestCheckBoxList_1"
name="cblTestCheckBoxList:1" />
<span>
<input type="checkbox"
id="cblTestCheckBoxList_2"
name="cblTestCheckBoxList:2" />
DataValueField="DataSourceField"
RepeatColumns="ColumnCount"
RepeatDirection="Vertical | Horizontal"
RepeatLayout="Flow | Table"
TextAlign="Right | Left"
OnSelectedIndexChanged="OnSelectedIndexChangedMethod"
/>
<asp:ListItem text="label" value="value" selected="True | False" />
</asp:RadioButtonList>
With aryArrayList
.Add("Radio Button #1")
.Add("Radio Button #2")
.Add("Radio Button #3")
End With
With rblRadioButtonList
.DataSource = aryArrayList
.DataBind()
End With
Else
lblResponse.Text = _
rblRadioButtonList.SelectedItem.Text
End If
End Sub
Inherits="WebControlCheckBoxListSample"%>
<html><head>
<title>Web Control - ListBox Control Example</title>
</head>
<body>
<form id="WebControlListBoxSample"
method="post"
runat="server">
<asp:ListBox id=lbMultipleSelections
runat="server"
Rows="3"
selectionmode="Multiple">
<asp:ListItem Value="Red">Red
</asp:ListItem>
<asp:ListItem Value="Green">Green
</asp:ListItem>
<asp:ListItem Value="Blue">Blue
</asp:ListItem>
<asp:ListItem Value="Yellow">Yellow
</asp:ListItem>
<asp:ListItem Value="Orange">Orange
</asp:ListItem>
192 Chapter 3 Working with ASP.NET
<asp:ListItem Value="Brown">Brown
</asp:ListItem>
</asp:ListBox>
</p>
<p>
<asp:Button id=btnSendSelections
runat="server"
Text="Send Selections">
</asp:Button>
</p>
<p>
<asp:Label id=lblSelections
runat="server"
Width="199"
Height="19">
</asp:Label></p>
</form>
</body>
</html>
Retrieving the selected items from the ListBox Control is relatively straight-
forward, similar to the procedure for the CheckBoxList and RadioButtonList
Controls. Here is the Page_Load (WebControlListBoxSample_Load) event
handler, which demonstrates how to retrieve the selected items from a multiple-
select ListBox Control as well as for a ListBox Control that allows just one
selection.
Imports System
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
System.Web.UI.WebControls.Label
Else
0 For Each liListItem In lbMultipleSelections.Items
If liListItem.Selected Then
194 Chapter 3 Working with ASP.NET
lblSelections.Text = strSelections
End If
End Sub
End Class
The example for the single-selection ListBox Control can easily be con-
verted to a DropDownList Control with just a few changes to the code. First,
we change the Web Control type from ListBox to DropDownList in the
HTML.
3.14 Miscellaneous Basic Controls 195
Then, we update the code-behind file to reflect the change made in the
HTML.
LAB 3-1
YOUR FIRST ASP.NET PROJECT
STEP 1. Launch VS.NET.
a. To launch VS.NET, click the Start menu and locate the Visual Studio.NET
7.0 program group (see Lab Figure 3-1).
Lab Figure 3-4 Progress message displayed while VS.NET creates a new
Web page
b. To add a new Web Form to the solution, right-click on the Lab3-1 icon inside
the Solution Explorer window and select Add➔Add Web Form . . . from the
menu (see Lab Figure 3-6).
c. In the Name field of the Add New Item dialog box, type “Lab3-1_FirstPage.
aspx” as the name of the new Web Form (see Lab Figure 3-7). Click the
Open button when you are finished typing the name.
The new Web Form now opens inside the VS.NET IDE and is ready for edit-
ing. VS.NET defaults to the Design View mode for the Web Form. This mode
allows you to use the HTML WYSIWYG (What You See Is What You Get) edi-
tor and to place Web Controls onto the Web Form. The Toolbox window
shows the available HTML and Web Controls plus other components and
controls (see Lab Figure 3-8).
dow, which contains properties for the Web Control. Lab Figure 3-10 shows
the Properties window.
To change the name of the Web Control, click in the (ID) field and type a
new name. This value will be used to programmatically reference the Web
Control in application code. You can adjust other properties using the same
procedure. For this lab, name the Web Controls as follows:
• The TextBox Control: txtYourName
• The Label Control: lblReply
• The Button Control: cmdSayHello
d. The code for the Click event of cmdSayHello is very simple. Assign the
value entered in the TextBox Control, txtYourName, to the Text property
Lab Figure 3-11 Selecting View Code for the Button Control
3.15 Creating a Simple ASP.NET Application 205
Lab Figure 3-12 Selecting the cmdSayHello Button Control for code-behind
editing
of the lblReply Label Control. The entry of this code is shown in Lab
Figure 3-14.
b. Now that the solution is built, you need to tell VS.NET which Web page to
use as the entry point into the application (the start page). You can desig-
nate any Web page in the solution as the start page by right-clicking it in
the Solution Explorer window and selecting Set As Start Page from the
menu (see Lab Figure 3-16).
Lab Figure 3-16 Setting the start page for the Web application
c. Now you’re ready to run the Web application. Select Start Without Debug-
ging from the Debug menu (see Lab Figure 3-17). This runs the application
without invoking the VS.NET debugger. Your first Web application in action
should look something like the screen shown in Lab Figure 3-18.
Congratulations on finishing the lab! You’ve gained valuable experience for developing
ASP.NET applications with VB.NET. Other Web applications in this book are, of course,
considerably more complex, but the fundamentals are the same. In the next lab, you’ll
have the chance to use more of the Web Controls and add much more application code to
provide rich application functionality.
3.16 ASP.NET Page Directives 209
Table 3-6 Attributes Used for the @ Page and @ Control Page Directives
AspCompat (used only for @ Page) Sets backward compatibility with classic ASP. The
default is False, which means “not compatible.”
MaintainState Turns the view state of the HTML and Web Controls
on and off on a page-wide level. The default is True.
Trace (used only for @ Page) Turns on and off debug tracing for the page. The
default is False.
Using just the above syntax, the control renders in the browser with
default styles and date selection enabled and displays the current month and
date on the Web server, as shown in Figure 3-21.
Table 3-7 contains the complete listing of the Calendar Control’s many
properties. Remember that as a Web Control, the Calendar Control also
inherits all the shared properties of other Web Controls.
214 Chapter 3 Working with ASP.NET
Property Description
CellPadding Controls the amount of space between the cell border and
the cell contents in the calendar (a cell contains a day).
Property Description
FirstDayOfWeek Controls which day is displayed as the first day of the week
in the calendar. Property is of type System.Web.UI.
WebControls.FirstDayOfWeek.
NextMonthText Controls the text displayed for the next month hyperlink if
the ShowNextPrevMonth property is set to True.
NextPrevFormat Controls the format for the next and previous month
hyperlinks. Property is of type System.Web.UI.
WebControls.NextPrevFormat.
(continued)
216 Chapter 3 Working with ASP.NET
Property Description
SelectedDayStyle Read-only property that gets the style properties for the
selected date as a System.Web.UI.
WebControls.TableItemStyle object.
SelectWeekText Gets or sets the text shown for the week selection in the
selector column if SelectionMode is
CalendarSelectionMode.DayWeek or
CalendarSelectionMode.DayWeekMonth.
ShowDayHeader Indicates whether or not to show the days of the week on the
calendar. Default is True.
Property Description
TitleStyle Read-only property that gets the style for the calendar title as
a System.Web.UI.WebControls.Style object.
TodayDayStyle Read-only property that gets the style for today’s date as a
System.Web.UI.WebControls.Style object.
VisibleDate Gets or sets the date that specifies which month to display.
The date can be any date within the month.
WeekendDayStyle Read-only property that gets the style for weekend dates as a
System.Web.UI.WebControls.Style object.
When you use VS.NET to put calendars on your pages, you can use a
convenient feature to give your calendar a pleasing look. In the Properties
window for the Calendar Control, click on the AutoFormat link (see Figure
3-22). This brings up the Calendar AutoFormat window shown in Figure 3-23.
You can select a color and style scheme from a list of predefined styles.
</head>
<body>
<asp:calendar id=Calendar1
runat="server"
DayNameFormat="FirstLetter"
BackColor="White"
SelectorStyle-BackColor="#CCCCCC"
NextPrevStyle-VerticalAlign="Bottom"
TodayDayStyle-ForeColor="Black"
TodayDayStyle-BackColor="#CCCCCC"
DayHeaderStyle-Font-Bold="True"
DayHeaderStyle-BackColor="#CCCCCC"
Font-Size="8pt"
Font-Names="Verdana"
Height="180"
OtherMonthDayStyle-ForeColor="#808080"
TitleStyle-Font-Bold="True"
TitleStyle-BorderColor="Black"
TitleStyle-BackColor="#999999"
WeekendDayStyle-BackColor="#FFFFCC"
ForeColor="Black"
BorderColor="#999999"
Width="201"
SelectedDayStyle-Font-Bold="True"
SelectedDayStyle-ForeColor="White"
SelectedDayStyle-BackColor="#666666"
CellPadding="4">
</asp:Calendar>
<asp:Label id=lblSelectionMessage
runat=server>
</asp:label>
</form>
</body>
</html>
The Calendar Control, like other Web Controls, also responds to events.
The Calendar Control has three events, listed in Table 3-8, that are of particu-
lar interest.
220 Chapter 3 Working with ASP.NET
Event Description
DayRender Occurs when each day is created in the control hierarchy for the
calendar. Use this event to modify the contents of each date cell
with custom data.
SelectionChanged Occurs when the user clicks on a day, week, or month selector
and changes the SelectedDate property.
VisibleMonthChanged Occurs when the user clicks on the next or previous month
controls on the calendar title.
As a quick example, let’s write some code to echo back the date the user
selects from the calendar. Using the definition created earlier in the Calendar
AutoFormat example, we write an event handler for the SelectionChanged
event in a code-behind file.
Imports System
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
lblSelectionMessage.Text = _
Calendar1.SelectedDate.ToString()
End Sub
End Class
3.17 ASP.NET Rich Controls 221
<asp:AdRotator
id=value
runat="server"
AdvertisementFile="AdvertisementFile"
OnAdCreated="OnAdCreatedMethod"
KeywordFilter="keyword"
Target="browserwindoworframename"
>
</asp:AdRotator>
As with the other Web Controls, the AdRotator Control inherits all the
shared Web Control properties. The properties specific to the AdRotator
Control are listed in Table 3-9.
The advertisement data file holds all the information about the banner ads
to display. This includes for each ad the URL to the banner graphic, the URL
link associated with the banner graphic, the graphic’s ALT text, a keyword asso-
ciated with the banner, and a rotation “weight.” All of this data is contained
within an XML format. In order for the AdRotator Control to function prop-
erly, the XML format must be valid. The path to the advertisement file is
specified in the AdvertisementFile property. This is the format for the
XML advertisement file.
222 Chapter 3 Working with ASP.NET
Property Description
AdvertisementFile Specifies the relative path to the advertisement data file (in XML
format).
<Advertisements>
<Ad>
<ImageUrl>URL of image to display</ImageUrl>
<TargetUrl>URL of page to link to</TargetUrl>
<AlternateText>
Text to show as ToolTip
</AlternateText>
<Keyword>keyword used to filter</Keyword>
<Impressions>relative weighting of ad</Impressions>
</Ad>
</Advertisements>
TECHTALK: XML
XML stands for eXtensible Markup Language. For the uniniti-
ated, XML is the talk of the whole software industr y. XML
allows you to package data in a hierarchical, self-describing
format. XML has wide applications, from business-to-
business e-commerce to providing an infrastructure for dis-
tributed Internet applications. It’s no coincidence that all of
the .NET Framework relies heavily on XML. XML is a World
Wide Web Consortium standard and is embraced by many
different software vendors. I’ll mention XML again in the dis-
cussions of data access and Web Ser vices. If you’re curious
about the technical details and specifications of XML, you
can find more information at the World Wide Web Consor-
tium’s XML Web site at http://www.w3.org/XML.
3.17 ASP.NET Rich Controls 223
Keyword and Impressions are two features you can use to selectively dis-
play ads based on importance or category. Keyword causes the AdRotator
Control to display banner ads that have a keyword that matches the keyword
specified in the KeywordFilter property. This is useful, for example, when the
user is in an area of a site that is customized for a certain demographic (for
example, you can display ads in the business section of a site that pertain to
consulting and business services and filter out ads for entertainment). The
Impressions feature allows you to make particular banner ads appear more
often than others. This is useful when you want to draw attention to a special
product or service. In banner hosting scenarios, you may want to give higher
Impressions values to companies that have paid higher hosting fees in
exchange for greater ad exposure. The values for Impressions are relative;
higher values receive more rotation.
The AdRotator Control also defines an event called OnAdCreated. This
event is raised upon the next post-back to the server whenever the advertise-
ment changes. The OnAdCreated event is useful for adjusting the content of
the rest of the page based on which banner ad the AdRotator Control picked.
The AdCreatedEventArgs object associated with the OnAdCreated event
contains these members:
■ e.AdProperties (IDictionary collection of all properties for the
selected banner ad)
■ e.AlternateText (corresponds to AlternateText in the XML file)
■ e.ImageUrl (corresponds to ImageURL in the XML file)
■ e.NavigateUrl (corresponds to TargetURL in the XML file)
Since the AdCreatedEventArgs object contains all the relevant information
about the banner ad, you should be able to make good decisions about content
changes to the page based on this information.
The AdRotator Control example below demonstrates these concepts. The
.aspx file contains the AdRotator Control and a Label Control.
<form id="WebControlAdRotator"
method="post"
runat="server">
<h1>Web Control - AdRotator Sample</h1>
<p>
<asp:AdRotator id=adrotMyRotator
runat="server"
Width="470"
Height="60"
AdvertisementFile="adrot.xml">
</asp:AdRotator>
</p>
<p>
<asp:Label id=lblCurrentAd
runat="server"
Width="461"
Height="19">
</asp:Label>
</p>
</form>
</body>
</html>
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
End Class
Apart from the placement of the AdRotator Control in the .aspx file, no
coding is required to display and rotate banner ads. The interesting code is
in the code-behind portion of the example. We write an event handler for
AdCreated (OnAdCreated) that sets the lblCurrentAd Label Control with
the value of the ALT text for the banner’s graphic.
Figure 3-24 shows the example in action, displaying one of the banner ads
contained in the advertisement file.
Property Description
Display Determines how the Control is used in the page. Takes a type
of ValidationDisplay. Possible values are Static, None,
and Dynamic.
<asp:RequiredFieldValidator
id="RequiredFieldValidator1" runat="server"
ControlToValidate="id_of_control"
ErrorMessage="Your error message here"
ForeColor="Red">
</asp:RequiredFieldValidator>
data in the field, the text specified in ErrorMessage appears in the display area
when data is posted back to the server. The post-back does not execute until
the error (and all other validation errors on the page) are reconciled. This
means that all other Validation Controls on the page must contain valid data
before the post-back occurs. The ForeColor property specifies a color for the
ErrorMessage text. It’s a good idea to choose a color that stands out from the
rest of the page so users can identify an error easily. For design purposes, the
Display property can be used to designate how Validation Controls are dis-
played in the page. By default, Validation Controls take up space on the page
even if the error message is not currently being displayed. Since this can cause
difficulties in page layout, you can set the Display property to Dynamic, which
causes the Validation Control to occupy space on the page only when an error
is displayed. Setting Dynamic for the Display property is really applicable only
to Web browsers that support DHTML (up-level browsers such as Internet
Explorer 4.0 or above). This is because validation occurs on the client side,
without a server post-back. Down-level browsers always perform server-side
validation since they cannot reliably use client-side script in all types of data
validation scenarios.
Below is a small example of a Web Form that uses the
RequiredFieldValidator Control. The RequiredFieldValidator
Control checks for an entry in the txtRequired text box when the
btnSubmit button is clicked.
<form id="WebControlValidationDemo"
method="post"
runat="server">
<h1>Validation Demo</h1>
<p>You must type something here:
<asp:TextBox id=txtRequired
runat="server">
</asp:TextBox>
230 Chapter 3 Working with ASP.NET
<asp:RequiredFieldValidator id=rfvTxtRequired
runat="server"
ErrorMessage="You must enter something!"
ControlToValidate="txtRequired">
</asp:RequiredFieldValidator>
</p>
<p>
<asp:Button id=btnSubmit
runat="server"
Text="Send Data">
</asp:Button>
</p>
</form>
</body>
</html>
<asp:CompareValidator
id="CompareFieldValidator1"
runat="server"
ForeColor="Red"
ControlToValidate="id_of_control"
ErrorMessage="Your error message here.">
</asp: CompareValidator >
Property Description
Type Specifies the data type to use for the comparison. Can be String,
Integer, Double, Date, or Currency. Defaults to String.
<form id="WebControlValidationDemo"
method="post"
runat="server">
<asp:ListItem Value="31">31</asp:ListItem>
<asp:ListItem Value="42">42</asp:ListItem>
<asp:ListItem Value="123">123</asp:ListItem>
<asp:ListItem Value="44">44</asp:ListItem>
<asp:ListItem Value="784">784</asp:ListItem>
</asp:DropDownList>
<asp:CompareValidator id=cvMagicNumber
runat="server"
ErrorMessage="You must select a number!"
ControlToValidate="ddlNumberList"
ValueToCompare="Please Select a Number"
Operator="NotEqual">
</asp:CompareValidator>
</p>
<p>
<asp:Button id=btnSubmit
runat="server"
Text="Send Data">
</asp:Button>
</p>
</form>
</body>
</html>
<form id="WebControlValidationDemo"
method="post"
runat="server">
<p>Select a minimum:
<asp:DropDownList id=ddlMinimum runat="server">
<asp:ListItem Value="-10">-10</asp:ListItem>
<asp:ListItem Value="0">0</asp:ListItem>
<asp:ListItem Value="50">50</asp:ListItem>
<asp:ListItem Value="100">100</asp:ListItem>
</asp:DropDownList>
Select a maximum:
<asp:DropDownList id=ddlMaximum runat="server">
<asp:ListItem Value="0">0</asp:ListItem>
<asp:ListItem Value="20">20</asp:ListItem>
<asp:ListItem Value="70">70</asp:ListItem>
<asp:ListItem Value="100">100</asp:ListItem>
</asp:DropDownList>
</p>
<p>
<asp:CompareValidator id=cvMinMax
runat="server"
ErrorMessage="Minimum must be less than maximum!"
ControlToValidate="ddlMinimum"
ControlToCompare="ddlMaximum"
Type="Integer"
Operator="LessThan">
</asp:CompareValidator>
</p>
<p>
<asp:CompareValidator id=cvMaxMin
runat="server"
ErrorMessage="Maximum must be greater than minimum!"
234 Chapter 3 Working with ASP.NET
ControlToValidate="ddlMaximum"
ControlToCompare="ddlMinimum"
Type="Integer"
Operator="GreaterThan">
</asp:CompareValidator>
</p>
<p>
<asp:Button id=btnSubmit
runat="server"
Text="Send Data">
</asp:Button>
</p>
</form>
</body>
</html>
<asp:RangeValidator id=RangeValidator1
runat="server"
ErrorMessage="Value is out of range!"
ControlToValidate="txtRangeNumber"
</asp:RangeValidator>
Properties Description
tested to make sure the selections were meaningful. Now we want to test
whether an integer value entered into a text box falls within the range speci-
fied (1 through 10). The example begins with the two DropDownList Controls
from the previous example. Then we add a TextBox Control along with a
RangeValidator Control, as shown in the boldface text.
<form id="WebControlValidationDemo"
method="post"
runat="server">
<p>Select a minimum:
<asp:DropDownList id=ddlMinimum runat="server">
<asp:ListItem Value="-10">-10</asp:ListItem>
<asp:ListItem Value="0">0</asp:ListItem>
<asp:ListItem Value="50">50</asp:ListItem>
<asp:ListItem Value="100">100</asp:ListItem>
</asp:DropDownList>
Select a maximum:
<asp:DropDownList id=ddlMaximum runat="server">
<asp:ListItem Value="0">0</asp:ListItem>
<asp:ListItem Value="20">20</asp:ListItem>
<asp:ListItem Value="70">70</asp:ListItem>
<asp:ListItem Value="100">100</asp:ListItem>
</asp:DropDownList>
</p>
236 Chapter 3 Working with ASP.NET
<p>
<asp:CompareValidator id=cvMinMax
runat="server"
ErrorMessage="Minimum must be less than maximum!"
ControlToValidate="ddlMinimum"
ControlToCompare="ddlMaximum"
Type="Integer"
Operator="LessThan">
</asp:CompareValidator>
</p>
<p>
<asp:CompareValidator id=cvMaxMin
runat="server"
ErrorMessage="Maximum must be greater than minimum!"
ControlToValidate="ddlMaximum"
ControlToCompare="ddlMinimum"
Type="Integer"
Operator="GreaterThan">
</asp:CompareValidator>
</p>
<p>
<asp:RangeValidator id=rvRangeValidator
runat="server"
ErrorMessage="Value is out of range!"
ControlToValidate="txtRangeNumber"
Type="Integer"
MinimumValue="1"
MaximumValue="10">
</asp:RangeValidator>
</p>
</form>
</body>
</html>
3.18 Validation Controls 237
Now when the user enters a value in the txtRangeNumber text box,
rvRangeValidator checks against a range defined by the MinimumValue
and MaximumValue properties.
<asp:RegularExpressionValidator
id=id_of_control runat="server"
ControlToValidate="control_to_validate"
ErrorMessage="Your Error Message here"
ValidationExpression="your_regular_expression">
</asp:RegularExpressionValidator>
Here’s a scenario for using a regular expression. Web sites often try to
collect e-mail addresses. E-mail addresses follow a general form, typically
[email protected]. In other words, an e-mail address contains at least four
parts (in this order): a string of arbitrary length, an @ sign, any number of
domain names delimited by a period (.), and an ending top-level domain. All
valid e-mail addresses follow this pattern. (By valid I mean that the e-mail
address follows the defined format, not that the e-mail belongs to an active
user or exists at all.)
How do you build such a regular expression? Actually, for performing
an e-mail address check as described above, you don’t need to. VS.NET
does that for you with the Regular Expression Editor. To see how this is
done, first drag a RegularExpressionValidator Control to the Web Form.
Then open the Properties window for the RegularExpressionValidator
Control and click the button in the box for the ValidationExpression.
This opens the Regular Expression Editor, pictured in Figure 3-25.
Select the Internet E-Mail Address option. The Validation Expression
box shows the syntax for validating a TextBox Control for a valid e-mail
address entry.
The example below uses this syntax and also shows multiple Validation
Controls (in the boldface code blocks) being applied to a single TextBox Con-
trol. We also use the RequiredFieldValidator Control to check for a blank
entry. Any and all Validation Controls applied must pass the validation test
before a valid post-back occurs.
<form id="WebControlValidationDemo"
method="post"
runat="server">
<p>
Enter an e-mail address:
<asp:TextBox id=txtEmailAddress
runat="server">
</asp:TextBox>
<asp:RequiredFieldValidator id=rfvTxtEmailAddress
runat="server"
ErrorMessage="You must enter an e-mail address!"
ControlToValidate="txtEmailAddress">
</asp:RequiredFieldValidator>
</p>
240 Chapter 3 Working with ASP.NET
<p>
<asp:RegularExpressionValidator
id=revTxtEmailAddress
runat="server"
ErrorMessage="That doesn’t appear to be
a valid e-mail address!"
ControlToValidate="txtEmailAddress"
ValidationExpression="[\w-]+(\+[\w-]*)?@([\w-]+\.)+[\w-]+">
</asp:RegularExpressionValidator>
</p>
<p>
<asp:Button id=btnSubmit
runat="server"
Text="Send Data">
</asp:Button>
</p>
</form>
</body>
</html>
<asp:CustomValidator id=CustomValidator1
runat="server"
ErrorMessage="Your error message here">
</asp:CustomValidator>
Property Description
<script language=javascript>
<!— —
function clientSideTest (source, arguments)
{
if ((arguments.Value % 2) == 0)
{
arguments.IsValid = true;
}
else
{
arguments.IsValid = false;
}
return arguments.IsValid;
}
3.18 Validation Controls 243
//——>
</script>
</head>
<body>
<form id="WebControlValidationDemo"
method="post"
runat="server">
<asp:CustomValidator id=cvClientSideTest
runat="server"
controltovalidate="txtClientSideTest"
ErrorMessage="You must enter an even number!"
clientvalidationfunction="clientSideTest">
</asp:CustomValidator>
</p>
<p>
<asp:Button id=btnSubmit
runat="server"
Text="Send Data">
</asp:Button></p>
</form>
</body>
</html>
function does not check the customer’s credit or even whether the num-
ber entered belongs to a real credit card). The code we use to place a
CustomValidator Control on the page is similar to the last example.
<form id="WebControlValidationDemo"
method="post"
runat="server">
<h1>Validation Demo</h1>
<p>
Give me your credit card number:
<asp:TextBox id=txtCreditCard
runat="server">
</asp:TextBox>
<asp:CustomValidator id=cvCreditCardCheck
OnServerValidate="IsCreditCardValid"
runat="server"
ControlToValidate="txtCreditCard"
ErrorMessage="That’s not a valid credit card number!"
Width="119"
Height="57"
Display="Dynamic">
</asp:CustomValidator>
<asp:RequiredFieldValidator id=rfvCreditCard
runat="server"
ControlToValidate="txtCreditCard"
ErrorMessage="You must enter a credit card number!"
Display="Dynamic">
</asp:RequiredFieldValidator>
</p>
3.18 Validation Controls 245
<p>
<asp:Button id=btnSubmit
runat="server"
Text="Send Data">
</asp:Button></p>
</form>
</body>
</html>
Imports System
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports Microsoft.VisualBasic
strTmp = args.Value
intCounter = 1
intTmpInt = 0
args.IsValid = False
strTmp = Replace(strTmp, " ", "")
Exit Sub
End If
End Sub
End Class
In this section, we’ll explore the three types of List Controls: Repeater,
DataGrid, and DataList. We’ll also see some data-binding examples, but we’ll
forgo examples using databases until Chapter 7.
<HeaderTemplate>
Header template HTML
</HeaderTemplate>
<ItemTemplate>
Item template HTML
</ItemTemplate>
<AlternatingItemTemplate>
Alternating item template HTML
</AlternatingItemTemplate>
<SeparatorTemplate>
Separator template HTML
</SeparatorTemplate>
<FooterTemplate>
Footer template HTML
</FooterTemplate>
<asp:Repeater>
Let’s start by exploring how templates work. Templates allow you to spec-
ify arbitrary HTML to render for the template item. In other words, you can
specify HTML for rows, headers, and footers for a particular list. Table 3-14
lists the possible template divisions for the Repeater Control.
248 Chapter 3 Working with ASP.NET
Template Description
FooterTemplate HTML to render at the end of all the rows in the list
HeaderTemplate HTML to render before any rows in the list are rendered
You’ll typically want to display lists as HTML tables since this is the gener-
ally accepted way to display tabular data. A typical template for a list looks
something like the code shown below.
<form id="WebFormRepeaterControl"
method="post"
runat="server">
<h1>Web Controls - Repeater Control</h1>
<p>
1 <asp:Repeater id=rptTestRepeater
runat="server">
2 <HeaderTemplate>
<table border=1>
<tr>
3.19 Data List Controls 249
<td bgcolor="Black">
<font color="white"><b>Color</b></font>
</td>
<td bgcolor="Black">
<font color="white"><b>Swatch</b></font>
</td>
</tr>
</HeaderTemplate>
3 <ItemTemplate>
<tr>
<td></td>
<td bgcolor=""></td>
</tr>
</ItemTemplate>
4 <FooterTemplate>
<caption valign="bottom" align="left">
<i>Table 1-1 Some colors</i>
</caption>
</table>
</FooterTemplate>
</asp:Repeater>
</p>
</form>
</body>
</html>
We begin the template with the placement of the Repeater Control in line
1. To build a list based on an HTML table, we need to begin with a <table>
tag as our HeaderTemplate in line 2 along with a header row that we define
using a table row (using the <tr> tag) with two columns (using the <td> tag).
In lines 3 and 4, we define how each item in the list will be rendered (using a
table row with two columns) and how to close off the table (with an ending
</table> tag and a <caption> tag).
That’s all we need to define a template to display a list of data with two
columns. But now we need to give the Repeater Control a data source to
which to bind. For our example, we’ll create a data source for the Repeater
Control that’s based on the System.Collection.Hashtable class (see Section
4.2.4). The hashtable is a sort of associative array. Each item in the hashtable
contains a key and a corresponding value. We’ll create a hashtable with some
values in it and display the key–value pairs in the two-column template we just
250 Chapter 3 Working with ASP.NET
created. In the code-behind file (for the Page_Load event), we create the
hashtable with some color values, as shown by the boldface text below.
Imports System
Imports System.Data
Imports System.Collections
Imports System.Drawing
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
With aryMyList
.Add("Red", "#FF0000")
.Add("Green", "#00FF00")
.Add("Blue", "#0000FF")
.Add("Yellow", "#FFFF00")
End With
rptTestRepeater.DataSource = aryMyList
rptTestRepeater.DataBind()
End Sub
End Class
ues along with the name of each color. Looking back at the code section
beginning on line 3, we change the ItemTemplate section to the follow-
ing code.
<ItemTemplate>
<tr>
<td><%# Container.DataItem.Key %></td>
<td bgcolor="<%# Container.DataItem.Value %>"></td>
</tr>
</ItemTemplate>
Template expressions are placed inside special markers, the <%# and %>
symbols. When you want to access the data bound to the Repeater Control,
you need to access the RepeaterItem class that is associated with each tem-
plate (ItemTemplate, HeaderTemplate, and so on). You do this by using the
Container keyword. The Container keyword allows you to reference the parent
control of whatever child control you are currently using. DataItem is a member
of the RepeaterItem class. DataItem is of type Object. The exact type of object
that DataItem is depends on the type of data that is bound to the control. In the
case of the bound hashtable above, each DataItem object is a DictionaryEntry
object. The DictionaryEntry object has two members of interest: Key and
Item. These correspond to the key and value items we added to the hashtable
with the Hashtable.Add method for the color name and color value.
Here’s another example of template expressions. Suppose that we bound
the Repeater Control to an array list instead of a hashtable. First, we replace
the code that populates the hashtable with this code that fills an array list with
some values.
With aryMyList
.Add("#00FF00")
.Add("#FF0000")
.Add("#0000FF")
.Add("#FFFF00")
End With
rptTestRepeater.DataSource = aryMyList
rptTestRepeater.DataBind()
<ItemTemplate>
<tr>
<td><%# Container.DataItem %></td>
<td bgcolor="<%# Container.DataItem %>"></td>
</tr>
</ItemTemplate>
This time, the object for DataItem is just a string, System.String, since
that is the type of data we supplied when we populated the array list. Notice
that we don’t reference a member of System.String. We certainly can, if
needed, call methods of System.String for purposes of formatting or trim-
ming the string. The example relies on the default member of System.String,
3.19 Data List Controls 253
which returns the characters of the string. In summary, it’s necessary to know
how your bound data is structured so a properly declared template expression
can be assigned.
While this is the only syntax needed to display bounded data, you typically
need to adjust the look and feel of the data grid to suit your application’s
design requirements. Consider this example that uses the DataGrid Control.
<html><head>
<title>Web Form - DataGrid Example 1</title>
254 Chapter 3 Working with ASP.NET
</head>
<body>
<form id=WebFormDataGrid1
method=post runat="server">
<h1>Web Form - DataGrid Example 1</h1>
<p>
5 <asp:DataGrid id=dgMyDataGrid
runat="server"
AutoGenerateColumns="False"
HeaderStyle-BackColor="#aaaadd"
Font-Size="8pt"
Font-Name="Verdana"
CellSpacing="0"
CellPadding="3"
ShowFooter="false"
BorderColor="black"
BackColor="#ccccff">
6 <Columns>
<asp:boundcolumn headertext="Drawing Date"
datafield="DrawingDate">
</asp:boundcolumn>
<asp:boundcolumn
headertext="Winning Numbers"
datafield="WinningNumbers">
</asp:boundcolumn>
<asp:boundcolumn
headertext="Winner’s Name"
datafield="WinnersName">
</asp:boundcolumn>
</Columns>
</asp:DataGrid>
</p>
</form>
</body>
</html>
The code block beginning in line 5 shows the placement of the DataGrid
Control and also the adjustment of several visual properties. Many of these
properties are simply the shared properties inherited from Control and
3.19 Data List Controls 255
WebControl. Some are specific to the DataGrid Control, and those appear in
Table 3-15.
Property Description
AllowCustomPaging Controls custom paging
AlternatingItemStyle Gets the style properties for alternating items in the data grid
CellPadding Sets the amount of space between cells in the data grid
CellSpacing Sets the amount of space between the borders of adjacent cells
DataKeyField Gets or sets the primary key field in the data source
referenced by DataSource
DataSource Gets or sets the data source to which the control will bind; must
support the System.Collections.ICollection interface
(continued)
256 Chapter 3 Working with ASP.NET
Property Description
HorizontalAlign Sets how surrounding text flows around the data grid
ItemStyle Gets the style for the individual items in the data grid
PagerStyle Gets the style of the pager buttons for the data grid
ShowFooter Specifies whether or not to show the footer of the data grid
ShowHeader Specifies whether or not to show the header of the data grid
VirtualItemCount Gets or sets the total number of items in the data grid to
calculate the index of the first item on the page when
AllowCustomPaging is True
The DataGrid Control needs data to which to bind. We can create some
new data “on the fly” by using ADO.NET’s DataTable and DataRow objects in
the code-behind file.
Imports System
Imports System.Data
Imports System.Drawing
Imports System.Web
3.19 Data List Controls 257
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports Microsoft.VisualBasic
End Sub
With tblTable.Columns
.Add(New DataColumn("DrawingDate", _
System.Type.GetType("System.String")))
.Add(New DataColumn("WinningNumbers", _
System.Type.GetType("System.String")))
.Add(New DataColumn("WinnersName", _
System.Type.GetType("System.String")))
End With
For intCounter = 1 To 10
workRow = tblTable.NewRow()
workRow(“DrawingDate") = _
FormatDateTime(dteToday.Today.AddDays(-intCounter), _
DateFormat.ShortDate)
workRow("WinningNumbers") = CStr(intCounter * 100)
workRow("WinnersName") = “"
tblTable.Rows.Add(workRow)
Next
258 Chapter 3 Working with ASP.NET
dgMyDataGrid.DataSource = tblTable.DefaultView
dgMyDataGrid.DataBind()
End Sub
End Class
<Columns>
<asp:boundcolumn headerstyle-font-bold=True
headertext="Date"
datafield="DrawingDate"/>
<asp:boundcolumn headerstyle-font-bold=True
headertext="Winning Number"
datafield="WinningNumbers"/>
<asp:boundcolumn headerstyle-font-bold=True
headertext="Winner’s Name"
datafield="WinnersName"/>
</Columns>
The DataGrid Control can use any of the classes shown in Table 3-16 as
columns for the grid.
For the above example, we use the BoundColumn class to create bindings
between the visual column and the data field in the data source. There are
many styles we can apply to the BoundColumn class. We can set style character-
istics for the header, item, and footer portions of the column. In the example,
we apply bold formatting to headertext, which is the string displayed in the
top cell of the column. We also set a value for datafield, which tells the col-
umn which data field in the data source to use when displaying the item data.
3.19 Data List Controls 259
Table 3-16 Valid Controls for the Columns Collection of the DataGrid Control
Class Description
EditCommandButton Column for Edit, Update, and Cancel commands used for
editing data in the current row
When we run the code in this example, the output looks like that shown in
Figure 3-27.
The DataGrid Control supports other features that we haven’t covered
yet, such as in-place editing of data. We’ll cover that topic in Chapter 7 with
the discussions of data access and ADO.NET. We’ll revisit the DataGrid Con-
trol and add functionality, such as editing the data in the columns, updating
the database, and other functions.
To use the DataList Control, you need to place it on a Web Form, set the
list format, set the list layout, and template the data. In the example, let’s
begin by placing the DataList Control on a Web Form.
Src="WebFormDataListEx1.vb"
Inherits="WebFormDataListEx1"%>
<html><head>
<TITLE>DataList Example</TITLE>
</head>
<body>
<form id="WebFormDataListEx1"
method="post"
runat="server">
<h1>DataList Example</h1>
<p>
<asp:DataList id=dlMyDataList
runat="server"
ForeColor="Black">
<AlternatingItemStyle
BackColor="Gainsboro">
</AlternatingItemStyle>
<FooterStyle
BackColor="Silver"
ForeColor="White">
</FooterStyle>
<ItemStyle
BackColor="White">
</ItemStyle>
<HeaderStyle
BackColor="Navy"
Font-Bold="True"
ForeColor="White">
</HeaderStyle>
</asp:DataList>
</p>
</form>
</body>
</html>
262 Chapter 3 Working with ASP.NET
As mentioned before, the DataList Control uses the same template styles
as the Repeater Control, and we include some of them in the example. We
define Property tags for AlternatingItemStyle, FooterStyle, ItemStyle,
and HeaderStyle.
Now is a good time to make up some data to which the DataList Control
can bind. Here is the code-behind file that accomplishes this.
Imports System
Imports System.Data
Imports System.Collections
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports Microsoft.VisualBasic
strImagePath = Server.MapPath("images")
: dlMyDataList.DataSource = aryArrayList
dlMyDataList.DataBind()
End Sub
End Class
<asp:DataList id=dlMyDataList
runat="server"
repeatlayout=Table
repeatdirection=Horizontal
repeatcolumns=3>
<ItemTemplate>
; <%# Container.DataItem.FileName %><br>
< <img src="<%# Container.DataItem.ImageURL %>">
</ItemTemplate>
<AlternatingItemStyle
BackColor="white">
</AlternatingItemStyle>
<FooterStyle
ForeColor="White">
</FooterStyle>
<ItemStyle
BackColor="White">
</ItemStyle>
<HeaderStyle
BackColor="white"
Font-Bold="True"
ForeColor="White">
</HeaderStyle>
</asp:DataList>
Figure 3-28 Output of the DataList Control example for displaying images
266 Chapter 3 Working with ASP.NET
LAB 3-2
THE XYZ CORPORATION HOME PAGE
STEP 1. Launch VS.NET.
a. Launch VS.NET from the Windows Start bar.
since you’re changing the file type. Click the Yes button to approve the
change.
e. Another dialog box appears asking if you want to create a new class file
associated with the newly renamed .aspx file (see Lab Figure 3-22). Click
the Yes button to create the class file.
Lab Figure 3-21 Confirming the change to the file name extension
Lab Figure 3-23 The XYZ Corporation home page with placeholders for Web
Controls
b. To add radio buttons to the list, click the button in the Items property
to bring up the ListItem Collection Editor. Click the Add button to add a
ListItem. Edit the text and values of the ListItem as shown in Lab
Figure 3-24. If you wish to make a particular ListItem the default choice,
set the Selected property to True. Also, be sure to assign a meaningful
name to the control (through the ID property).
c. Repeat Step b for as many choices as you want to add to the list of radio
buttons.
270 Chapter 3 Working with ASP.NET
d. Next, add a submit button somewhere underneath the list of radio buttons
so the user can submit his or her survey response. Also, add a Label Con-
trol next to the button. This label will be used to display a message confirm-
ing that a selection was made. Assign an identifier (ID property) to each
of these controls. Lab Figure 3-25 shows an example of this portion of
the page.
e. On the other side of the page, there’s a placeholder for giving the user
the ability to enter his or her e-mail address to subscribe to the XYZ Cor-
poration newsletter. You want to validate the e-mail address entered
(as much as the RegularExpressionValidator Control allows you to)
to ensure you’re collecting “good data.” This requres the TextBox,
RegularExpressionValidator, Label, and Button Controls. Again,
3.20 Building the XYZ Corporation Home Page 271
Lab Figure 3-25 Placing the RadioButtonList, Label, and Button Controls
set the ID properties for each to meaningful names. Lab Figure 3-26 shows
a sample layout after completion of this step.
f. Now add the events calendar to the page by using the Calendar Control
(see Lab Figure 3-27). You can quickly change the display style of the calen-
dar, if you wish, by right-clicking the Calendar Control and selecting Auto
Format. . . . AutoFormat provides a graphical interface for changing styles.
g. Place the AdRotator Control at the top of the page near the banner ads
placeholder (see Lab Figure 3-28). Set the AdvertisementFile property to
“adrot.xml”.
c. Add some code to display information about XYZ Corporation events when
the user clicks a particular date on the calendar: the selected date is
checked, and an appropriate message is displayed in a Label Control.
strDateString = FormatDateTime( _
Calendar1.SelectedDate, _
DateFormat.ShortDate)
274 Chapter 3 Working with ASP.NET
d. Now all that’s left is to build the Web application by selecting Build➔Build
Solution from the menu bar. Set the Start Page to the home page file in the
Solution Explorer. Click the Start button on the tool bar to run your project.
That’s it for Lab 3-2! Of course, the coding for the XYZ Corporation Web site would be
considerably more complex than what you created in this lab, and the site would contain
many more pages. There are many different ASP.NET pages you can build on your own.
Get creative and get practicing!
<html>
<head>
<title>User Control Sample 1</title>
</head>
<body>
<form id="UserControlSample1"
method="post"
runat="server">
<p>New Password:
<asp:TextBox id=txtNewPassword
textmode=Password
runat="server">
</asp:TextBox>
</p>
<p>Confirm Password:
<asp:TextBox id=txtOldPassword
textmode=Password
runat="server">
</asp:TextBox>
276 Chapter 3 Working with ASP.NET
<asp:Button id=btnChangePassword
runat="server"
Text="Change Password">
</asp:Button>
</p>
<p>
<asp:CompareValidator id=cvPassword
runat="server"
ErrorMessage="Password not confirmed"
ControlToValidate="txtOldPassword"
ControlToCompare="txtNewPassword"
Display="Dynamic">
</asp:CompareValidator>
</p>
</form>
</body>
</html>
Now the transformation from Web Form to User Control occurs. To make
this Web Form into a User Control, the <html>, <form>, and <body> tag pairs
need to be removed from the file. Also, the <%@ Control %> directive needs
to be added. The attributes to the page directive (like the Language attribute)
can remain the same. Finally, we need to rename the file so it has an .ascx
extension, the extension for User Controls. The new code should read as
shown below.
<p>New Password:
<asp:TextBox id=txtNewPassword
textmode=Password
runat="server">
</asp:TextBox>
</p>
<p>Confirm Password:
<asp:TextBox id=txtOldPassword
textmode=Password
runat="server">
</asp:TextBox>
3.21 User Controls 277
<asp:Button id=btnChangePassword
runat="server"
Text="Change Password">
</asp:Button>
</p>
<p>
<asp:CompareValidator id=cvPassword
runat="server"
ErrorMessage="Password not confirmed"
ControlToValidate="txtOldPassword"
ControlToCompare="txtNewPassword"
Display="Dynamic">
</asp:CompareValidator>
</p>
That’s all we need to do to finish the User Control, but let’s take things just
a step further. User Controls can have custom properties, so let’s add one to
ours. Suppose that we want users to specify their own custom error messages
when the values for the two TextBox Controls do not match. We can add some
code directly to the .ascx file that declares a property.
</script>
<html>
<head>
</head>
<body>
<h1>User Control Demonstration</h1>
The PasswordConfirm User Control appears below:
<form id="UserControl1Usage"
method="post"
runat="server">
> <MattsControls:PasswordConfirm
id=pcMyPassword
ErrMessage="The password was not correctly confirmed"
runat="server"/>
</form>
</body>
</html>
Using a User Control in a Web Form starts with the <%@ Register %>
page directive, shown above beginning in line =. This directive informs
ASP.NET how we wish to reference the User Control we created previously.
User Controls, like Web Controls, have a TagPrefix and a TagName. You may
specify any strings to be used for TagPrefix and TagName. In this example, we
call the TagPrefix “MattsControls” and the TagName “PasswordConfirm”.
Most importantly, we tell ASP.NET where to find the .ascx file for the control
in the Src attribute (a relative path).
Now we place the User Control on the page. This works just like the other
Web Controls we’ve used before, as shown in line >. Notice the use of the
property ErrMessage. When we run this page, we see output like that shown
in Figure 3-29.
3.22 Saving State with the StateBag Object 279
Figure 3-29 Output of the example showing a User Control used in a Web Form
Property Description
Item Gets or sets the value of an item stored in the StateBag object
Keys Gets a collection of keys representing the items in the StateBag object
Values Gets a collection of the view state values stored in the StateBag object
Every Web Form has access to the ViewState object, which is a static
object you don’t need to declare explicitly. You can store any values you wish
in the ViewState collection. Here are some examples.
Writing to ViewState:
ViewState(“MyStateVariable") = “Test"
StrMyVariable = ViewState(“MyStateVariable")
Property Description
Filter Gets or sets the filter to use when reading the current input
stream.
Property Description
HttpMethod Gets the HTTP data transfer method (such as GET, POST,
or HEAD) used by the client.
PhysicalApplicationPath Gets the physical file system path of the currently executing
server application’s root directory.
RequestType Gets or sets the HTTP data transfer method (GET or POST)
used by the client.
(continued)
284 Chapter 3 Working with ASP.NET
Property Description
UserAgent Gets the raw user agent string of the client browser.
COLOR=green&SIZE=XL&STYLE=sweater%2FV+Neck
Property Description
BufferOutput Gets or sets a value indicating whether to buffer output and send
it after the entire page is finished processing
Cache Gets the caching policy (expiration time, privacy, vary clauses) of
a Web page
CacheControl Determines whether proxy servers are able to cache the output
generated by ASP
Charset Specifies the value of the character set in the HTTP Content-Type
header
ContentEncoding Gets or sets the HTTP character set of the output stream
ContentType Specifies the MIME HTTP content type to use for the response
Expires Sets the expiration date (after which the browser will refresh) for
the page
ExpiresAbsolute Sets the expiration date and time (after which the browser will
refresh) for the page
Filter Gets or sets a wrapping filter object used to modify the HTTP
entity body before transmission
IsClientConnected Indicates whether or not the Web browser still has an open
connection to the server (true/false value)
Status Specifies the value of the HTTP status line for the response
3.23 ASP.NET Intrinsic Objects 287
Property Description
StatusCode Gets or sets the HTTP status code of the output returned to
the client
StatusDescription Gets or sets the HTTP status string of the output returned to
the client
(continued)
288 Chapter 3 Working with ASP.NET
Write(ByVal s As String)
Write(ByVal buffer() As
Char, ByVal index As
Integer, ByVal count As
Integer)
WriteFile(ByVal fileHandle
As IntPtr, ByVal offset As
Long, ByVal size As Long)
WriteFile(ByVal filename
As String, ByVal offset As
Long, ByVal size As Long)
Name Description
Domain Sets the limiting domain for the cookie. Request must come from the
domain specified for the cookie to be returned.
Expires Sets the date when the cookie expires. Must be set for the cookie to be
written to the client’s disk.
Path If specified, the cookie is sent only to requests to this path. If this attribute is
not set, the application path is used.
Property Description
CreateObject(ByVal type As
Type) As Object
Execute(ByVal path As
String, ByVal writer As
TextWriter)
(continued)
292 Chapter 3 Working with ASP.NET
UrlEncode(ByVal s As
String, ByVal output As
TextWriter)
Application("variable_name") = value
3.23 ASP.NET Intrinsic Objects 293
The value assigned to the application variable can be of any type, includ-
ing string, numeric, and object variables. To retrieve the value of an applica-
tion variable, just reverse the notation:
variable = Application("variable_name")
Property Description
AllKeys Gets the access keys in the HttpApplicationState collection.
Property Description
CodePage Gets or sets the code page identifier for the current session
IsNewSession Gets a value indicating whether the session has been created with the
current request
IsSynchronized Gets a value indicating whether access to the collection of session state
values is read-only (thread-safe)
LCID Gets or sets the locale identifier (LCID) of the current session
SyncRoot Gets an object that can be used to synchronize access to the collection
of session state values
Timeout Gets and sets the time-out period (in minutes) allowed between
requests before the session state provider terminates the session
296 Chapter 3 Working with ASP.NET
Add Adds a new item to the session state Add(ByVal name As String,
ByVal value As Object)
Method Description
SetAbort Marks the current transaction as “failed” and notifies COM+ to undo any
changes made to database tables during the attempted transaction
SetComplete Notifies COM+ that this step in the transaction executed without problems
and the transaction can continue
Event Description
3.24 Summary
Let’s review what you’ve learned in this chapter.
■ ASP.NET applications are compiled code. They can be written in a
variety of .NET-capable languages and can be mixed freely. ASP.NET
applications provide facilities for state management, interactive debug-
ging, and integrated security features.
■ ASP.NET pages have a .aspx extension, which IIS uses to identify
ASP.NET pages. ASP.NET pages have an event model that allows you
to determine when the page loads and unloads.
■ ASP.NET Web applications are configured using an XML-based con-
figuration file called Global.asax. Using Global.asax, you can define
application event handlers that allow you to trap events such as session
starts and expirations.
■ The HTML Controls provide server-side functionality to standard
HTML elements. They are intended to correspond to the program-
ming model of HTML and make the migration of existing static HTML
pages to ASP.NET easier.
298 Chapter 3 Working with ASP.NET
■ The Web Controls provide rich server and client-side functionality for
displaying content in Web pages. Web Controls provided with
ASP.NET include standard user interface elements (such as text
boxes, buttons, and lists) and rich controls such as the Calendar and
AdRotator Controls. Web Controls can have many different events for
which you can write event handlers. Web Controls adjust their render-
ing behavior automatically according to the Web browser being used to
display them.
■ Validation Controls allow you to code client-side or server-side form
validation by simply placing various Validation Controls onto a Web
Form. Many types of validations can be performed, such as com-
parison operations, checks for required entries, and validation of
range limits.
■ List Controls are used to display data in tabular and free-form
formats. You can use templates to customize the exact look of the
formatted data. Data for the List Controls can come from a variety
of sources. The DataList and DataGrid Controls have rich editing
capabilities.
■ You can program custom controls called User Controls. These
snippets of ASP.NET code wrap up other server controls into a single
control. This provides a good way to reuse code and aids in consistency
within a Web site.
■ The ASP.NET intrinsic objects are intended to provide low-level
support for Web application development. By using the ASP.NET
intrinsic objects you can query the Web server for environment vari-
ables, get low-level access to CGI-encoded data, and perform other
functions.
■ Further Reading
■ MSDN Library (http://msdn.microsoft.com/library/default.asp): This is
the definitive source for programming reference material with the
Microsoft platform. Documentation for the .NET Framework is also
included.
This page intentionally left blank
CHAPTER 4
301
302 Chapter 4 Using the .NET Framework Class Library
Imports System
Imports System.Collections
Imports Microsoft.VisualBasic
Module Module1
Sub Main()
Dim aList1 As ArrayList
Dim aList2 As ArrayList
Dim intSearchChoice As Integer
Dim intLocatedIndex As Integer
Else
Console.WriteLine("No match found.")
304 Chapter 4 Using the .NET Framework Class Library
End If
End Sub
CreateArrayList = aNewArrayList
End Function
End Module
End Function
End Class
End Sub
Randomize()
For intIndex = 0 To 9
aNewArrayList.Add(objCustom)
Next
CreateCustomArrayList = aNewArrayList
End Function
Then it’s a simple matter of creating the array, calling Sort() in the nor-
mal fashion, and displaying the items.
4.2 Using Data Collections (System.Collections) 307
aCustomObjArray = CreateCustomArrayList()
aCustomObjArray.Sort()
PrintCustomArrayList(aCustomObjArray)
Imports System
Imports System.Collections
Imports Microsoft.VisualBasic
Module Module1
Sub Main()
l Do While (AddPhrase(stkUndoStack))
Loop
AddPhrase = True
DisplayStackContents(UndoStack)
End Function
End Sub
End Module
310 Chapter 4 Using the .NET Framework Class Library
Imports System
Imports System.Collections
Imports Microsoft.VisualBasic
Module Module1
DocTitle = DTitle
DocOwner = DOwner
DateTimeSubmitted = Now()
End Sub
End Class
For intIndex = 1 To 5
objDoc = New DocRecord()
With objDoc
.DocOwner = "Joe"
.DocTitle = "Document #" & _
intIndex.ToString()
End With
q objDocQueue.Enqueue(objDoc)
Next
InitializeQueue = objDocQueue
End Function
Sub Main()
Dim objPrtQueue As Queue
objPrtQueue = InitializeQueue()
ShowDocsInQueue(objPrtQueue)
End Module
Print Queue
Imports System
Imports System.Collections
Imports Microsoft.VisualBasic
Module Module1
End Class
Randomize()
intIDNumber = rndRandom.Next(1, 1000)
t Do While ContactTable.ContainsKey(intIDNumber)
intIDNumber = rndRandom.Next(1, 1000)
Loop
u ContactTable.Add(intIDNumber, objContactEntry)
Console.WriteLine("Added contact with ID: " & _
intIDNumber.ToString())
End Sub
v CInt(Console.ReadLine()))
End Sub
End Sub
Sub Main()
Dim objMyContacts As New Hashtable()
AddContact(objMyContacts)
AddContact(objMyContacts)
AddContact(objMyContacts)
ListContacts(objMyContacts)
QueryContact(objMyContacts)
End Sub
End Module
316 Chapter 4 Using the .NET Framework Class Library
This simple program prompts the user to enter information about three
contacts and stores those contacts in a hashtable. After completion of data
entry, the contacts are displayed in a list, and the program prompts the user
for a key value (ID number) to recall a contact’s information.
A unique key value must be used to insert a new object into a hashtable.
The key value for each contact is randomly generated. Line t shows how to
generate this value. Beginning with a random number, the program searches
the hashtable for an existing key with this randomly generated value by using
the ContainsKey() method. Since the value needs to be unique, the program
repeatedly generates a random number until an unused key value is found.
Then, the new ContactEntry class object is added to the hashtable using the
Add() method shown in line u.
We can search a hashtable by using the Item() method. The single parame-
ter to the Item() method in line v is the object (in this case it’s an Integer
type) that is the key value. The Item() method returns an object reference to
the matching object or Nothing if the object can’t be located.
Beginning in line w we include code to display the contacts in a list. By
using the Values() method, we can obtain an ICollection interface handle
that can be used by the For . . . Each loop. The objContact variable holds
the current contact as we iterate through the loop, and we access its members
to display the data to the console.
Imports System
Imports System.IO
Module Module1
Sub Main()
Try
objStreamReader = File.OpenText("test.txt")
Console.Write(objStreamReader.ReadToEnd())
objStreamReader.Close()
Catch E As Exception
Console.WriteLine("Error occurred: " & E.Message)
End Try
End Sub
End Module
Property Description
on), or a more complex String data type. You have the flexibility to write
formatted strings, like the ones used when specifying a ParamArray in
Console.Write(). The following example demonstrates these various ways
of writing to a stream using the StreamWriter class.
4.3 Handling File Input/Output and Directories (System.IO) 319
Imports System
Imports System.IO
Module Module1
Sub WriteToStream()
Dim objStreamWriter As StreamWriter
Dim intA As Integer = 100
Dim intB As Integer = 200
Dim blnSampleBoolean As Boolean = True
Dim dSampleDecimal As Decimal = 3.14
Try
objStreamWriter = File.CreateText("c:\newfile.txt")
With objStreamWriter
.WriteLine("Log File for " & FormatDateTime(Now()))
.WriteLine("------------------------------------")
.Write("This is a formatted string: {0} {1}", _
intA, intB)
.WriteLine()
.WriteLine(blnSampleBoolean)
.WriteLine(dSampleDecimal)
.Close()
End With
Catch E As Exception
Console.WriteLine("Error occurred: " & E.Message)
End Try
End Sub
Sub Main()
WriteToStream()
End Sub
End Module
Tables 4-3 and 4-4 list the properties and methods, respectively, of the
StreamWriter class.
Property Description
AutoFlush Causes all output bound for the stream to be written immediately
when the value is True
NewLine (inherited Gets or sets the line terminator string used by the current
from TextWriter) TextWriter class
WriteLine(Char())
WriteLine(Decimal)
WriteLine(Double)
WriteLine(Int32)
WriteLine(Int64)
WriteLine(Object)
WriteLine(Single)
WriteLine(String)
WriteLine(UInt32)
WriteLine(UInt64)
WriteLine(String, Object)
WriteLine(String,Object())
Property Description
Handle Gets the operating system file handle for the file that the current
FileStream object encapsulates; used with COM interoperability
with unmanaged code
(continued)
324 Chapter 4 Using the .NET Framework Class Library
TECHTALK: MP3
MPEG Layer 3 (commonly referred to as MP3) is a popular
file format for encoding audio data into a highly compressed
form. In spite of their small size, MP3 files have extraordinary
sound quality and are well suited for playing back high-
fidelity music.
As the popularity of the MP3 format increased, users
began to collect large numbers of MP3 files. To facilitate
indexing of these files (using a scheme other than the
file name), the ID3v1 standard was created. The ID3v1
structure is a 128-byte data block appended to the end
of the file that contains information about the song title,
artist, album, year of publication, genre, and additional
comments. You can find additional information about
ID3v1 (including the updated standard, ID3v2) at http://
www.id3.org/id3v1.html.
Imports System
Imports System.IO
Module Module1
Try
x m_objFS = New FileStream(FileName, _
FileMode.Open, _
FileAccess.ReadWrite)
y m_objFS.Seek(m_objFS.Length - 128, _
SeekOrigin.Begin)
z m_objFS.Read(bytTag, 0, 128)
{ m_strRawID3 = BytesToString(bytTag)
Catch E As Exception
Console.WriteLine("Error: " & E.Message)
End Try
Sub Main()
Dim objMP3Info As New _
MP3ID3v1("c:\Peter Murphy - Cuts You Up.mp3")
With objMP3Info
Console.WriteLine("Artist: {0}", .m_strArtist)
Console.WriteLine("Title: {0}", .m_strTitle)
Console.WriteLine("Album: {0}", .m_strAlbum)
Console.WriteLine("Year: {0}", .m_strYear)
Console.WriteLine("Comment: {0}", .m_strComment)
Console.WriteLine("Genre Code: {0}", .m_strGenreCode)
End With
End Sub
End Module
Let’s investigate the source code. The MP3ID3v1 class contains member
variables for each of the ID3v1 segments that occur at different offsets in the
file. The overloaded New() constructor calls the function that reads the song
information, RefreshID3Info().
The real work of reading the ID3v1 block begins with opening the file by
creating a new FileStream object in line x. In the constructor, we specify the
file name, how we wish to open the file (open existing, open existing or create,
open for append, and so on), and whether or not we want the stream to sup-
port read/write (in this example we specify read and write access). Once the
stream is opened, we want to position it at the start of the ID3v1 data block.
Since the data block is positioned at the end of the file and we know it’s a fixed
328 Chapter 4 Using the .NET Framework Class Library
If GenreCode = 0 Then
strNewRawID3 &= Chr(CInt(m_strGenreCode))
Else
strNewRawID3 &= Chr(GenreCode)
End If
Try
With m_objFS
~ .Seek(m_objFS.Length - 128, SeekOrigin.Begin)
Ö .Write(StringToBytes(strNewRawID3), 0, 127)
Ä .Flush()
330 Chapter 4 Using the .NET Framework Class Library
Å .Close()
End With
Catch E As Exception
Console.WriteLine("Error writing ID3 info: " & E.Message)
End Try
End Sub
Dim ch As Char
Dim intIndex As Integer
Dim bytReturnArray(128) As Byte
StringToBytes = bytReturnArray
End Function
The new subroutine allows us to modify part or all of the existing ID3v1
information by using Optional parameters for the subroutine. If a parameter
is not specified, the existing value in the class member variable that corre-
sponds to the parameter is used. The boldface code blocks beginning in line }
show how we build the ID3v1 string. Each parameter is appended to the
string and padded out to 30 characters with spaces (4 characters for the year)
using the String object’s PadRight() method.
As in the prior example, we use the Seek() method in line ~ to position
the stream at the start of the ID3v1 block. In line Ö, we use a private function
to reverse the conversion we did previously; this time we convert the string
into a byte array using StringToBytes(). This result is then used by the
Write() method to write the binary block to the file. The Flush() method in
line Ä ensures that the buffered writing persists to the disk. Then we finalize
the process by closing the stream in line Å.
To call the new member subroutine, use the following example code. This
changes the comment to the new string, leaving the other fields unmodified.
objMP3Info.WriteID3Info("", "", "", "", "Matt was here")
4.3 Handling File Input/Output and Directories (System.IO) 331
Imports System
Imports System.IO
Module Module1
Sub DisplayFileInformation(ByVal FileSpec As String)
Dim strFileInfo As String
Dim fabFileAttribs As New FileAttributes()
Ç Dim objFileInfo As New FileInfo(FileSpec)
É Try
If objFileInfo.Exists Then
fabFileAttribs = objFileInfo.Attributes
Ñ If fabFileAttribs And FileAttributes.Archive Then
Console.WriteLine("Archive flag set")
Else
Console.WriteLine("Archive flag set")
End If
! strFileInfo = "File information: {0}" & _
ControlChars.CrLf & _
"Size: {1}" & ControlChars.CrLf & _
332 Chapter 4 Using the .NET Framework Class Library
End Sub
Sub Main()
DisplayFileInformation("test.txt")
End Sub
End Module
Try
objFileInfo = New FileInfo(FileToCopy)
objFileInfo.CopyTo(objFileInfo.DirectoryName & _
"Copy of " & objFileInfo.Name, _
True)
objFileInfo.MoveTo(objFileInfo.DirectoryName & _
"OLD_" & objFileInfo.Name)
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
End Sub
Imports System
Imports System.IO
Imports Microsoft.VisualBasic
Module Module1
Try
Ü If Not objDir.Exists Then
# objDir.Create()
End If
$ Console.WriteLine(strDirInfo, _
objDir.FullName, _
FormatDateTime(objDir.CreationTime), _
FormatDateTime(objDir.LastAccessTime), _
FormatDateTime(objDir.LastWriteTime))
4.3 Handling File Input/Output and Directories (System.IO) 335
strRootDir = objDir.FullName
Catch E As Exception
Console.WriteLine("Error: " & E.Message)
End Try
End Sub
Sub Main()
DisplayDirectoryInfo(".\")
End Sub
End Module
Imports System
Imports System.IO
Module Module1
Try
aFiles = objDir.GetFiles()
Catch E As Exception
Console.WriteLine("Error: " & E.Message)
End Try
End Sub
Sub Main()
DisplayDirectoryContents(".\")
End Sub
End Module
This class has many practical applications. For example, suppose that you
have a back-end image-processing system that accepts user submissions for
an online photo album. After an image is sent to the Web host, a server-side
application could copy the image file to a particular processing directory.
Whenever new files are added to this processing directory, the system could
generate a thumbnail version of the image suitable for browsing in a Web
page. The FileSystemWatcher class could provide the functionality to moni-
tor the directory and direct application code to generate the thumbnail upon
receipt of the file.
The FileSystemWatcher class works through either an asynchronous,
event-driven mechanism or through a synchronous wait routine. In the event-
driven model, event handlers are registered for different file events such as
when files are changed, created, deleted, or renamed. Whenever a change
occurs in the watched directory, a corresponding event is raised for that
change. In the synchronous watching mechanism, a method is called that
waits indefinitely until a change occurs.
Applications that use the FileSystemWatcher class are typically Windows
Services or other “faceless” applications.
Table 4-7 lists the properties of the FileSystemWatcher class, and Table
4-8 lists the methods.
In the example on page 338, we use the event-driven mechanism of file-
watching. The code watches a directory for files that are created, changed,
renamed, or deleted.
338 Chapter 4 Using the .NET Framework Class Library
Imports System
Imports System.IO
Module Module1
Sub Main()
( objWatcher.NotifyFilter = NotifyFilters.FileName Or _
NotifyFilters.Attributes Or _
NotifyFilters.LastAccess Or _
NotifyFilters.LastWrite Or _
NotifyFilters.Security Or _
NotifyFilters.Size
* objWatcher.EnableRaisingEvents = True
e.FullPath, strChange)
End Sub
End Module
Property Description
Filter Gets or sets the filter used to determine what subset of files
to monitor for changes.
InternalBufferSize Sets the size (in bytes) of the buffer to use to store change
data. Should be a minimum of 4096 bytes (4K) and a
multiple of that value for best performance.
block that begins in line ( we tell the FileSystemWatcher object what types
of changes to monitor. In this case, we are watching for any changes to a file’s
attributes, last accessed time, last write time, security attributes, or size.
4.4 Watching the File System for Changes (System.IO.FileSystemWatcher) 341
Value Description
new names of the file. Any event handler for rename events must have a signa-
ture using the RenamedEventArgs object.
Imports System
Imports System.Diagnostics
Imports Microsoft.VisualBasic
Module Module1
Sub Main()
Dim strLogStr As String
WriteToLog(strLogStr)
ReadApplicationLog()
End Sub
End Sub
strLog = "Application"
strSource = "EventLogSample"
4.5 Using the Windows Event Log (System.Diagnostics) 345
6 objLog.WriteEntry(StringToLog, _
EventLogEntryType.Information)
End Sub
End Module
This program reads and writes to the Event Log. Let’s begin our discus-
sion with the ReadApplicationLog() subroutine. We first need to check to
see if the desired log exists on the target machine (the local machine) by using
the static Exists() method in line .. If that succeeds, we proceed to line /
where we create a new EventLog object. In lines 0 and 1 we set the Log and
MachineName properties with the values “Application” and “.”, respectively,
to denote the Application Log and the local machine.
With those properties set, we are ready to retrieve information about the
log. Starting with line 2 we retrieve the number of entries in the log using the
Entries.Count property. In line 3 we start a For . . . Each loop to iterate
the collection of EventLogEntry objects in Entries. Each EventLogEntry
object contains properties that correspond to the different fields in the Event
Log. Beginning in line 4 we display the contents of the EntryType,
TimeWritten, Source, and Message properties.
Writing to the Event Log is handled by the WriteToLog() subroutine.
Taking a single String parameter, the subroutine repeats the process of
ReadApplicationLog() that checks for the existence of the Application Log
and the creation of a new EventLog object. Before the write to the log occurs,
we set the Source property in line 53, which denotes what program is produc-
ing the event. Writing to the log is accomplished through a call to the
WriteEntry() method in line 54.
Figure 4-2 shows some sample output from the program.
346 Chapter 4 Using the .NET Framework Class Library
Imports System
Imports System.IO
Imports System.DirectoryServices
Imports Microsoft.VisualBasic
Module Module1
348 Chapter 4 Using the .NET Framework Class Library
Try
7 objDirEnt = New DirectoryEntry(ADPath)
End Sub
Sub Main()
GetADInfo("WinNT://rmdevbiz01")
Console.WriteLine("--------------------------")
GetADInfo("WinNT://rmdevbiz01/matt")
End Sub
End Module
4.6 Working with Active Directory Services (System.DirectoryServices) 349
Name = RMDEVBIZ01
Path = WinNT://rmdevbiz01
SchemaClassName = Computer
Properties:
OperatingSystem =
Windows NT
OperatingSystemVersion =
5.0
Owner =
SampleOwner
Division =
SampleDivision
ProcessorCount =
Uniprocessor Free
Processor =
x86 Family 6 Model 7 Stepping 2
For the next example, we take the previous code and change the Active
Directory Services path to point to a user account on a particular machine.
Here’s sample output of that directory node for the user “matt.”
350 Chapter 4 Using the .NET Framework Class Library
Name = matt
Path = WinNT://rmdevbiz01/matt
SchemaClassName = User
Properties:
RasPermissions =
1
UserFlags =
66049
MaxStorage =
-1
PasswordAge =
323671
PasswordExpired =
0
LoginHours =
System.Byte[]
FullName =
Matt J. Crouch
Description =
Developer
BadPasswordAttempts =
0
HomeDirectory =
LoginScript =
Profile =
HomeDirDrive =
Parameters =
PrimaryGroupID =
513
MinPasswordLength =
6
MaxPasswordAge =
5184000
MinPasswordAge =
86400
PasswordHistoryLength =
5
AutoUnlockInterval =
4.6 Working with Active Directory Services (System.DirectoryServices) 351
1800
LockoutObservationInterval =
1800
MaxBadPasswordsAllowed =
5
objectSid =
System.Byte[]
TECHTALK: LDAP
Details on the Lightweight Directory Access Protocol
(LDAP) can be found in RFC 1777 at http://www.ietf.
org/r fc/r fc1777.txt including the syntax used for search
queries strings.
Try
; objDirEnt = New DirectoryEntry( _
"LDAP://ldap.yourserverhere.com")
< objADSearch = New DirectorySearcher(objDirEnt, _
"(sn=" & LastName & "*)")
= objSearchRSColl = objADSearch.FindAll()
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
Inside the For . . . Each loop, notice the call to the GetDirectoryEntry()
method in line >. This method of the SearchResult class is used to obtain a
DirectoryEntry object for each SearchResult object in the objSearchRSColl
SearchResultCollection. After this DirectoryEntry object is retrieved, we
can display information about it, such as its Name property (see line ?). This
returns the LDAP common name (cn) for the object, which usually contains
the person’s full name (depending on the organization of the LDAP directory).
The SearchResult object properties and method are listed in Tables 4-10
and 4-11, respectively.
The SearchResultsCollection class contains not only a collection but
also useful operations such as dumping the objects in the collection into an
array. Tables 4-12 and 4-13 describe the properties and methods, respectively,
available in the SearchResultsCollection class.
Tables in Appendix A show the properties and methods of the
DirectoryEntry and DirectorySearcher classes.
Property Description
Method Description
Property Description
of the account. The code change is minimal; it requires setting one of the
properties of a DirectoryEntry object with a new value, as shown in boldface
text in the following code snippet.
Try
4.7 Using Message Queues (System.Messaging) 355
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
All that’s involved in changing the property is obtaining the key name of a
property in the Properties collection (a PropertyCollection class) and
specifying the item index (in this case, 0). Then we can assign a new value.
Changes aren’t permanent until the CommitChanges() method is called and
the application has sufficient permissions to modify the directory.
once. Again, this works like the e-mail example. When the user attempts to
retrieve the messages from the server, he or she sends a message back to the
server for each message indicating it was successfully retrieved and can be
removed from the server (queue). Like e-mail systems, the MSMQ system has
the ability to prioritize messages. Messages that are marked as urgent make
their way through the queue much faster than messages of lower priority.
Try
@ If Not MessageQueue.Exists(".\" & QName) Then
objQueue = MessageQueue.Create(".\" & QName)
Else
A objQueue = New MessageQueue(".\" & QName)
End If
CreatePublicQueue = objQueue
Catch E As Exception
Console.WriteLine("Error: " & E.Message)
End Try
End Function
In line @ the function checks to see if the queue already exists by using
the static method Exists(). Notice that the pathname to the queue begins
with ".\". This denotes that the queue we are attempting to look up would
reside on the local computer. If the queue doesn’t already exist, we use the
static Create() method to make the new queue with the specified name. If
the queue with the specified name already exists, we simply pass that name
into the MessageQueue constructor in line A, which returns a MessageQueue
object pointing to the queue path.
Property Description
Active Indicates whether the TCP connection is still active (true/false value)
NoDelay Causes a delay to be invoked when send and receive buffers are full
if the value is set to True
SendTimeout Sets the send time-out value (in milliseconds) of the connection
Connect(ByVal address As
IPAddress, ByVal port As
Integer)
Connect(ByVal hostname As
String, ByVal port As
Integer)
mand is sent over the socket connection and the response from the server is
received and then displayed.
Imports System
Imports System.IO
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports Microsoft.VisualBasic
Module Module1
Try
B objTCPClient.Connect("localhost", 80)
C objStream = objTCPClient.GetStream()
D bytWrite = Encoding.ASCII.GetBytes(strHTTPCommand)
E objStream.Write(bytWrite, 0, bytWrite.Length)
F intNumberOfBytes = objStream.Read(bytReceivedData, _
0, 1024)
intTotalBytes += intNumberOfBytes
G Do While intNumberOfBytes <> 0
ReDim Preserve bytReceivedData( _
bytReceivedData.Length + 1024)
intNumberOfBytes = objStream.Read( _
4.8 Communicating with Servers on the Internet (System.Web and System.Net) 361
bytReceivedData, _
intTotalBytes, 1024)
intTotalBytes += intNumberOfBytes
Loop
strReceivedData = _
H Encoding.ASCII.GetString(bytReceivedData)
Console.WriteLine(strReceivedData)
I objTCPClient.Close()
End Sub
End Module
the storage of the accumulated data, we increase the size of the array by 1K
for each chunk read from the stream while keeping a running total of the
number of bytes received. Once the loop completes, signaled by a Read()
return value of 0, the program truncates the byte array to the actual number
of bytes stored in the array. In line H we use the Encoding.ASCII class to
convert the data received in the byte array back into a String object using
the GetString() method.
Finally, the program displays the data to the user and closes the connec-
tion with the Close() method in line I. Here is some sample output from the
program.
HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Cache-Control: no-cache
Expires: Tue, 14 Aug 2001 02:13:55 GMT
Date: Tue, 14 Aug 2001 02:13:55 GMT
Content-Type: text/html
Accept-Ranges: bytes
Last-Modified: Tue, 14 Aug 2001 01:10:02 GMT
ETag: "2c6d3ad85d24c11:8d5"
Content-Length: 144
<html>
<head>
<TITLE>Matt's Home Page</TITLE>
</head>
<body>
<h1>Welcome to Matt's Home Page</h1>
Enjoy your stay.
</body>
</html>
Property Description
Active Gets or sets a value that indicates whether the listener’s socket has been
bound to a port and started listening
LocalEndpoint Gets the active end point for the local listener socket
The small server program below listens for connection requests and dis-
plays incoming data from the TCP client. This functionality is encapsulated in
a class we call TCPServ.
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.IO
Module Module1
L objTCPClient = m_objTCPListener.AcceptTcpClient()
M objNetStream = objTCPClient.GetStream()
Do While True
N If objNetStream.DataAvailable Then
intBytesRead = _
O objNetStream.Read(m_bytRequest, 0, _
m_bytRequest.Length)
ReDim Preserve m_bytRequest(intBytesRead)
strStringRequest = _
Encoding.ASCII.GetString(m_bytRequest)
Console.WriteLine("Server received: " & _
strStringRequest)
End If
Loop
End Sub
4.8 Communicating with Servers on the Internet (System.Web and System.Net) 365
End Class
Sub Main()
Dim objTCPServ As New TCPServ()
objTCPServ.Run()
End Sub
End Module
In the constructor of the TCPServ class we initiate the first step of setting
up the server: creating a TcpListener object and setting it to listen on a TCP
port (port 10000) in line J. Then, to begin listening for connections, we call
the Start() method in line K.
In the Run() subroutine we accept an incoming connection to the server
by using AcceptTcpClient() in line L. This method, once called, waits (and
blocks the current thread) until a connection is received. AcceptTcpClient()
predictably returns a TcpClient object, just like the one used in the previous
examples. From this object we obtain the NetworkStream object, which is
used to read the incoming data from the TCP client using GetStream() in
line M.
Next we start a Do . . . While loop that receives the data from the TCP
client until the program is terminated. First the program checks to see if there
is data to receive on the stream by looking at the DataAvailable property in
line N. If ready to proceed with receiving data, the program calls Read() in
line O to populate a byte array with the data. Then the byte array is converted
into a String object for display to the console.
Property Description
ContentLength Sets the content length (in bytes) of the request data
Method Determines the HTTP protocol method used for the request
(for example, GET, POST, HEAD)
RequestUri Gets the URI of the Internet resource associated with the
request when overridden in a descendant class
Property Description
Headers The collection of HTTP header name–value pairs from the response
ResponseUri The URI of the Internet resource that responded to the request
Here’s a sample program that allows the user to enter a URL, retrieve tex-
tual data like an HTML or text file from a Web server, and view that data in
the console. The program demonstrates the use of the WebRequest and
WebResponse classes.
Imports System
Imports System.Net.Sockets
Imports System.Net
Imports System.IO
Imports System.Text
Module Module1
Sub Main()
Console.WriteLine("Enter a URL to retrieve:")
4.8 Communicating with Servers on the Internet (System.Web and System.Net) 369
GetDocument(Console.ReadLine())
End Sub
P objReq = WebRequest.Create(URL)
Q objResult = objReq.GetResponse()
R objReceiveStream = objResult.GetResponseStream()
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
End Module
then convert the resulting data collected in the byte array to a String object
to display to the console.
Note: This text covers only a subset of the capabilities of the System.XML
classes that support XML in the .NET Framework. Most of the material pre-
sented in the examples applies to DOM Level 1 Core functionality.
<Songs>
<song format="MP3">
<title>Eh Cumpari</title>
<artist>Julius LaRosa</artist>
<length>149</length>
<category>Italian-American</category>
</song>
<song format="CD">
<title>Plasticity</title>
<artist>Front Line Assembly</artist>
<length>406</length>
<category>Industrial</category>
</song>
</Songs>
Imports System
Imports System.Xml
Module Module1
U objRoot = XMLDoc.DocumentElement
V objSong = XMLDoc.CreateElement("song")
W objSong.SetAttribute("format", SongFormat)
X objSongTitle = XMLDoc.CreateElement("title")
Y objTmpText = XMLDoc.CreateTextNode(SongTitle)
Z objSongTitle.AppendChild(objTmpText)
[ objSong.AppendChild(objSongTitle)
objSongArtist = XMLDoc.CreateElement("artist")
objTmpText = XMLDoc.CreateTextNode(SongArtist)
objSongArtist.AppendChild(objTmpText)
objSong.AppendChild(objSongArtist)
objSongLength = XMLDoc.CreateElement("length")
objTmpText = XMLDoc.CreateTextNode(SongLength)
objSongLength.AppendChild(objTmpText)
objSong.AppendChild(objSongLength)
objSongCategory = XMLDoc.CreateElement("category")
objTmpText = XMLDoc.CreateTextNode(SongCategory)
objSongCategory.AppendChild(objTmpText)
objSong.AppendChild(objSongCategory)
\ objRoot.AppendChild(objSong)
AddEntryToDoc = XMLDoc
End Function
Sub Main()
Dim objSongXMLDoc As XmlDocument
objSongXMLDoc = CreateXMLDocument()
objSongXMLDoc = AddEntryToDoc(objSongXMLDoc, _
4.9 Manipulating XML Data (System.XML) 373
"MP3", _
"Julius LaRosa", _
"Eh Cumpari", _
"149", _
"Italian-American")
objSongXMLDoc = AddEntryToDoc(objSongXMLDoc, _
"CD", _
"Front Line Assembly", _
"Plasticity", _
"406", _
"Industrial")
DisplayXMLDocument(objSongXMLDoc)
End Sub
End Module
Building a new XML document with the DOM begins with the crea-
tion of a new XmlDocument object, which is the responsibility of the
CreateXMLDocument() function. This is the root of the document where we
perform many different operations, such as creating elements, as shown in
line S. Moving on to line T, we begin to assemble the top level of the XML
document, the <song> node where all the song “records” (nodes) will be con-
tained. Then the XmlDocument object is returned from the function.
Now the XML document is ready to accept entries. We first need to
obtain an XmlElement from the root of the XML document using the
DocumentElement property shown in line U. We’ll need this after we
assemble all the elements of the <song> node for addition to the XML
document.
Next we begin assembling a <song> node by creating the needed elements
for song format, song title, artist, song length, and musical category. Each of
these items is of the XmlElement type. To create a new element, we call the
CreateElement() function of the XmlDocument class (specifying a name for
the element), which returns an XmlElement object. Assembly of the <song>
node begins in line V with the creation of an XmlElement with the name
"song". Since the <song> element has an attribute called "format", we can
add that by calling the SetAttribute() method of the XmlElement class in
line W and supplying the value for the attribute.
Now that we’ve established the empty <song> node, we can create nested
elements for the song’s catalog information. Again, we start by creating a new
374 Chapter 4 Using the .NET Framework Class Library
XmlElement object in line X, this time for the song’s title. The song’s title will
be contained within the <title></title> tags. This text is represented in the
XML DOM as an XmlText object. We create a new instance of this object in
line Y by using the CreateTextNode() method of XmlDocument and specifying
the text as the parameter. Now that we have the XmlElement object represent-
ing the song title and its associated element text, we need to add it to the doc-
ument structure. The AppendChild() method shown in line Z attaches an
existing XmlNode (XmlElement derives from XmlNode) to another XmlElement
or XmlNode. The AppendChild() method associates the XmlText object, which
contains the song title text, to the <title> XmlElement, then the code in line
[ adds the complete <title> XmlElement to the <song> node, represented
by objSong. This procedure repeats for the artist, song length, and musical
category. Once we have all the child elements in place for the <song> node, it
is added to the root DocumentElement objRoot in line \. Then the updated
XML document is returned from the function, and the results are displayed to
the console using the InnerXml property.
The properties and methods of the XmlDocument, XmlElement, and
XmlText classes used in this example are outlined in Appendix A.
Imports System
Imports System.Xml
Module Module1
End Sub
Sub Main()
Try
376 Chapter 4 Using the .NET Framework Class Library
_ objXMLDoc.Load("songs.xml")
` DisplayNode(objXMLDoc.ChildNodes)
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
End Module
]>
<Songs>
<song format="MP3">
<title>Eh Cumpari</title>
<artist>Julius LaRosa</artist>
<length>149</length>
<category>Italian-American</category>
</song>
<song format="CD">
<title>Plasticity</title>
<artist>Front Line Assembly</artist>
<length>406</length>
<category>Industrial</category>
</song>
</Songs>
TIP: You don’t have to include your DTD and XML in the
same file. This example does so for simplicity’s sake, but
you can specify an external reference to a DTD by substitut-
ing this line in place of the inline DTD:
<!DOCTYPE Songs SYSTEM "your_dtd_file.dtd ">
The DTD allows for any number of song entries and imposes a rule that
the format attribute for <song> elements must be one of the following: MP3,
LP, CS, or CD.
The code for reading in an XML document with validation remains much
the same as that for no validation, except for how we load the XML file. In the
Main() subroutine, we change some of the code that loads the XML docu-
ment, as indicated by the boldface text below.
Sub Main()
Try
378 Chapter 4 Using the .NET Framework Class Library
objXmlValidatingReader = New _
XmlValidatingReader(objXmlTextReader)
objXMLDoc.Load(objXmlValidatingReader)
DisplayNode(objXMLDoc.ChildNodes)
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
Loading validated XML data into an XmlDocument object starts with the
XmlTextReader class. This class is normally used for reading XML data in a
stream-based mechanism (see Section 4.9.3), but we are using it to create an
XmlTextReader object for the constructor of the XmlValidatingReader class.
Now, instead of passing a file name to the Load() method of the XmlDocument
object, we give Load() the XmlValidatingReader object that we created.
When Load() is called, if any errors are found during validation of the XML
data, an exception is thrown citing in what line numbers and column numbers
the validation errors occurred. In this example, an invalid option was selected
for the format attribute and the program output this error message (you’ll
have to modify the XML file and put in an invalid format attribute value for
an error to be generated):
ERROR: The 'format' attribute has an invalid value according to its
data type.
An error occurred at file:///c:/songs2.xml(13, 8).
TECHTALK: XPATH
XPath is rather complicated, and discussion of it is really
beyond the scope of this book. But you can find all the infor-
mation you need to know about XPath at http://www.w3.
org/TR/xpath.
4.9 Manipulating XML Data (System.XML) 379
Let’s use the previous XML data file of songs and perform a search. The
loading code remains the same as the previous example. The new function,
SearchArtist(), finds all songs matching a specified artist and displays the
node contents for each match of the query.
Imports System
Imports System.Xml
Module Module1
objNodeList = XmlDoc.SelectNodes( _
"descendant::song[artist='" & Artist & "']")
End Sub
Sub Main()
Try
objXmlValidatingReader = New _
XmlValidatingReader(objXmlTextReader)
objXMLDoc.Load(objXmlValidatingReader)
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
380 Chapter 4 Using the .NET Framework Class Library
End Try
End Sub
End Module
The boldface code shows the use of the SelectNodes() method. The
parameter we passed to it is the XPath query string. This query says to return
all the nodes that contain an <artist> element with the text passed into the
function as a parameter. Then we display a string representation of the match-
ing node data using the InnerText property of every node in the returned
XmlNodeList.
SelectSingleNode() works the same way, but it’s used for returning only
one XmlNode. Use SelectSingleNode() when your query should return only
one XmlNode.
Imports System
Imports System.Xml
Module Module1
Sub Main()
Dim objReader As XmlTextReader = Nothing
4.9 Manipulating XML Data (System.XML) 381
Try
b While objReader.Read()
c Select Case objReader.NodeType
Case XmlNodeType.Element
Console.WriteLine("<{0}>", _
objReader.Name)
Case XmlNodeType.Text
Console.WriteLine(objReader.Value)
Case XmlNodeType.XmlDeclaration
Console.WriteLine( _
"<?xml version='1.0'?>")
Case XmlNodeType.EndElement
Console.WriteLine("</{0}>", _
objReader.Name)
End Select
End While
Finally
If Not (objReader Is Nothing) Then
䢇
100 objReader.Close()
End If
End Try
End Sub
End Module
Select . . . Case block to format the value of the node for display to the con-
sole. At the end of the loop, the program checks to see if all nodes have been
read from the stream by checking whether the XmlTextReader class contains a
null reference (Nothing). If so, the program closes the stream (see line 䢇100).
Sub XmlWriteDemo()
Dim writer As New _
䢇
101 XmlTextWriter("sample.xml", Nothing)
䢇
102 writer.Formatting = Formatting.Indented
䢇
103 writer.WriteComment("Stream-XML Write demo")
䢇
104 writer.WriteStartElement("Songs")
䢇
105 writer.WriteStartElement("song")
䢇
106 writer.WriteStartAttribute("", "format", "")
䢇
107 writer.WriteString("MP3")
䢇
108 writer.WriteEndAttribute()
writer.WriteStartElement("title")
writer.WriteString("Plasticity")
writer.WriteEndElement()
writer.WriteStartElement("artist")
writer.WriteString("Front Line Assembly")
writer.WriteEndElement()
4.9 Manipulating XML Data (System.XML) 383
writer.WriteStartElement("category")
writer.WriteString("Industrial")
writer.WriteEndElement()
writer.WriteStartElement("length")
writer.WriteString("406")
writer.WriteEndElement()
writer.WriteEndElement()
䢇
109 writer.WriteEndElement()
writer.Flush()
writer.Close()
doc.PreserveWhitespace = True
doc.Load("sample.xml")
Console.Write(doc.InnerXml)
End Sub
The function begins with creating a new XmlTextWriter object in line 䢇 101,
supplying a new file to contain the output. When XML data is routed around
networks or contained in persistent storage, it is normally stripped of any
insignificant white space. This is, of course, to save storage space, but it has
the unfortunate side effect of making the XML text less readable. The default
behavior of the XmlTextWriter class is to not include any of this white space.
This behavior can be changed by setting the Formatting property as shown in
line 䢇
102. This causes XML nodes to be prefixed with indentation to reflect their
Each song record in the XML file (we create one song record in this
example) begins with a song element, as shown in line 䢇 105. The song element
has an attribute attached to it, which is the song format. Like the beginning
and ending WriteStartElement() and WriteEndElement() methods, we use
the WriteStartAttribute() method in line 䢇 106 and the WriteEndAttribute()
method in line 䢇 to write an attribute. The text of the attribute is added with
108
a call to the WriteString() method in line 䢇 107, which outputs the value of
the attribute. Each element for a song (title, artist, and so on) is written
using a combination of WriteStartElement(), WriteString(), and
WriteEndElement() lines.
This function produces the following output.
Imports System
Imports System.Xml
Imports System.Xml.Xsl
Module Module1
4.9 Manipulating XML Data (System.XML) 385
Sub Main()
Dim objXSLT As New XslTransform()
Try
䢇
110 objXSLT.Load("songs.xsl")
䢇
111 objXSLT.Transform("c:\songs.xml", _
"songs.htm")
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
End Module
In line 䢇
110, we load the following XSL file.
<html>
<head>
<title>XslTransform Example</title>
</head>
<body>
<h1>List of Songs</h1>
<table border="1">
<tr>
<td><b>Title</b></td>
<td><b>Artist</b></td>
<td><b>Length</b></td>
<td><b>Category</b></td>
</tr>
<xsl:for-each select="//Songs/song">
<tr>
<td><xsl:value-of select="title"/></td>
<td><xsl:value-of select="artist"/></td>
<td><xsl:value-of select="length"/></td>
<td><xsl:value-of select="category"/></td>
386 Chapter 4 Using the .NET Framework Class Library
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
<Songs>
<song format="MP3">
<title>Eh Cumpari</title>
<artist>Julius LaRosa</artist>
<length>149</length>
<category>Italian-American</category>
</song>
<song format="CD">
<title>Plasticity</title>
<artist>Front Line Assembly</artist>
<length>406</length>
<category>Industrial</category>
</song>
</Songs>
Here’s the HTML that results from using the Transform() method on the
preceding XML file.
<html xmlns:fo="http://www.w3.org/1999/XSL/Format">
<head>
<META http-equiv="Content-Type"
content="text/html; charset=utf-8">
<title>XslTransform Example</title>
</head>
<body>
<h1>List of Songs</h1>
<table border="1">
<tr>
<td>
<b>Title</b>
</td>
<td>
<b>Artist</b>
4.10 Sending Internet E-mail (System.Web.Mail) 387
</td>
<td>
<b>Length</b>
</td>
<td>
<b>Category</b>
</td>
</tr>
<tr>
<td>Eh Cumpari</td>
<td>Julius LaRosa</td>
<td>149</td>
<td>Italian-American</td>
</tr>
<tr>
<td>Plasticity</td>
<td>Front Line Assembly</td>
<td>406</td>
<td>Industrial</td>
</tr>
</table>
</body>
</html>
Property Description
SmtpServer The hostname of the SMTP server to use. If omitted, the IIS 5.0 SMTP
service running on the local machine is used.
Property Description
Property Description
UrlContentBase The base URL to use for all relative links included in the body of
the e-mail message
UrlContentLocation Gets or sets the Content-Location HTTP header for the e-mail
message.
Property Description
Imports System
Imports System.Web.Mail
Module Module1
Sub Main()
䢇
112 Dim objMsg As New MailMessage()
Dim objAttachment As New _
䢇
113 MailAttachment("c:\samples\mountain.jpg")
390 Chapter 4 Using the .NET Framework Class Library
Try
䢇
114 objMsg.To = "[email protected]"
䢇
115 objMsg.From = "[email protected]"
䢇
116 objMsg.Priority = MailPriority.High
objMsg.Subject = _
".NET Framework Mail Demonstration"
䢇
117 objMsg.BodyFormat = MailFormat.Html
objMsg.Body = _
"<h1>.NET Framework Mail Demo</h1>" & _
"This mail contains an attachment"
䢇
118 objMsg.Attachments.Add(objAttachment)
䢇
119 SmtpMail.Send(objMsg)
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
End Module
This sample assumes that we will use the local SMTP server that IIS
5.0 provides. In line 䢇
112 we create a new MailMessage object, which will
the message.
Now we’re ready to set up the message for delivery. Lines 䢇 114 and 䢇
115 show
how to set the e-mail addresses of the recipient and the sender, respectively.
Line 䢇 116 shows setting the high-priority flag of the message so that compatible
e-mail clients can display a special visual indicator to highlight important mes-
sages. This particular message will be sent in HTML format, so we specify
this in line 䢇117, followed by an HTML string that represents the content of
4.11 Summary 391
method of the static class SmtpMail and passing it the objMsg object we
constructed.
4.11 Summary
We covered a lot of ground in this tour of the .NET Framework Class Library.
In spite of all the material presented, we’ve only scratched the surface of this
massive code library. Nonetheless, you learned about several things in this
chapter:
As a result, after working through this chapter you’ve learned how to:
■ Further Reading
393
394 Chapter 5 Building .NET Managed Components for COM+
Byte Byte
Int16 Short
Int32 Integer
Int64 Long
Single Single
Double Double
Object Object
Char Char
String String
Decimal Decimal
Boolean Boolean
Module Module1
e Structure Student
Dim FirstName As String
Dim LastName As String
Dim SSN As String
Dim ClassRank As Integer
End Structure
Sub Main()
f With udtStudent
.FirstName = "Matt"
.LastName = "Crouch"
.SSN = "888-88-1234"
.ClassRank = 2
End With
398 Chapter 5 Building .NET Managed Components for COM+
End Sub
End Module
End Sub
Sub Main()
With udtStudent
.FirstName = "Matt"
.LastName = "Crouch"
.SSN = "888-88-1234"
.ClassRank = 2
End With
ValueTypeDemoFunction(udtStudent)
End Sub
Suppose a system failure occurs at step 4. The source account had the
transfer amount deducted but the amount was not added to the destination
account. Therefore, the money from the source account gets lost. Clearly, this
is not good because the integrity of the database has been damaged.
Each of the account transfer’s steps can be checked for success or failure.
If a failure occurs before all values have been updated, the program needs to
undo the deduction made to the source account. That’s a rollback. If every
step succeeds, the program needs to apply all the changes made to the data-
base. That’s when a commit operation is performed.
Not Supported This is the default setting for new MTS components.
Execution of the component is always outside a
transaction regardless of whether or not a transaction
has been initiated for the component.
System.Console.WriteLine( . . . )
ing manner. (This example shows the usage of Dim to declare an object for a
particular class inside the assembly.)
End Class
The VS.NET IDE adds this code for you for an empty class called
Class1. A .vb file is also generated that contains the class’s code (which
VS.NET should be displaying in the front-most window). Give the class
another name (in the example below, we’ll name it CTaxComponent) by
410 Chapter 5 Building .NET Managed Components for COM+
changing it in the editor and then renaming the class file in the Solution
Explorer to CTaxComponent. The code should now say:
End Class
End Sub
End Function
5.4 Using VB.NET to Develop Managed Components 411
Imports System
Imports SCDemoClasses
Imports Microsoft.VisualBasic
Module Module1
Sub Main()
Dim objTaxComponent As New CTaxComponent()
Dim dblItemPrice As Double = 9.99
Dim dblTotalPrice As Double
With objTaxComponent
.TaxRate = 7
dblTotalPrice = _
.CalculatePriceAfterTax(dblItemPrice)
End With
FormatCurrency(dblTotalPrice))
End Sub
End Module
the ordering and inventory system, showing tables, columns, and foreign key
relationships among columns. (Note that this system is simplified for the pur-
poses of the example.) To run the code samples, you will need to create a SQL
Server database with these specifications, tables, and relationships. Tables 5-3
through 5-6 list the table column names and data types for the four tables
shown in Figure 5-6.
Table 5-3 Column Names and Data Types for the Inventory Table
BinNumber Varchar(255)
SKU Varchar(255)
Quantity Int
414 Chapter 5 Building .NET Managed Components for COM+
Table 5-4 Column Names and Data Types for the Product Table
SKU Varchar(255)
Description Varchar(255)
UnitPrice Decimal
StockingBinNumber Varchar(255)
Table 5-5 Column Names and Data Types for the Orders Table
OrderNumber Varchar(255)
SupplierName Varchar(255)
OrderReceived Bit
Table 5-6 Column Names and Data Types for the OrderDetails Table
OrderNumber Varchar(255)
LineItemNumber Int
SKU Varchar(255)
QuantityReceived Int
Quantity Int
ID Identity
5.6 Building VB.NET Serviced Components 415
LAB 5-1
AN ORDERING AND INVENTORY SYSTEM MADE
WITH SERVICED COMPONENTS
STEP 1. Create a new VB.NET class library project.
a. Open VS.NET and select File➔New➔Project.
b. Highlight Class Library and give the new project the name
“SupermarketSystem”.
b. Organize these functions into a series of classes for your class library. Four
classes will handle the business logic of the different duties that each user
will perform: Product, ReceiveOrder, UpdateInventory, and
CreateOrder. Lab Figure 5-1 shows the classes and the methods of each
class.
Adding a new product to the system, updating inventory, receiving an
order, and creating an order all involve operations on the database tier of
the application. For some of these operations, database updates can occur
in multiple tables. It’s important to keep data integrity across these tables.
You also want to implement security features so the users perform only the
functions that their roles designate. You’ll see this functionality develop as
you code the components.
Lab Figure 5-1 The classes and methods of the Supermarket program
5.6 Building VB.NET Serviced Components 417
Class . . . from the menu. Name the classes as listed above. VS.NET will
“stub out” an empty class definition for each class.
b. Building serviced components requires support from COM+ Component Ser-
vices. The .NET Framework implements this support through classes in the
System.EnterpriseServices namespace. VS.NET doesn’t include this ref-
erence by default, so you’ll need to add it yourself. Select Project➔Add
Reference from the menu and select System.EnterpriseServices from the
list. Click the Select button and then click OK.
c. Now you’re ready to add component functionality. Start by adding the fol-
lowing code for the Product class (Product.vb).
Imports System
Imports System.Reflection
Imports System.EnterpriseServices
Imports System.Data
Imports System.Data.SqlClient
i <Assembly: ApplicationName("Supermarket")>
j <Assembly: ApplicationActivation(ActivationOption.Library)>
k <Assembly: AssemblyKeyFile("KeyFile.snk")>
l Namespace Supermarket
n <ConstructionEnabled( _
[Default]:="Default Construction String"), _
Transaction(TransactionOption.Required)> _
Public Class Product
o Inherits ServicedComponent
p Implements Supermarket.IProduct
End Sub
418 Chapter 5 Building .NET Managed Components for COM+
End Sub
Try
objCnn = New SqlConnection()
objCnn.ConnectionString = _
"Initial Catalog=Supermarket;Data Source=localhost;uid=sa;pwd="
objCnn.Open()
objCmd = objCnn.CreateCommand()
objCmd.CommandText = _
"INSERT INTO Product " & _
"( SKU, Description, UnitPrice, StockingBinNumber ) " & _
"VALUES ( @sku, @description, @unitprice, @stockingbinnumber )"
objCmd.Parameters.Add(objParam)
objParam = New SqlParameter()
With objParam
.ParameterName = "@unitprice"
.SqlDbType = SqlDbType.Decimal
.Direction = ParameterDirection.Input
.Value = UnitPrice
End With
objCmd.Parameters.Add(objParam)
intRowsReturned = _
objCmd.ExecuteNonQuery()
Create = True
r ContextUtil.SetComplete()
Catch E As Exception
Create = False
s ContextUtil.SetAbort()
Finally
objCnn.Close()
End Try
End Function
End Class
End Namespace
Lab Figure 5-2 Specifying a strong name for the assembly using sn.exe
Let’s move on to the main part of the component code. Line l defines
the Supermarket namespace, which will contain all the components for the
Supermarket application. Line m declares an interface you’ll use in the
client application (the ASP.NET Web Form) to call the component. The inter-
face has one function, Create(), which you’ll use to set up a new product
in the Product database table.
The component’s class definition comes next. The code beginning in line
n shows two class-level attributes for the Product class. The first one,
ConstructionEnabled, specifies that the class will be able to use COM+
constructor strings. A constructor string is a string passed into the activa-
tion procedure of the component. This string can be specified by a system
administrator inside the Component Services Console. A constructor string
can contain any information, but typically you’ll use it for passing initializa-
tion information to the component. If no constructor string is given for the
component in the Component Services Console (see Lab Figure 5-3, which
shows the Component Services Console dialog box for setting a constructor
string), a default constructor string is used by specifying it in the attribute
as shown in the continuation of line n. The other class-level attribute speci-
fies how the class will participate in transactions. Use the Transaction
attribute to specify the participation level. In this code, Transaction uses
422 Chapter 5 Building .NET Managed Components for COM+
Imports System
Imports System.Reflection
Imports System.EnterpriseServices
Imports System.Data
Imports System.Data.SqlClient
Namespace Supermarket
424 Chapter 5 Building .NET Managed Components for COM+
<ConstructionEnabled( _
[Default]:="Default Construction String"), _
Transaction(TransactionOption.Required)> _
Public Class CreateOrder
Inherits ServicedComponent
Implements ICreateOrder
End Sub
Try
objCnn = New SqlConnection()
objCnn.ConnectionString = _
"Initial Catalog=Supermarket;Data Source=localhost;uid=sa;pwd="
objCnn.Open()
objCmd = objCnn.CreateCommand()
objCmd.CommandText = _
"INSERT INTO Orders " & _
"( OrderNumber, SupplierName, OrderReceived ) " & _
"VALUES ( @OrderNumber, @SupplierName, @OrderReceived )"
With objParam
.ParameterName = "@OrderNumber"
.SqlDbType = SqlDbType.VarChar
.Direction = ParameterDirection.Input
.Value = OrderNumber
End With
objCmd.Parameters.Add(objParam)
intRowsAffected = objCmd.ExecuteNonQuery()
Create = True
ContextUtil.SetComplete()
Catch E As Exception
Create = False
ContextUtil.SetAbort()
End Try
End Function
Try
objCnn = New SqlConnection()
objCnn.ConnectionString = _
"Initial Catalog=Supermarket;Data Source=localhost;uid=sa;pwd="
objCnn.Open()
objCmd = objCnn.CreateCommand()
objCmd.CommandText = _
"SELECT MAX( LineItemNumber ) " & _
"FROM OrderDetails " & _
"WHERE OrderNumber = @OrderNumber"
objParam = New SqlParameter()
With objParam
.ParameterName = "@OrderNumber"
.SqlDbType = SqlDbType.VarChar
.Direction = ParameterDirection.Input
.Value = OrderNumber
End With
objCmd.Parameters.Add(objParam)
objTemp = objCmd.ExecuteScalar()
If TypeOf objTemp Is DBNull Then
intMaxLineNumber = 1
Else
intMaxLineNumber = CType(objTemp, Integer)
intMaxLineNumber += 1
End If
objCmd = objCnn.CreateCommand()
objCmd.CommandText = _
"INSERT INTO OrderDetails " & _
"( OrderNumber, LineItemNumber, SKU, " & _
"QuantityReceived, Quantity ) VALUES " & _
"( @OrderNumber, @LineNumber, @SKU, " & _
"@QuantityReceived, @Quantity )"
objParam = New SqlParameter()
With objParam
.ParameterName = "@OrderNumber"
.SqlDbType = SqlDbType.VarChar
5.6 Building VB.NET Serviced Components 427
.Direction = ParameterDirection.Input
.Value = OrderNumber
End With
objCmd.Parameters.Add(objParam)
intRowsAffected = objCmd.ExecuteNonQuery()
AddItems = True
428 Chapter 5 Building .NET Managed Components for COM+
ContextUtil.SetComplete()
Catch E As Exception
AddItems = False
ContextUtil.SetAbort()
Finally
objCnn.Close()
End Try
End Function
End Class
End Namespace
Imports System
Imports System.Reflection
Imports System.EnterpriseServices
Imports System.Data
Imports System.Data.SqlClient
Namespace Supermarket
<ConstructionEnabled( _
[Default]:="Default Construction String"), _
Transaction(TransactionOption.Required)> _
Public Class UpdateInventory
Inherits ServicedComponent
Implements IUpdateInventory
End Sub
5.6 Building VB.NET Serviced Components 429
Try
objCnn = New SqlConnection()
objCnn.ConnectionString = _
"Initial Catalog=Supermarket;Data Source=localhost;uid=sa;pwd="
objCnn.Open()
objCmd = objCnn.CreateCommand()
objCmd.CommandText = _
"SELECT StockingBinNumber " & _
"FROM Product WHERE SKU = @SKU"
objTemp = objCmd.ExecuteScalar()
If TypeOf objTemp Is DBNull Then
GetStockingLocation = ""
Else
GetStockingLocation = _
CType(objCmd.ExecuteScalar(), String)
End If
ContextUtil.SetComplete()
Catch E As Exception
ContextUtil.SetAbort()
GetStockingLocation = ""
Finally
objCnn.Close()
End Try
430 Chapter 5 Building .NET Managed Components for COM+
End Function
Try
objCnn = New SqlConnection()
objCnn.ConnectionString = _
"Initial Catalog=Supermarket;Data Source=localhost;uid=sa;pwd="
objCnn.Open()
objCmd = objCnn.CreateCommand()
objCmd.CommandText = _
"SELECT COUNT(*) FROM Inventory " & _
"WHERE SKU = @SKU AND " & _
"BinNumber = @StockingBinNumber"
objParam = New SqlParameter()
With objParam
.ParameterName = "@SKU"
.SqlDbType = SqlDbType.VarChar
.Direction = ParameterDirection.Input
.Value = SKU
End With
objCmd.Parameters.Add(objParam)
objTemp = objCmd.ExecuteScalar()
If TypeOf objTemp Is DBNull Then
5.6 Building VB.NET Serviced Components 431
intRowCount = 0
Else
intRowCount = CType(objTemp, Integer)
End If
ContextUtil.SetComplete()
Catch E As Exception
InventoryRecExists = False
ContextUtil.SetAbort()
Finally
objCnn.Close()
End Try
End Function
Try
objCnn = New SqlConnection()
objCnn.ConnectionString = _
"Initial Catalog=Supermarket;Data Source=localhost;uid=sa;pwd="
objCnn.Open()
objCmd = objCnn.CreateCommand()
With objParam
.ParameterName = "@Quantity"
.SqlDbType = SqlDbType.Int
.Direction = ParameterDirection.Input
.Value = Quantity
End With
objCmd.Parameters.Add(objParam)
intRowCount = objCmd.ExecuteNonQuery()
ContextUtil.SetComplete()
Catch E As Exception
ContextUtil.SetAbort()
Finally
objCnn.Close()
End Try
End Sub
Try
objCnn = New SqlConnection()
objCnn.ConnectionString = _
"Initial Catalog=Supermarket;Data Source=localhost;uid=sa;pwd="
objCnn.Open()
objCmd = objCnn.CreateCommand()
objCmd.CommandText = _
"INSERT INTO Inventory " & _
"( BinNumber, SKU, Quantity ) VALUES " & _
"( @BinNumber, @SKU, @Quantity )"
intRowCount = objCmd.ExecuteNonQuery()
ContextUtil.SetComplete()
434 Chapter 5 Building .NET Managed Components for COM+
Catch E As Exception
ContextUtil.SetAbort()
Finally
objCnn.Close()
End Try
End Sub
Try
If InventoryRecExists(SKU, BinNumber) Then
UpdateInventoryRecord( _
BinNumber, _
SKU, _
Quantity)
Else
InsertInventoryRecord( _
BinNumber, _
SKU, _
Quantity)
End If
Update = True
ContextUtil.SetComplete()
Catch E As Exception
Update = False
ContextUtil.SetAbort()
End Try
End Function
End Class
End Namespace
5.6 Building VB.NET Serviced Components 435
Imports System
Imports System.Reflection
Imports System.EnterpriseServices
Imports System.Data
Imports System.Data.SqlClient
Namespace Supermarket
<ConstructionEnabled( _
[Default]:="Default Construction String"), _
Transaction(TransactionOption.Required)> _
Public Class ReceiveOrder
Inherits ServicedComponent
Implements IReceiveOrder
End Sub
Try
objCnn = New SqlConnection()
436 Chapter 5 Building .NET Managed Components for COM+
objCnn.ConnectionString = _
"Initial Catalog=Supermarket;Data Source=localhost;uid=sa;pwd="
objCnn.Open()
objCmd = objCnn.CreateCommand()
objCmd.CommandText = _
"UPDATE OrderDetails " & _
"SET QuantityReceived = " & _
"QuantityReceived + @QuantityReceived " & _
"WHERE OrderNumber = " & _
"@OrderNumber AND LineItemNumber = @LineNumber"
intRowsAffected = objCmd.ExecuteNonQuery()
ContextUtil.SetComplete()
Catch E As Exception
5.6 Building VB.NET Serviced Components 437
ContextUtil.SetAbort()
Finally
objCnn.Close()
End Try
End Sub
Try
objCmd.CommandText = _
"SELECT MAX(LineItemNumber), " & _
"SKU FROM OrderDetails od, Orders o " & _
"WHERE od.OrderNumber = @OrderNumber AND " & _
"o.OrderReceived = 0 AND " & _
"o.OrderNumber = od.OrderNumber GROUP BY SKU"
objSQLDr = objCmd.ExecuteReader()
objSQLDr.Read()
438 Chapter 5 Building .NET Managed Components for COM+
ContextUtil.SetComplete()
objSQLDr.Close()
Catch E As Exception
GetNextLineItem = -1
SKU = ""
ContextUtil.SetAbort()
Finally
objCnn.Close()
End Try
End Function
Try
UpdateOrderDeatils(OrderNumber, _
LineNumber, _
QuantityReceived)
If objInvUpdate.Update(strBinNumber, _
SKU, QuantityReceived) Then
Receive = True
ContextUtil.SetComplete()
Else
Receive = False
ContextUtil.SetAbort()
End If
Catch E As Exception
Receive = False
ContextUtil.SetAbort()
End Try
End Function
End Class
End Namespace
e. Now that you’ve entered the main code for the Supermarket COM+ appli-
cation, it’s time to compile it. Choose Build➔Build Solution from the menu
to create the assembly file. In the next step, you’ll create a project that
references that assembly.
Lcs5-5.aspx, Lcs5-5.aspx.vb
Lcs5-6.aspx, Lcs5-6.aspx.vb
Lcs5-7.aspx, Lcs5-7.aspx.vb
Lcs5-8.aspx, Lcs5-8.aspx.vb
These Web Forms will test the different components and their
functionality.
440 Chapter 5 Building .NET Managed Components for COM+
<form id="Form1"
method="post"
runat="server">
<p>SKU:
<asp:TextBox
id=txtSKU
runat="server">
</asp:TextBox></p>
<p>Description:
<asp:TextBox
id=txtDescription
runat="server">
</asp:TextBox></p>
<p>Unit Price:
<asp:TextBox
id=txtUnitPrice
runat="server">
</asp:TextBox></p>
<p>Stocking Location:
<asp:TextBox
id=txtStockLoc
runat="server">
</asp:TextBox></p>
5.6 Building VB.NET Serviced Components 441
<p>
<asp:Button
id=cmdAddProduct
runat="server"
Text="Add Product">
</asp:Button>
<asp:CompareValidator
id=CompareValidator1
runat="server"
ErrorMessage="You must enter a price (number)"
Type="Double"
ControlToValidate="txtUnitPrice"
Operator="DataTypeCheck">
</asp:CompareValidator></p>
</form>
</body>
</html>
ASP.NET Web Forms can run inside the context of a COM+ Component Services trans-
action. In this ASP.NET Web application, the Web Forms call the serviced components
in response to events raised by Web Controls (buttons clicked and so on). Since the
ASP.NET Web Form is the initiator of calls made into a COM+ application, the Web Form
is considered the root of the transaction. It has the “final vote” as to whether or not the
transaction succeeds or fails.
In order to designate that the Web Form will participate in a transaction, you need to
set the Transaction page attribute (highlighted in bold above). This code specifies the
level as RequiresNew. This means that the page will always begin a new transaction for
any units of work executed during the lifetime of the page.
Here is the code-behind file, Lcs5-5.aspx.vb, for the preceding Web Form.
Imports SupermarketSystem.Supermarket
Imports System.EnterpriseServices
Imports System.Reflection
Imports System.ComponentModel
System.Web.UI.WebControls.TextBox
Protected WithEvents txtDescription As _
System.Web.UI.WebControls.TextBox
Protected WithEvents txtUnitPrice As _
System.Web.UI.WebControls.TextBox
Protected WithEvents txtStockLoc As _
System.Web.UI.WebControls.TextBox
Protected WithEvents CompareValidator1 As_
System.Web.UI.WebControls.CompareValidator
End Sub
If bln Then
ContextUtil.SetComplete()
Else
ContextUtil.SetAbort()
End If
End Sub
End Class
The Click event for the cmdAddProduct button calls the Product component to add a
new product to the database. The code creates a new Product object and obtains a refer-
ence to the IProduct interface. It then calls the Create() method. If the call was success-
ful (returned True), SetComplete() is called to indicate to COM+ that this unit of work in
the transaction was successful. If not, SetAbort()stops the transaction immediately.
5.6 Building VB.NET Serviced Components 443
<form id="Form1"
method="post"
runat="server">
<p>Order number:
<asp:TextBox
id=txtOrderNumber
runat="server">
</asp:TextBox></p>
<p>Supplier Name:
<asp:TextBox
id=txtSupplierName
runat="server">
</asp:TextBox></p>
<p>
<asp:Button
id=cmdCreateOrder
runat="server"
Text="Add">
</asp:Button></p>
</form>
</body>
</html>
444 Chapter 5 Building .NET Managed Components for COM+
Imports System.EnterpriseServices
Imports System.Reflection
Imports SupermarketSystem.Supermarket
End Sub
If objCreateOrder.Create(txtOrderNumber.Text, _
txtSupplierName.Text) Then
ContextUtil.SetComplete()
Else
ContextUtil.SetAbort()
End If
End Sub
End Class
Similar to the test Web Form for the Product component, this code creates a
CreateOrder object using New. The program calls the Create() method and then
calls SetComplete() or SetAbort() upon success or failure, respectively.
5.6 Building VB.NET Serviced Components 445
<form id="Form1"
method="post"
runat="server">
<p>Order Number:
<asp:TextBox
id=txtOrderNumber
runat="server">
</asp:TextBox></p>
<p>SKU:
<asp:TextBox
id=txtSKU
runat="server">
</asp:TextBox></p>
<p>Quantity:
<asp:TextBox
id=txtQuantity
runat="server">
</asp:TextBox></p>
<p>
<asp:CompareValidator
id=CompareValidator1
runat="server"
ErrorMessage="Quantity must be a whole number!"
446 Chapter 5 Building .NET Managed Components for COM+
ControlToValidate="txtQuantity"
Type="Integer"
Operator="DataTypeCheck">
</asp:CompareValidator></p>
<p>
<asp:Button
id=cmdAddToOrder
runat="server"
Text="Add To Order">
</asp:Button></p>
</form>
</body>
</html>
Imports System.EnterpriseServices
Imports System.Reflection
Imports SupermarketSystem.Supermarket
End Sub
ByVal e As System.EventArgs) _
Handles cmdAddToOrder.Click
If objCreateOrder.AddItems(txtOrderNumber.Text, _
txtSKU.Text, CInt(txtQuantity.Text)) Then
ContextUtil.SetComplete()
Else
ContextUtil.SetAbort()
End If
End Sub
End Class
<form id="Form1"
method="post"
runat="server">
<asp:TextBox
id=txtOrderToReceive
runat="server">
</asp:TextBox>
448 Chapter 5 Building .NET Managed Components for COM+
<asp:Button
id=cmdGetOrder
runat="server"
Text="Get Order">
</asp:Button></p>
<p>
<asp:Panel
id=Panel1
runat="server"
Width="399px"
Height="144px"
Enabled="False">
<p>
<asp:Label
id=lblOrderNumber
runat="server"
Width="184px"
Height="19px">
</asp:Label></p>
<p></p><p>
<asp:Label
id=lblReceiveSKU
runat="server"
Width="183px"
Height="19px">
</asp:Label></p>
<p>
<asp:Label
id=lblLineNumberReceive
runat="server"
Width="188px"
Height="19px">
</asp:Label></p>
<p>
<asp:Label
id=Label1
runat="server"
Width="128px"
5.6 Building VB.NET Serviced Components 449
Height="19px">
Quantity To Receive:
</asp:Label>
<asp:TextBox
id=txtQuantityToReceive
runat="server">
</asp:TextBox>
<asp:Button
id=cmdReceive
runat="server"
Text="Receive">
</asp:Button>
</asp:Panel></p>
</form>
</body>
</html>
This Web Form wraps page elements in a Panel Web Control. The panel is initially dis-
abled to avoid displaying or enabling the order information until a valid order number is
keyed into the Web Form. Here’s the code-behind file (Lcs5-8.aspx.vb).
Imports System.EnterpriseServices
Imports System.Reflection
Imports SupermarketSystem.Supermarket
End Sub
intLineNumber = _
objReceiveOrder.GetNextLineItem( _
txtOrderToReceive.Text, _
strSKUToReceive)
If objReceiveOrder.Receive( _
ViewState("OrderToReceive"), _
ViewState("SKUToReceive"), _
ViewState("LineNumber"), _
CInt(txtQuantityToReceive.Text)) Then
ContextUtil.SetComplete()
Else
ContextUtil.SetAbort()
End If
End Sub
End Class
This form uses two Button Web Controls, cmdGetOrder and cmdReceive. This makes
a two-step process for receiving items for an order. First, the event handler for
cmdGetOrder calls GetNextLineItem(), taking as input the order number the user
entered. If there is a line item to receive for the order, the program displays the line-item
information in the Label Web Control contained within the Panel Web Control. The Panel
Web Control is then enabled, making the information visible to the user. The line-item
information is also copied to the ViewState StateBag because the program will need this
information on the subsequent post-back that will occur when items are received.
The event handler for cmdReceive calls the Receive() method. The Receive()
method updates the OrderDetails table as well as the Inventory table. Using a trans-
action in this situation helps point out any discrepancies between quantities in inventory
and quantities ordered. The Receive() method returns True on success and False on
failure, and the program makes an appropriate call to either SetComplete() or
SetAbort() as a result.
d. Now you need to add a reference to the assembly DLL for the components.
Right-click the References folder in the Solution Explorer, select Add Refer-
ence, browse to the compiled DLL, and select it. Click OK to add the refer-
ence to the selected assembly.
a. Now you’re ready to build the application. Select Build➔Build Solution from
the menu. Select a start page for the application (like Lcs5-5.aspx) by
right-clicking on a Web Form in the Solution Explorer and selecting Set As
Start Page from the menu.
c. Test the application by entering some products. Then create a new order,
add some items to the order, and run an order-receive process. This should
complete a full test.
b. Now you can set up the user roles (Receiving Clerks, Supervisors, and
Suppliers) inside the COM+ Component Services Console. For each role,
right-click the Roles folder under the Supermarket application (see Lab
Figure 5-6), select New➔Role from the menu, and assign a name for
the role.
c. Assign users to each role by right-clicking the User folder under the role and
selecting New➔User from the menu. Pick a Windows account name(s) or
group(s) to assign to the role. Lab Figure 5-7 shows users assigned to the
various roles of the Supermarket application.
Lab Figure 5-4 The Supermarket application within the COM+ Component
Services Console
Lab Figure 5-5 Enabling role-based security for the Supermarket application
context of a specific user. Normally, when you run an application from the
console, Windows uses the security context of the currently logged-on user.
By using the runas command, you can run an executable program using any
account name (provided, of course, you have the password of that account!).
Here’s a simple console application you can run to test role-based security.
Imports System
Imports SupermarketSystem.Supermarket
Imports System.EnterpriseServices
Module Module1
5.6 Building VB.NET Serviced Components 455
Sub Main()
Dim objCreateOrder As ICreateOrder
End Sub
End Module
456 Chapter 5 Building .NET Managed Components for COM+
Compile this small testing console application and run it using the runas
command below:
5.7 Summary
Let’s recap what you’ve learned in this chapter about writing .NET managed
components.
■ Managed code is application code that executes within the .NET
Framework.
■ Runtime systems enable application programs you write to access oper-
ating system–level services. Several different runtime environments are
available for various systems. A runtime environment is usually specific
to a programming language.
■ Intermediate languages provide an additional layer of abstraction over
another existing runtime environment. The goal of intermediate lan-
guages is to provide portability of application code across operating sys-
tems. The intermediate language for the .NET Framework is called the
Microsoft Intermediate Language (MSIL).
■ The runtime environment for the .NET Framework is called the Com-
mon Language Runtime (CLR). It supports self-describing code
through metadata, a specification for the Common Type System (CTS),
just-in-time compilation of code, and the concept of assembly mani-
fests, which describe a packaged set of components, programs, files,
and other dependencies an application needs in order to function
properly.
■ COM is a programming model invented by Microsoft that allows for
binary-level software component reuse.
■ Transactions provide consistency and data integrity to a software sys-
tem. By checking the success or failure of smaller atomic tasks that
make up the transaction, you can decide whether the transaction
should succeed as a whole.
■ Windows provides programmers with easy transaction support for their
applications through COM+ Component Services. COM+ Component
Services provides transaction support, object pooling, and component-
level runtime security.
■ Components are simply classes at their most basic level. Components
have properties and methods, which roughly correspond to member
functions and member variables, respectively.
■ Serviced components are classes that take advantage of COM+ Com-
ponent Services. Security is provided by grouping users into roles and
assigning those roles to components.
458 Chapter 5 Building .NET Managed Components for COM+
Web Services form the most important piece of the .NET Framework. Web
Services solve the problems that arise from the design and implementation of
distributed software systems. For the first time, software developers can use
the Internet as an infrastructure for building applications. Data can flow freely
through this infrastructure, unrestrained by incompatibilities of protocols and
transport mechanisms. Much as component-based software systems revolu-
tionized the way desktop and server-side applications are developed, so
do Web Services make these component-based systems truly distributed.
Also, Web Services can be used in any operating system or platform environ-
ment, which makes interoperability with other software easy.
This chapter covers the following topics:
■ The problems associated with distributed Web application develop-
ment and how Web Services can solve these problems
■ The architecture of Web Services as they relate to ASP.NET
■ The Web Service Description Language (WSDL)
■ Wire formats (the communication protocols used by Web Services)
■ Static and dynamic discovery of Web Services
■ Creation of Web Services, including the use of transactions and state
management
459
460 Chapter 6 Building Web Services
the desktop computer’s hard drive or, in the case of time-sharing mainframe
systems, the software ran on that central computer and displayed information
through a terminal console. Each application was usually suited for a particu-
lar task, for example, word processing or banking, and had little or no facilities
to access external data outside the scope of what the application was designed
to handle. And as these applications became more complex and grew in size,
so did the effort increase on the part of software developers making these
applications.
Another problem associated with these monolithic applications was
incompatibilities between network mediums and protocols. Many of these
systems, if they were networked at all, used proprietary network mediums
and protocols that were generally incompatible with other networks. Hopes
of sharing data across these systems were thwarted due to complex interfac-
ing code that would need to be developed in order for communication to
take place.
Switching these software systems to component-based architecture solved
many of the problems of upgrading, scaling, and interfacing. Many software
vendors have been quite successful selling just components to other software
developers who make complete applications from them. Components make
software development easier because code doesn’t need to be written from
scratch, it can easily be upgraded, and it provides a logical structure that
makes complex, enterprise-wide applications more understandable.
However, component-based software systems are not without their archi-
tectural limitations. Many component-based architectures are designed to
work within the confines of a single computer, limiting their ability to operate
over a network. If distributed capabilities exist, they are typically retrofitted
onto the current design, as is the case with COM/DCOM (Distributed COM).
Furthermore, the communication protocol used for sending remote proce-
dure calls (RPCs) over the network wire is proprietary and uses network
communication channels that are normally not accessible through firewall
systems due to security reasons. Web Services aim to solve these problems
and make distributed component-based computing practical and usable for
all participants.
site exposed that lookup functionality as a Web Service, it would return only
the relevant data (the stock price). You could query the service programmati-
cally and use the return value in a manner appropriate for the device you used
to access the service.
The second line denotes that you wish to import the required class
libraries that enable Web Services to work. These classes are contained in the
System.Web.Services namespace.
End Class
The implementation of this method is quite simple and not really impor-
tant, but the declaration of the member function is key. The class starts by
inheriting from System.Web.Services.WebService, which is a class that con-
tains support for Web Services. It also exposes ASP.NET intrinsic objects,
such as those used for session and state management. The member function
HelloWorld() contains an attribute class called <WebMethod>. This specifies
that the member function will be publicly exposed through the Web Service.
This attribute class also allows you to define an optional description for the
Web method and specify additional parameters that can alter the behavior of
the Web method. We’ll discuss the specifics shortly.
xmlns:soap=http://schemas.xmlsoap.org/wsdl/soap/
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:s0="http://tempuri.org/"
targetNamespace="http://tempuri.org/"
xmlns="http://schemas.xmlsoap.org/wsdl/">
<types>
<s:schema attributeFormDefault="qualified"
elementFormDefault="qualified"
targetNamespace="http://tempuri.org/">
<s:element name="HelloWorld">
<s:complexType />
</s:element>
<s:element name="HelloWorldResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1"
maxOccurs="1"
name="HelloWorldResult"
nillable="true"
type="s:string" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="string"
nillable="true"
type="s:string" />
</s:schema>
</types>
<message name="HelloWorldSoapIn">
<part name="parameters" element="s0:HelloWorld" />
</message>
<message name="HelloWorldSoapOut">
<part name="parameters" element="s0:HelloWorldResponse" />
</message>
<message name="HelloWorldHttpGetIn" />
<message name="HelloWorldHttpGetOut">
<part name="Body" element="s0:string" />
</message>
<message name="HelloWorldHttpPostIn" />
<message name="HelloWorldHttpPostOut">
<part name="Body" element="s0:string" />
</message>
<portType name="PalindromeTestSoap">
6.3 Web Service Description Language 465
<operation name="HelloWorld">
<input message="s0:HelloWorldSoapIn" />
<output message="s0:HelloWorldSoapOut" />
</operation>
</portType>
<portType name="PalindromeTestHttpGet">
<operation name="HelloWorld">
<input message="s0:HelloWorldHttpGetIn" />
<output message="s0:HelloWorldHttpGetOut" />
</operation>
</portType>
<portType name="PalindromeTestHttpPost">
<operation name="HelloWorld">
<input message="s0:HelloWorldHttpPostIn" />
<output message="s0:HelloWorldHttpPostOut" />
</operation>
</portType>
<binding name="PalindromeTestSoap"
type="s0:PalindromeTestSoap">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="HelloWorld">
<soap:operation
soapAction="http://tempuri.org/HelloWorld"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<binding name="PalindromeTestHttpGet"
type="s0:PalindromeTestHttpGet">
<http:binding verb="GET" />
<operation name="HelloWorld">
<http:operation location="/HelloWorld" />
<input>
<http:urlEncoded />
</input>
<output>
466 Chapter 6 Building Web Services
http://yourserver/YourWebService.asmx?WSDL
6.4 Web Service Wire Formats 467
http://yourserver/scriptname.aspx?param1=value1¶m2=value2
Calling a Web Service using this method requires a URL like the follow-
ing example:
http://yourserver/YourWebService.asmx/YourWebMethod?Param1=Value1
468 Chapter 6 Building Web Services
After the Web Service has finished performing its work, the results are
returned to the client using the following format. (This particular Web
method returned a Boolean value equal to True.)
The client then parses this XML result and passes it on to whatever pro-
gram called the Web Service for further processing.
Param1=value1
This is the actual “chunk” of data sent by the client over the network
socket. Normally, the HTTP POST method is used to send the values a user
has entered into an HTML form along with the request. In the case of a
Web Service call, the name–value pair mechanism normally used to send
input element values is used to send the Web method parameter values.
The response back from the Web Service is in the same format as for the
HTTP GET.
restricted by the types of information they can send to Web Services. Since
they send only name–value pairs of information, you can’t easily extend the
types of information you can send with the request. Plus, the name–value pair
approach isn’t structured, so that makes processing of the request more diffi-
cult for the Web Service.
SOAP solves these problems by providing a mechanism for passing Web
Service request data in a structured and expandable fashion. You can use a
standardized XML schema for passing request data as well as receiving
response data.
SOAP is a fairly complex topic, so we’ll just touch on the basics of the pro-
tocol. Whenever you use VS.NET to build systems that use Web Services, the
IDE configures your Web Services and clients to use SOAP for all communi-
cations by default. Keeping with the previous examples, here’s how a request
for a Web method looks when using SOAP.
The XML in boldface shows how the Web method is called. An XML
element called YourWebMethod contains subelements that specify the
parameters and their values. The response received from the Web Service
is also encoded using SOAP, as shown below.
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<soap:Envelope
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
xmlns:xsd=http://www.w3.org/2001/XMLSchema
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<YourWebMethodResponse xmlns="http://tempuri.org/">
<YourWebMethodResult>True</YourWebMethodResult>
</YourWebMethodResponse>
</soap:Body>
</soap:Envelope>
SOAP returns the value from the Web method as shown in boldface. The
XML element YourWebMethod shows a return value of True.
xmlns:disco="http://schemas.xmlsoap.org/disco"
xmlns:scl="http://schemas.xmlsoap.org/disco/scl">
<scl:contractRef
ref="http://MyWebServer/MyWebService.asmx?WSDL"/>
<disco:discoveryRef
ref="SomeFolder/OtherWebService.disco"/>
</disco:discovery>
LAB 6-1
THE PALINDROME WEB SERVICE
The first Web Service you’ll create will check whether a supplied word or phrase is a
palindrome (a special word or phrase that, when the letters are reversed, spells the origi-
nal word, for example, “Anna”). This Web Service will take an input string that contains
the word or phrase and return a Boolean True value if the string is a palindrome.
b. Since you renamed some files, you need to adjust the default code slightly.
The change occurs in the palindrome.asmx file. VS.NET defaults the view
of this file to the Design View, but you need to modify the file directly in the
Source Code Editor. To open the file with the Source Code Editor, right-click
the palindrome.asmx file and select Open With . . . . The Open With dialog
appears with different program selections (see Lab Figure 6-1).
c. Select the Source Code (Text) Editor option from the list and click the Open
button. The source file appears and contains the following code (spacing
has been added here for readability):
This .asmx file is all that’s required for your Web Service. VS.NET config-
ures it with the Codebehind directive to separate the Web Service code
from this file.
d. Because of the file name change, you need to edit the value for the Class
directive. Change it to read “Palindrome.Palindrome”.
Lab Figure 6-2 Stub code for the Palindrome Web Service
6.6 Creating a Simple Web Service 475
d. It’s time to add a Web method of your own. This Web method is called
IsPalindrome(). Enter the following code.
End Function
This code first removes any spaces from the word or phrase and converts
the string to all uppercase letters. Removal of spaces is necessary so they
won’t be considered as part of the palindrome. (A more complete implemen-
tation would consider other characters as well, such as punctuation.) Con-
version to uppercase letters ensures that case-sensitivity will not be an
issue when comparing the reversed string with the original. The VB.NET
StrReverse() function reverses the candidate string and compares it to
the original passed as the parameter to the function. If the values match,
the string is a palindrome, and True is returned by the Web method.
e. After you’ve entered all the code, save the project.
Lab Figure 6-5 The XML results of calling the IsPalindrome() Web method
Congratulations! You’ve just built a complete, working Web Service. Of course, Web Ser-
vices for production systems are considerably more complex than this one, but the basic
process of construction remains the same.
What does a proxy class look like? To illustrate, let’s examine the proxy
class for the Palindrome Web Service.
Option Explicit On
Imports System
Imports System.Diagnostics
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Xml.Serialization
Namespace MattsWebServices
<System.Web.Services.WebServiceBindingAttribute( _
Name:="PalindromeSoap", [Namespace]:="http://tempuri.org/")> _
<System.Diagnostics.DebuggerStepThroughAttribute()> _
Public Sub New()
MyBase.New()
Me.Url = "http://localhost/palindrome/Palindrome.asmx"
End Sub
<System.Diagnostics.DebuggerStepThroughAttribute(), _
System.Web.Services.Protocols.SoapDocumentMethodAttribute( _
"http://tempuri.org/IsPalindrome", _
Use:=System.Web.Services.Description.SoapBindingUse.Literal, _
ParameterStyle:= _
480 Chapter 6 Building Web Services
System.Web.Services.Protocols.SoapParameterStyle.Wrapped)>
End Function
<System.Diagnostics.DebuggerStepThroughAttribute()> _
Public Function BeginIsPalindrome( _
ByVal TestString As String, _
ByVal callback As System.AsyncCallback, _
ByVal asyncState As Object) As _
System.IasyncResult
Return Me.BeginInvoke( _
"IsPalindrome", New Object() {TestString}, _
callback, asyncState)
End Function
<System.Diagnostics.DebuggerStepThroughAttribute()> _
Public Function EndIsPalindrome( _
ByVal asyncResult As System.IAsyncResult) As _
Boolean
Although the code for the proxy class looks considerably complex, you
don’t need to worry about it because VS.NET and the .NET Framework gen-
erate this code for you. The .NET Framework contains a utility that parses the
WSDL for a Web Service and generates all the proxy class code based on the
information contained in the WSDL.
LAB 6-2
A CONSOLE APPLICATION FOR THE
PALINDROME WEB SERVICE
c. When you have successfully located the Palindrome Web Service, enter its
location as a URL and click the Add Reference button at the bottom of the
Add Web Reference window.
f If clsPalindrome.IsPalindrome(strTestString) Then
Console.WriteLine("{0} is a palindrome!", _
strTestString)
Else
Console.WriteLine("{0} is NOT a palindrome!", _
strTestString)
End If
Imports System.Web.Services
End Function
CInt(Session("MyCounter")) + 1
End If
IncrementSessionCount = CInt(Session("MyCounter"))
End Function
End Class
<%@ WebService
Language="vb"
Class="SomeWebService" %>
Imports System
Imports System.Web.Services
Imports System.EnterpriseServices
<WebMethod(TransactionOption:=TransactionOption.RequiresNew)> _
Public Sub SomeMethod()
End Sub
End Class
1. You must include the Imports statements shown in the .asmx file
above.
2. The transaction option must be set for Web methods that will execute
as part of a transaction. This example uses the TransactionOption.
RequiresNew option, which will begin a new transaction. In other
words, the Web method will act as the root of the transaction. When
the code for the Web method finishes executing, it will automatically
commit or roll back the transaction based on whether or not an excep-
tion inside the Web method was thrown.
LAB 6-3
AN ENHANCED ORDERING AND INVENTORY SYSTEM
STEP 1. Start VS.NET.
Imports System
Imports SupermarketSystem.Supermarket
488 Chapter 6 Building Web Services
Imports System.Web.Services
Imports System.EnterpriseServices
<WebMethod(True, TransactionOption.RequiresNew)> _
Public Sub AddAProduct(ByVal SKU As String, _
ByVal Description As String, _
ByVal UnitPrice As Decimal, _
ByVal StockBinNumber As String)
Dim objProduct As IProduct
Dim bln As Boolean
Try
objProduct = New Product()
bln = objProduct.Create(SKU, _
Description, _
CDec(UnitPrice), _
StockBinNumber)
If bln Then
If Session("MyCounter") Is Nothing Then
Session("MyCounter") = 1
Else
Session("MyCounter") = _
CInt(Session("MyCounter")) + 1
End If
End If
Catch e As Exception
'* handle error here
End Try
End Sub
<WebMethod(True)> _
Public Function GetNumProductAdds() As Integer
If Session("MyCounter") Is Nothing Then
GetNumProductAdds = 0
Else
GetNumProductAdds = CInt(Session("MyCounter"))
End If
End Function
End Class
6.12 Summary 489
6.12 Summary
In this chapter, you learned several things about .NET Web Services.
■ Web Services are the most important piece in the .NET Framework.
They are designed to facilitate the construction of truly distributed and
interoperable software systems.
■ Web Services use open Internet standards for communication, such as
XML and HTTP.
■ Web Services allow you to separate content from presentation. In a
sense, they allow programmatic access to functionality that would nor-
mally be tied to a Web page.
■ The Simple Object Access Protocol (SOAP) is the protocol used to
communicate with a Web Service. It is a standards-based protocol that
uses XML and is transported over HTTP.
490 Chapter 6 Building Web Services
■ Web Services can use the HTTP GET and POST communication meth-
ods in place of SOAP. However, SOAP is the protocol of choice since it
allows the use of complex data types and VS.NET will automatically
SOAP-enable any Web Service you create with it.
■ A Web Service is a class that derives from System.Web.Services.
WebService. You expose member functions in the class as callable
Web methods by using the WebMethod() attribute.
■ The Web Service Description Language (WSDL) is an XML schema
that a Web Service client uses to determine how to call the Web Ser-
vice. From the Web Service’s WSDL file, you can determine available
methods, parameters, and data types.
■ Web Service discovery is the process of letting a potential client know
what Web Services are available on a particular server. A special XML
file called a .disco file gives this information.
■ Static discovery allows you to explicitly define the location of individual
Web Services. It also allows you to group together the locations of Web
Services into a logical unit.
■ Dynamic discovery allows for an automatic way to discover multiple
Web Services. It automatically identifies every Web Service in a partic-
ular directory. You also have the option to exclude certain subfolders
from the discovery process.
■ Web Services can be called inside any .NET managed code. Calls to
Web Services can be made through proxy classes. This allows you to
treat a Web Service just like a normal class in the program code, mak-
ing the coding process more intuitive.
■ Web Services can use ASP.NET state management using the Session
and Application objects.
■ Web Services can participate in a COM+ Component Services transac-
tion by specifying a TransactionOption in the WebMethod() attribute.
Accessing Data
with ADO.NET
491
492 Chapter 7 Accessing Data with ADO.NET
For these reasons, ODBC is rarely used now for programming with databases.
With the introduction of COM and its language-independent architecture,
a new version of data-access technology was required to take advantage of
COM’s architecture. This new technology is known as OLE-DB (OLE stands
for Object Linking and Embedding, which is the forerunner technology of
COM). OLE-DB communicates with a data provider, which is software that
provides access to the physical data. The OLE-DB package that Microsoft dis-
tributes comes with a data provider for ODBC drivers. This enables program-
mers to write OLE-DB code, which communicates with ODBC data sources,
using the COM methodology. In addition to providing access to ODBC data
sources, OLE-DB providers are available for specific DBMSs. This provides
the fastest access to the data. OLE-DB can even talk to data providers for
nonrelational database data as well, such as flat files or stores of e-mail mes-
sages. Whatever the data source, the programmer’s interface remains the
same.
7.1.5 ADO
ADO provides an easier programming interface to data sources while still
being efficient. The object model of OLE-DB is complicated, so ADO serves
as another code “wrapper” around OLE-DB to make programming easier.
ADO unifies the functionality of previous data-access methods and reduces
the number of objects in the programming interface as well. In the past
Microsoft often referred to ADO technology as “Universal Data Access,” and
this is the company’s strategy for the future of access to any kind of data, rela-
tional or not.
normally blocked by firewalls. This puts limitations on the ways you can archi-
tect Web application systems. It hampered interoperability, which is a key
strategy behind the .NET platform.
In ADO.NET, XML and HTTP are used to work around the interoper-
ability problem. Data records are encoded and transported using XML and
HTTP. XML is the format of choice for representing structured and hierarchi-
cal data, and HTTP can easily be ferried across firewalls along with normal
Web traffic. XML is an open standard, so even non-Microsoft platforms can
act as receiving points for data that originated from ADO.NET. Likewise, data
records can originate from sources other than ADO.NET as long as the XML
schema rules are followed.
High Performance
ADO.NET gets a dramatic performance boost over any previous data-access
method. This speed increase is accounted for by the lightweight nature of the
XML/HTTP transport and the use of disconnected data. Unlike traditional
client/server models of data access that maintain an open data connection for
the duration that commands are executed, ADO.NET operates on data
retrieved from the server and cached locally on the client computer. After
retrieving that initial set of data, any updates made to the data happen locally.
After updates are complete, the modified data is marshaled back to the server
in one step.
TIP: You need to have SQL Ser ver (7.0 or 2000) installed
for this example and the ADO.NET examples following this
one. We will be using the example pubs database that is
present by default on most SQL Ser ver installations. Since
some ADO.NET classes are abstract ones (they must be
inherited by a .NET Managed Data Provider), we will be
mostly focusing on the SQL Ser ver .NET Managed Data
Provider and classes in the System.Data.SqlClient name-
space in our discussions of .NET Managed Data Providers.
Property Description
RecordsAffected Specifies the number of rows affected by the execution of the SQL
statement
7.4 Displaying Database Data 499
this same concept by allowing the .NET Managed Data Provider code to
implement the various interfaces. This way, when you write ADO.NET
application code, you don’t refer to specific implemented classes of the
.NET Managed Data Provider—you simply call methods and properties of
the interface class. For example, the SQL Server .NET Managed Data
Provider provides an implementation of the IDataReader interface with a
class in the System.Data.SqlClient namespace called SqlDataReader.
To further illustrate and to see your first ADO.NET sample in action, let’s
look at a piece of code that queries the authors table in the pubs SQL Server
database.
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports Microsoft.VisualBasic
Module Module1
Sub Main()
Try
e Dim objCnn As New SqlConnection( _
"Initial Catalog=pubs;" & _
"Data Source=localhost;uid=sa;pwd=")
500 Chapter 7 Accessing Data with ADO.NET
f objCnn.Open()
h objCmd.CommandText = _
"SELECT au_id, au_lname, au_fname FROM Authors"
j Do While objReader.Read()
Console.WriteLine("{0}" & _
ControlChars.Tab & "{1} {2}", _
k objReader.GetString(0),
objReader.GetString(1), _
objReader.GetString(2))
Loop
l objCnn.Close()
Catch e As Exception
Console.WriteLine("Error: " & e.Message)
End Try
End Sub
End Module
The code begins with the creation of a new SqlConnection object of the
System.Data.SqlClient namespace in line e. The SqlConnection class han-
dles connections to an SQL Server. (The class structure is shown in Tables 7-3
and 7-4.) This class implements the IDbConnection interface for the SQL
Server .NET Managed Data Provider. Its constructor contains a connection
string. Connection string syntax is specific to a particular DBMS; SQL Server
connection strings typically supply a host name (Data Source), a database
name (Initial Catalog), a user name (uid), and a password (pwd).
Property Description
ConnectionString Specifies the connection string to use when opening an SQL Server
database
ConnectionTimeout Sets the maximum time (in seconds) to wait for a successful
connection to the database
DataSource Specifies the SQL instance to which to connect (configured with the
SQL Server Client Network Utility)
PacketSize Sets the size (in bytes) of network packets to use when
communicating with SQL Server
BeginTransaction(ByVal iso
As IsolationLevel) As
SqlTransaction
BeginTransaction(ByVal
transactionName As String)
As SqlTransaction
BeginTransaction(ByVal iso
As IsolationLevel, ByVal
transactionName As String)
As SqlTransaction
Property Description
CommandTimeout Sets the maximum time (in seconds) to wait for the completion of a
command
retrieved in the SQL command (starting with 0). After all the records are
retrieved, we clean up by closing the SqlDataReader object with a call to the
Close() method in line l.
quotes themselves. This leads to syntax errors in the statement, or worse, erro-
neous data in your database!
You can avoid these issues by constructing the command the second way:
by using SqlParameter objects to supply parameters to Transact-SQL state-
ments. Table 7-7 lists the properties of the SqlParameter class.
Property Description
Offset Sets the offset to the Value property for binary and string types
Precision Sets the maximum number of digits used to represent the Value
property
Scale Sets the number of decimal places to which the Value property is
resolved
Size Sets the maximum size (in bytes) of the data within the column
SourceColumn Specifies the name of the source column that is mapped to the DataSet
object and used for loading or returning the Value property
SqlDbType Specifies the SqlDbType of the parameter (maps to SQL Server data
types)
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports Microsoft.VisualBasic
Module Module1
Sub Main()
Try
Dim objParam As SqlParameter
Dim objCnn As New SqlConnection( _
"Initial Catalog=pubs;Data Source=localhost;uid=sa;pwd=")
objCnn.Open()
objCmd.Parameters.Add(objParam)
Do While objReader.Read()
Console.WriteLine("{0}" & _
ControlChars.Tab & "{1} {2}", _
objReader.GetString(0), _
objReader.GetString(1), _
objReader.GetString(2))
Loop
objCnn.Close()
Catch e As Exception
Console.WriteLine("Error: " & e.Message)
End Try
End Sub
End Module
@parameter_name
Notice the first boldface line, where we set the CommandText property. Instead
of reading in every record in the authors table like we did in the previous
example, we use an SQL WHERE clause to return records only for those authors
who live in California (CA) and have a contract. Names you assign to parame-
ters are arbitrary. The example uses parameter names that are the same as the
column names for simplicity.
Now it’s time to create the SqlParameter objects. After we create an
SqlParameter object, we proceed to assign values to the class properties. We
start with the ParameterName property, which is assigned the corresponding
parameter name specified in the CommandText string. Then the DbType needs
to be set. Since the state column in the authors table is a character field, we
use the DbType.String value to indicate that the parameter’s data should be
treated as a string. Next we need to specify how the parameter is to be used.
In this case, the SQL statement shall treat the value supplied as input, so we
specify ParameterDirection.Input. Finally, we specify the actual value for
508 Chapter 7 Accessing Data with ADO.NET
the parameter using the Value property. The process is repeated for the sec-
ond parameter, only we assign DbType.Boolean for the DbType (maps to SQL
Server “bit” type) and specify a Boolean True for the Value.
<html>
<head>
<title>SQL Server Data Binding Example</title>
</head>
<body>
7.4 Displaying Database Data 509
<form id="Form1"
method="post"
runat="server">
m <asp:DataGrid
id=dgMyDataGrid
DataKeyField="au_id"
AutoGenerateColumns=false
runat="server">
<Columns>
n <asp:TemplateColumn HeaderText="Author ID">
<ItemTemplate>
<asp:Label
Text='<%# Container.DataItem("au_id") %>'
id=lblAuthorID
Runat="server" />
</ItemTemplate>
</asp:TemplateColumn>
p <EditItemTemplate>
<asp:TextBox
Text='<%# Container.DataItem("au_lname") %>'
ID="txtAuthorLName"
Runat="server"/>
</EditItemTemplate>
</asp:TemplateColumn>
q <asp:EditCommandColumn
EditText="Edit"
CancelText="Cancel"
UpdateText="Update"/>
</Columns>
510 Chapter 7 Accessing Data with ADO.NET
</asp:DataGrid>
</form>
</body>
</html>
The code block beginning in line m shows the definition of the DataGrid
Control named dgMyDataGrid. Since we are defining our own template
columns, we don’t want the DataGrid Control to automatically generate
columns from the DataSource, so we set the AutoGenerateColumns property
to False. One other property of importance, DataKeyField, states which field
to use as a key when updating edited rows (more on this later).
Inside the <Columns> tag, we begin to define the template columns. In the
first column, coded in the block that begins in line n, we are going to display
the contents of the au_id field. So, we use an <ItemTemplate> tag to instruct
the DataGrid Control how to display the column data in item (read) mode.
A child control, Label, is used to display the data. The data-binding syntax
introduced in Chapter 3 is employed again in this example. In this case, the
DataItem is the name of the au_id column in the authors table we are going
to query.
Moving on to the next column, we display the au_lname field in the code
block that starts in line o. The column template for display/item mode is the
same as in the previous template column for au_id, except for changes to the
ID attribute and the DataItem name.
The au_lname field is one that we wish to edit, so we must provide an
<EditItemTemplate> tag in line p so the DataGrid Control will know how to
display data fields in edit mode. Again, it’s similar to our previous templates,
but we use a TextBox Control instead of a Label Control so the user will be
able to type in a new value.
In line q we specify a special column for the editing controls using the
EditCommandColumn Control. This column will display links for invoking edit-
ing on a row of data (EditText), canceling an edit (CancelText), and updating
the row (UpdateText).
Like most of our ASP.NET pages, we use a code-behind file to perform
the database access to SQL Server. In the Page_Load subroutine (see line r
in the code below), we want to retrieve the data from the database. We do
this by calling the BindIt() subroutine. This call will occur only when the
page does not send a post-back to the server (the first time the page is
requested).
7.4 Displaying Database Data 511
The BindIt() subroutine that begins in line s below uses code from the
IDataReader example. Just to recap the functionality of that code, we estab-
lish a connection to SQL Server with the SqlConnection object. After estab-
lishing a connection, we obtain an SqlCommand object. Using SqlParameter
objects, we build our query to retrieve records for authors who live in Cali-
fornia and have active publishing contracts. The IDataReader interface we
obtain from the ExecuteReader() method in line t can be used to set the
DataSource property of the DataGrid u.
Here’s the complete code for the editable DataGrid Control.
Imports System.Data
Imports System.Data.SqlClient
Imports System.Web
Imports System.Web.UI
Imports System.Web.UI.WebControls
End Sub
objCnn.Open()
With objParam
.ParameterName = "@state"
.DbType = DbType.String
.Direction = ParameterDirection.Input
.Value = "CA"
End With
objCmd.Parameters.Add(objParam)
dgMyDataGrid.DataSource = objReader
u dgMyDataGrid.DataBind()
End Sub
dgMyDataGrid.EditItemIndex = e.Item.ItemIndex
BindIt()
End Sub
dgMyDataGrid.EditItemIndex = -1
BindIt()
End Sub
ByVal e As DataGridCommandEventArgs) _
Handles dgMyDataGrid.UpdateCommand
y lblAuthorID = CType(e.Item.FindControl( _
"lblAuthorID"), _
Label)
z txtAuthorLName = CType(e.Item.FindControl( _
"txtAuthorLName"), _
TextBox)
objCnn.Open()
} intRowsAffected = objCmd.ExecuteNonQuery()
514 Chapter 7 Accessing Data with ADO.NET
dgMyDataGrid.EditItemIndex = -1
BindIt()
End Sub
End Class
We use the Handles keyword to designate for which event we are writing
an event handler. The event-handling function signature consists of an
Object parameter and the DataGridCommandEventArgs parameter. We
can determine specifics about the row we are about to edit through the
DataGridCommandEventArgs object. Setting the DataGrid Control into
edit mode is easy; we simply assign the EditItemIndex property of the
DataGrid Control to the index of the row that was selected. The selected
row value comes from e.Item.ItemIndex.; Item represents the row object
for the event and ItemIndex the ordinal index of that row. With the
EditItemIndex property set, we call the BindIt() subroutine again to
refresh the display.
We want to give users the opportunity to cancel an edit in progress. They
do this by clicking the Cancel button for a row for which the Edit button was
previously clicked. When Cancel is clicked, the CancelCommand event is
raised, and the event handler is called according to the code block that begins
in line w. Canceling the edit is simply a matter of setting EditItemIndex to
–1. This returns the DataGrid Control to read mode.
Handling the UpdateCommand event requires two steps, as shown in the
code beginning in line x. First we need to find out the values of the edited
7.4 Displaying Database Data 515
data items by obtaining references to the edited controls (see lines y and z in
the code above, reproduced here as well).
lblAuthorID = CType(e.Item.FindControl( _
"lblAuthorID"), _
Label)
txtAuthorLName = CType(e.Item.FindControl( _
"txtAuthorLName"), _
TextBox)
e.Item refers to the row in which the event occurred. That row contains
child controls that interest us. The FindControl() method helps us locate a
control based on its identifier. We obtain references to the Label Control that
holds the AuthorID value and the TextBox Control that contains the modified
value entered for the author’s last name. FindControl() returns an Object, so
in order for us to reference that Object as the control it’s supposed to repre-
sent, we use the VB CType() function to convert the Object to a Label Con-
trol and a TextBox Control.
Now we begin to build an SqlCommand to update the database. We use
code similar to that in previous examples. In lines { and | we see the String
values of the parameters being set to the value contained in the Text property
of the Label and TextBox Controls. Then, after the parameters have been
attached to the SQL UPDATE command, we use the ExecuteNonQuery()
method in line } to execute the update. The final call to the BindIt() sub-
routine refreshes the display.
Figure 7-1 shows the editing of a row in the completed data grid.
516 Chapter 7 Accessing Data with ADO.NET
LAB 7-1
AN ONLINE PHOTO GALLERY
STEP 1. Create a new VB.NET Web application named “PhotoAlbum”.
a. Drag a new DataGrid Web Control onto the Web Form and name its ID
property “dgPhotoData”. This DataGrid Control needs to set the
AutoGenerateColumns property to False. The DataGrid code should look
something like the following.
<asp:datagrid
id=dgPhotoData
runat="server"
Visible="False"
AutoGenerateColumns=false>
</asp:datagrid>
b. Now you need to create template columns for the DataGrid. This DataGrid
will ultimately be bound to the PhotoInfo table in the Photo SQL
Server database. To create an editable DataGrid you need to add an
EditCommandColumn command and some TemplateColumn Controls.
Within one of the TemplateColumn Controls, add an ItemTemplate
command and an EditItemTemplate command. Here’s how the modified
DataGrid Control code should look when you’re finished making these
additions to the previous DataGrid Control code.
<asp:datagrid
id=dgPhotoData
runat="server"
Visible="False"
AutoGenerateColumns=false>
<Columns>
<asp:TemplateColumn HeaderText="Name">
<ItemTemplate>
<%# Container.DataItem("PhotoFieldName")%>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Value">
<ItemTemplate>
<%# Container.DataItem("PhotoFieldValue")%>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox
ID="txtEditValue"
runat="server"
Text='<%# Container.DataItem("PhotoFieldValue") %>' />
7.5 Programming with the DataList and DataGrid Controls 519
</EditItemTemplate>
</asp:TemplateColumn>
<asp:EditCommandColumn
UpdateText="Update"
CancelText="Cancel"
EditText="Edit"
ButtonType=LinkButton/>
</Columns>
</asp:datagrid>
<asp:datalist
id=dlPhotoGrid
runat="server"
HorizontalAlign="Center"
RepeatColumns="3"
RepeatDirection="Horizontal"
BorderColor="Black"
CellSpacing="1"
CellPadding="1"
GridLines="Both"
BorderWidth="1px">
</asp:datalist>
These properties will give the data list gridlines and will display data items
in three columns.
d. Now set up the item templates. The code below shows what’s required to
place an HTML <img> tag in each cell of the DataList Control, plus the
styles to use for selected items in the DataList Control. Here’s the com-
plete DataList Control implementation.
<asp:datalist
id=dlPhotoGrid
520 Chapter 7 Accessing Data with ADO.NET
runat="server"
HorizontalAlign="Center"
RepeatColumns="3"
RepeatDirection="Horizontal"
BorderColor="Black"
CellSpacing="1"
CellPadding="1"
GridLines="Both"
BorderWidth="1px">
<SelectedItemStyle
BackColor="black"
ForeColor="white">
</SelectedItemStyle>
<SelectedItemTemplate>
<img src="<%# Container.DataItem.ToString() %>"><br>
<asp:Label BackColor="white" ID="lblSelFilename">
<%# Container.DataItem.ToString() %>
</asp:Label>
</SelectedItemTemplate>
<ItemTemplate>
<img src="<%# Container.DataItem.ToString() %>"><br>
<asp:Button
CommandName="Select"
CommandArgument="<%# Container.DataItem.ToString() %>"
Text="Select"
Runat="server"/>
<asp:Label ID=lblFilename>
<%# Container.DataItem.ToString() %>
</asp:Label>
</ItemTemplate>
</asp:datalist>
To show the cell as “inverted” for items the user selects, the code
specifies a BackColor of black for the SelectedItemStyle. Also, the
SelectedItemTemplate shows that the text should also be displayed as
white to make it visible against the black background of the cell. The
implementation of ItemTemplate is similar but includes the specification
of CommandName and CommandArgument, which will be used in the code-
behind file that handles events for selection of items.
7.5 Programming with the DataList and DataGrid Controls 521
e. Photos are added to the album via a forms-based file upload (RFC 1867)
using the HtmlInputFile Control. Place the code below, which contains the
required HTML fragment, in the Web Form. This code also includes a Button
Web Control to accept the file submission. Make sure the controls are
named correctly so they match the event handlers in the code-behind file.
f. For the last Web Control, place a Label Control in the Web Form, which will
be used to display any errors encountered during the use of the photo
gallery. Here is the code to enter.
<asp:Label
id=lblErrorMessage
runat="server"
Width="461px"
Height="19px"
ForeColor="Red"
Font-Bold="True">
</asp:Label>
g. Finally, you need to make one small adjustment to the <form> tag: add an
attribute, encType, and set it to multipart/form-data. This is a require-
ment for the file upload since IIS needs to know how to decode the form
data as well as the Base64-encoded file submission on the server. The code
should read as follows.
<form id=Form1
method=post
encType="multipart/form-data"
runat="server">
• Data-binding code
• Event handlers for the DataList and DataGrid Controls
• Event handler for the Add Photo button
• Miscellaneous support functions
a. Begin with the data-binding code. Your first job is to write a function that
will retrieve the images from the directory and bind that data to the
DataList Control. Here is that code.
strImagePath = Server.MapPath("/images")
dlPhotoGrid.DataSource = aryFileArray
dlPhotoGrid.DataBind()
End Sub
The BindIt() subroutine first retrieves the physical path of the /images
virtual directory. Then the code uses the VB Dir() function to return .jpg
file names in a loop. Each one is added to an array list, which is bound to
the DataList Control, dlPhotoGrid.
b. Implement the code shown below to bind the DataGrid Control for the text-
annotation data.
objCnn.Open()
objCmd = objCnn.CreateCommand()
7.5 Programming with the DataList and DataGrid Controls 523
objCmd.CommandText = _
"SELECT PhotoFieldName, PhotoFieldValue " & _
"FROM PhotoInfo WHERE Filename = '" & pKey & _
"'"
objSqlDR = objCmd.ExecuteReader()
dgPhotoData.Visible = True
dgPhotoData.DataSource = objSqlDR
dgPhotoData.DataBind()
End Sub
c. Set up some code for the Page_Load event that binds the DataList
Control.
ViewState("filename") = e.CommandArgument
BindPhotoData(e.CommandArgument)
This code checks the CommandName (which was specified in the DataGrid
Control in the HTML code) and then sets the appropriate SelectedIndex.
This was passed to the program from the DataListCommandEventArgs
parameter, e. Next, the code needs to save one piece of state information,
Filename. This is necessary because a post-back to the server will cause
the current file name selection in the DataList Control to become unavail-
able. The program will need this information when binding the DataGrid
Control with BindPhotoData().
e. The next step is the event-handling code for the DataGrid Control. You need
to handle events for the Edit, Update, and Cancel links. First, enter this
code for the Edit event.
dgPhotoData.EditItemIndex = e.Item.ItemIndex
BindPhotoData(ViewState("filename"))
End Sub
This code causes the DataGrid Control to enter edit mode for the
selected row. Data binding needs to happen here, so after setting the
EditItemIndex, the code calls BindPhotoData(), using the saved
value from the ViewState collection, which was populated when the
Select button was clicked for an item in the data list.
f. Implement similar functionality to handle the Cancel selection.
Try
Dim objCnn As New SqlConnection( _
"Initial Catalog=Photo;Data Source=localhost;uid=sa;pwd=")
Dim objSqlCmd As SqlCommand
Dim intRows As Integer
Dim objParam As SqlParameter
txtEditedValue = CType( _
e.Item.FindControl("txtEditValue"), _
TextBox)
strFilename = ViewState("filename")
objCnn.Open()
End With
objCmd.Parameters.Add(objParam)
intRows = objCmd.ExecuteNonQuery()
dgPhotoData.EditItemIndex = -1
BindPhotoData(strFilename)
End Sub
This code is considerably more complex, but the concepts should be familiar
since we have covered all of them in previous examples. To get the value
that the user typed into the editable field in the data grid, the code obtains
a reference to the TextBox Control defined in the EditItemTemplate. The
Text property of this TextBox Control contains the value that the user
entered. Next the database connection opens and the code begins building
the command for the SqlCommand object. SqlParameter objects set values
for the PhotoFieldValue and Filename columns in the SQL statement. The
SqlParameter objects are added to the command, the command is exe-
cuted, and then the EditItemIndex is reset to –1, placing the DataGrid
Control back into read mode.
h. Add the event handler for the Add Photo button, which copies the uploaded
photo to the server’s /images directory. It also initializes (adds) a new row
to the PhotoInfo table. Here is the code.
Try
objCnn.Open()
objSqlCmd = objCnn.CreateCommand()
objSqlCmd.CommandText = _
"INSERT INTO PhotoInfo " & _
"(PhotoFieldName, PhotoFieldValue, Filename) " & _
"VALUES ('Caption', '', '" & "/images/" & _
GetFilenameFromPath(fAddPhoto.PostedFile.FileName) & _
"')"
strFilePath = Server.MapPath("/images")
If Right(fAddPhoto.PostedFile.FileName, 4) <> _
".jpg" Then
Throw New BadImageFormatException( _
"Not a JPEG file")
End If
fAddPhoto.PostedFile.SaveAs(strFilePath & _
"\" & _
GetFilenameFromPath( _
fAddPhoto.PostedFile.FileName))
objSqlCmd.ExecuteNonQuery()
lblErrorMessage.Text = ""
End If
BindIt()
Catch E As Exception
lblErrorMessage.Text = E.Message
End Try
End Sub
The code first sets up the database connection and creates an SQL INSERT
statement for the PhotoInfo table. Next the program checks to see if there
528 Chapter 7 Accessing Data with ADO.NET
Sub New()
MyBase.New()
End Sub
End Class
Imports System
Imports System.Data
Imports System.Data.SqlClient
Inherits Exception
Sub New()
MyBase.New()
End Sub
End Class
objCnn.Open()
objCmd = objCnn.CreateCommand()
objCmd.CommandText = _
"SELECT PhotoFieldName, PhotoFieldValue " & _
"FROM PhotoInfo WHERE Filename = '" & pKey & _
"'"
objSqlDR = objCmd.ExecuteReader()
dgPhotoData.Visible = True
dgPhotoData.DataSource = objSqlDR
dgPhotoData.DataBind()
End Sub
strImagePath = Server.MapPath("/images")
dlPhotoGrid.DataSource = aryFileArray
dlPhotoGrid.DataBind()
End Sub
7.5 Programming with the DataList and DataGrid Controls 531
Try
objCnn.Open()
objSqlCmd = objCnn.CreateCommand()
objSqlCmd.CommandText = _
"INSERT INTO PhotoInfo " & _
"(PhotoFieldName, PhotoFieldValue, Filename) " & _
"VALUES ('Caption', '', '" & "/images/" & _
GetFilenameFromPath(fAddPhoto.PostedFile.FileName) & _
"')"
strFilePath = Server.MapPath("/images")
If Right(fAddPhoto.PostedFile.FileName, 4) <> _
".jpg" Then
Throw New BadImageFormatException( _
"Not a JPEG file")
End If
fAddPhoto.PostedFile.SaveAs(strFilePath & _
"\" & _
GetFilenameFromPath( _
fAddPhoto.PostedFile.FileName))
objSqlCmd.ExecuteNonQuery()
lblErrorMessage.Text = ""
End If
BindIt()
Catch E As Exception
lblErrorMessage.Text = E.Message
End Try
532 Chapter 7 Accessing Data with ADO.NET
End Sub
Try
Dim objCnn As New SqlConnection( _
"Initial Catalog=Photo;Data Source=localhost;uid=sa;pwd=")
Dim objSqlCmd As SqlCommand
Dim intRows As Integer
Dim objParam As SqlParameter
txtEditedValue = CType( _
e.Item.FindControl("txtEditValue"), _
TextBox)
strFilename = ViewState("filename")
7.5 Programming with the DataList and DataGrid Controls 533
objCnn.Open()
intRows = objCmd.ExecuteNonQuery()
dgPhotoData.EditItemIndex = -1
BindPhotoData(strFilename)
End Sub
BindIt()
End If
ViewState("filename") = e.CommandArgument
BindPhotoData(e.CommandArgument)
End Class
These are a few suggestions. With your knowledge of Web Controls, you should be able
to think up many more. Get creative!
7.6 Working with the DataSet and DataTable Objects 535
Property Description
(continued)
536 Chapter 7 Accessing Data with ADO.NET
Property Description
HasErrors Has a value of True if there are errors in any of the rows of the
DataSet object
Prefix Specifies the XML prefix that aliases the namespace of the
DataSet object
InferXmlSchema(ByVal
fileName As String, ByVal
nsArray() As String)
InferXmlSchema(ByVal
reader As TextReader,
ByVal nsArray() As
String)
InferXmlSchema(ByVal
reader As XmlReader,
ByVal nsArray() As
String)
(continued)
538 Chapter 7 Accessing Data with ADO.NET
Merge(ByVal dataSet As
DataSet)
Merge(ByVal table As
DataTable)
Merge(ByVal dataSet As
DataSet, ByVal
preserveChanges As
Boolean)
Merge(ByVal rows() As
DataRow, ByVal
preserveChanges As
Boolean, ByVal
missingSchemaAction As
MissingSchemaAction)
Merge(ByVal dataSet As
DataSet, ByVal
preserveChanges As
Boolean, ByVal
missingSchemaAction As
MissingSchemaAction)
Merge(ByVal table As
DataTable, ByVal
preserveChanges As
Boolean, ByVal
missingSchemaAction As
MissingSchemaAction)
ReadXml(ByVal fileName As
String) As XmlReadMode
7.6 Working with the DataSet and DataTable Objects 539
ReadXml(ByVal reader As
TextReader) As
XmlReadMode
ReadXml(ByVal reader As
XmlReader) As XmlReadMode
ReadXml(ByVal stream As
Stream, ByVal mode As
XmlReadMode) As
XmlReadMode
ReadXml(ByVal fileName As
String, ByVal mode As
XmlReadMode) As
XmlReadMode
ReadXml(ByVal reader As
TextReader, ByVal mode As
XmlReadMode) As
XmlReadMode
ReadXml(ByVal reader As
XmlReader, ByVal mode As
XmlReadMode) As
XmlReadMode
ReadXmlSchema(ByVal
fileName As String)
ReadXmlSchema(ByVal
reader As TextReader)
ReadXmlSchema(ByVal
reader As XmlReader)
(continued)
540 Chapter 7 Accessing Data with ADO.NET
WriteXmlSchema(ByVal
fileName As String)
WriteXmlSchema(ByVal
reader As TextReader)
WriteXmlSchema(ByVal
reader As XmlReader)
base and in many respects has the same behaviors and characteristics. The
properties and methods of the DataTable class are shown in Tables 7-10 and
7-11, respectively.
Property Description
DataSet Returns the DataSet object that contains the DataTable object
DefaultView Returns the default view of the DataTable object; used for some
data-binding situations
DisplayExpression Gets or sets the expression that will return a value used to
represent this table in the user interface
HasErrors Has a value of True if any rows in the data table contain errors
MinimumCapacity Sets the minimum number of rows (starting size) for the data table
Namespace Specifies the namespace for the XML representation of the data
stored in the DataTable object
Prefix Specifies the XML prefix that aliases the namespace of the
DataTable object
(continued)
542 Chapter 7 Accessing Data with ADO.NET
Property Description
PrimaryKey Specifies the array of columns that make up the primary key for the
data table
(continued)
544 Chapter 7 Accessing Data with ADO.NET
Select(ByVal
filterExpression As
String, ByVal sort As
String) As DataRow()
Select(ByVal
filterExpression As
String, ByVal sort As
String, ByVal As
recordStates
DataViewRowState) As
DataRow()
Imports System
Imports System.Xml
Imports System.Data
7.6 Working with the DataSet and DataTable Objects 545
Imports Microsoft.VisualBasic
Module Module1
Sub Main()
Ç aDC(0) = objDT.Columns("ProductSKU")
É objDT.PrimaryKey = aDC
aDC(0) = objDT.Columns("InventoryRecordNum")
objDT.PrimaryKey = aDC
With objDT.Columns("InventoryRecordNum")
546 Chapter 7 Accessing Data with ADO.NET
Ñ .AutoIncrement = True
! .AutoIncrementSeed = 1
Ü .AutoIncrementStep = 1
End With
End Module
We begin the code with the creation of a new DataSet object in line ~ called
Supermarket. The DataSet object will contain two tables. The first one is
created in line Ö. The new DataTable object, objDT, does not contain
any fields (columns), so we must specify some. All of the columns for the
DataTable object are kept in the collection referenced by the Columns
property.
Property Description
AllowDBNull Has a value of True if database NULL values are allowed for this
column
AutoIncrement Has a value of True if a new unique number is generated for this
column when a new row is added
Expression Specifies the expression used to filter rows, calculate the values in
a column, or create an aggregate column
Prefix Specifies the XML prefix that aliases the namespace of the
DataColumn object
(continued)
548 Chapter 7 Accessing Data with ADO.NET
Property Description
ReadOnly Has a value of True if the column’s data can’t be changed once a
row has been created
Unique Has a value of True if the values in each row of the column must
be unique
in line # shows the use of a nested loop that retrieves information for each
DataTable object in the DataSet (using the DataTableCollection)
and each DataColumn object in those DataTable objects (using the
DataColumnCollection). Code within these loops outputs each
DataTable object’s name as well as column name and type information.
Try
Dim dr As DataRow
$ dr = pProductTable.NewRow()
% dr.Item("ProductSKU") = pProductSKU
& dr.Item("ProductDescription") = pProductDescription
â pProductTable.Rows.Add(dr)
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
Once we’ve created the DataRow object, we can assign values to its
columns. In lines % and & we assign to the DataRow object the two String
parameters defined earlier. We reference the columns in the data row using
the Item property. The Item property can take an ordinal index or a column
name (specified as a String). The new data that we supply to the DataRow
object does not get appended to the table until the DataRow object is added to
the Rows collection in line â.
Try
Dim dc As DataColumn
Dim dr As DataRow
Dim obj As Object
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
7.6 Working with the DataSet and DataTable Objects 551
For clarity of the output, in the code block beginning in line ( we include
code to display all the column names in the DataSet object before displaying
any row data. In line ) we start the outer loop that iterates through all the
DataRow objects in the DataSet object. The DataRow class contains the
ItemArray property (see line *), which is an array of System.Object
and holds the values contained in the DataRow object. The inner loop
converts each of those object values to a System.String for display in
the console.
Property Description
MissingMappingAction Indicates or specifies whether unmapped source tables or
columns are passed with their source names in order to be
filtered or to raise an error. Can be Error, Ignore, or
Passthrough (MissingMappingAction enumeration).
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Xml
Module Module1
Sub Main()
Dim ds As DataSet
Dim da As SqlDataAdapter
Dim cb As SqlCommandBuilder
Dim dt As DataTable
ds = New DataSet("TestDataSet")
. da.Fill(ds, "authors")
Dim dr As DataRow
dt = ds.Tables("authors")
2 da.Update(ds, "authors")
End Sub
E.Row.Item("au_id"))
End Sub
End Module
Property Description
Event Description
Property Description
AllowDelete Has a value of True if deletes from the DataView object are
allowed
AllowEdit Has a value of True if edits of the DataView object are allowed
AllowNew Has a value of True if new rows are allowed to be added to the
DataView object
Property Description
RowStateFilter Specifies the row state filter with these values: Added,
CurrentRows, Deleted, ModifiedCurrent,
ModifiedOriginal, None, OriginalRows, and Unchanged
(DataViewRowState enumeration)
(continued)
558 Chapter 7 Accessing Data with ADO.NET
Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Xml
Imports Microsoft.VisualBasic
Module Module1
Sub Main()
Try
ds = New DataSet("TestDataSet")
da.Fill(ds, "authors")
ListTableContents(ds.Tables("authors"))
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
Try
Dim dc As DataColumn
Dim dr As DataRow
Dim obj As Object
Dim dv As DataView
Dim intRowIndex As Integer
Dim intFoundIndex As Integer
Dim aSearchValues(2) As String
4 dv = New DataView(pTable)
With dv
5 .Sort = "au_fname, au_lname"
6 .RowFilter = "Contract = 0"
7 .RowStateFilter = _
DataViewRowState.OriginalRows
End With
Console.WriteLine(ControlChars.NewLine)
560 Chapter 7 Accessing Data with ADO.NET
: aSearchValues(0) = "Michel"
aSearchValues(1) = "DeFrance"
intFoundIndex = dv.Find(aSearchValues)
dr = dv.Item(intFoundIndex).Row
For Each obj In dr.ItemArray
Console.Write(obj.ToString() & _
ControlChars.Tab)
Next
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
End Module
Property Description
of products, it follows that these products are the only ones that can exist in
the Inventory table. We can enforce this rule using the DataRelation class,
as shown in the code below.
7.7 Maintaining Data Integrity with the DataRelation Class 563
Imports System
Imports System.Xml
Imports System.Data
Imports Microsoft.VisualBasic
Module Module1
Sub Main()
aDC(0) = objDT.Columns("ProductSKU")
objDT.PrimaryKey = aDC
.Add("InventoryExpirationDate", _
Type.GetType("System.DateTime"))
End With
objDS.Tables.Add(objDT)
aDC(0) = objDT.Columns("InventoryRecordNum")
objDT.PrimaryKey = aDC
With objDT.Columns("InventoryRecordNum")
.AutoIncrement = True
.AutoIncrementSeed = 1
.AutoIncrementStep = 1
End With
; objProduct_SKU = _
objDS.Tables("Product").Columns("ProductSKU")
objInventory_SKU = _
objDS.Tables("Inventory").Columns("InventorySKU")
objDS.Relations.Add(New DataRelation( _
"fk_ProductSKU", _
objProduct_SKU, _
objInventory_SKU))
objDT = objDS.Tables("Product")
objIT = objDS.Tables("Inventory")
ListTableContents(objDT)
ListTableContents(objIT)
End Sub
Try
Dim dr As DataRow
dr = pInventoryTable.NewRow()
dr.Item("InventorySKU") = pProductSKU
dr.Item("InventoryQuantity") = pQuantity
dr.Item("InventoryBinNumber") = pBinNumber
dr.Item("InventoryExpirationDate") = pExpire
pInventoryTable.Rows.Add(dr)
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
Try
Dim dr As DataRow
dr = pProductTable.NewRow()
dr.Item("ProductSKU") = pProductSKU
dr.Item("ProductDescription") = pProductDescription
pProductTable.Rows.Add(dr)
Catch E As Exception
566 Chapter 7 Accessing Data with ADO.NET
End Sub
Try
Dim dc As DataColumn
Dim dr As DataRow
Dim obj As Object
Catch E As Exception
Console.WriteLine("ERROR: " & E.Message)
End Try
End Sub
End Module
With this code we’ve modified the previous DataSet example somewhat.
The boldface text shows the additions to the code. The code block that begins
in line ; shows the process of adding a new DataRelation object to the
DataSet object. Creating a new DataRelation object involves linking two
table columns together. The first step is obtaining two DataColumn objects
to the ProductSKU and InventorySKU columns. Then, using the Relations
collection of the DataSet object, we use the Add() method to add a new
DataRelation object to the collection. The DataRelation constructor accepts
three parameters: an arbitrary name to assign to the DataRelation object, a
7.8 Using Manual Database Transactions 567
Property Description
Imports System
Imports System.Data
Imports System.Data.SqlClient
Module Module1
Sub Main()
7.8 Using Manual Database Transactions 569
Try
objCnn = New SqlConnection( _
"Initial Catalog=pubs;Data Source=localhost;uid=sa;pwd=")
objCnn.Open()
= objTrans = objCnn.BeginTransaction()
objCmd.ExecuteNonQuery()
? objTrans.Commit()
Catch e As Exception
@ objTrans.Rollback()
Console.WriteLine("ERROR: " & e.Message)
Console.WriteLine("All records rolled back.")
Finally
objCnn.Close()
570 Chapter 7 Accessing Data with ADO.NET
End Try
End Sub
End Module
One of the most powerful features of the .NET Framework lies in the
extensibility of the class libraries. Many of the classes in the .NET Framework
can be extended through inheritance. The DataSet is one such class. By creat-
ing new application-specific classes that inherit from the DataSet class, you
can access table, column, and row information in a strongly typed fashion, that
is, you can reference objects by name rather than using a collection-based
index. Another benefit gained from using typed DataSet objects is the produc-
tivity enhancement received when using the VS.NET IDE. The editor offers
help via IntelliSense with method and property names for the typed DataSet
object.
VS.NET provides powerful graphical tools to aid in the construction
of typed DataSet objects. In Lab 7-2 you’ll learn how to use VS.NET to
create typed DataSet classes. The lab uses the SQL Server pubs database.
You’ll examine the process of generating the code for the new classes and
write a small program to demonstrate the use of the new typed DataSet class.
LAB 7-2
VS.NET AND TYPED DataSet OBJECTS
STEP 1. Launch VS.NET.
STEP 4. Add the XSD file and generate the DataSet object.
a. Select File➔Add New Item . . . from the menu. Select the DataSet icon and
enter a name for the XSD file (PubsDS.xsd is used in Lab Figure 7-3). Click
the Open button to create the XSD file.
The XSD file is an XML schema used to describe a DataSet object.
VS.NET uses this XML schema to generate the typed DataSet classes.
Initially, this file is “blank” (contains no table definition data). To add a
7.9 Working with Typed DataSet Objects 573
Lab Figure 7-2 The Server Explorer dialog showing the tables
of the pubs database
Lab Figure 7-4 The authors DataSet object in the XSD Design View
table definition to the file, you need to select a table from the Server
Explorer and drag it to the Design View of the XSD file.
b. Select the authors table from the Server Explorer and drag it to the designer
surface of the XSD file. The table appears as shown in Lab Figure 7-4.
A new class is generated as a result of adding the authors table to the
XSD file. Lab Figure 7-5 shows the Class View of the PubsDS class that
was created.
Imports System
Imports System.Data
Imports System.Data.SqlClient
7.9 Working with Typed DataSet Objects 575
Imports Microsoft.VisualBasic
Module Module1
Sub Main()
Dim objDA As SqlDataAdapter
Dim objPubsDS As PubsDS
Dim objAuthor As PubsDS.AuthorsRow
Try
objDA = New SqlDataAdapter( _
"SELECT * FROM authors", _
"Initial Catalog=pubs;Data Source=localhost;uid=sa;pwd=")
objDA.Fill(objPubsDS, "Authors")
Catch e As Exception
Console.WriteLine("ERROR: " & e.Message)
End Try
End Sub
End Module
The code follows these main steps for the typed DataSet object.
1. Create a new SqlDataAdapter object.
2. Declare a new instance of the typed DataSet object (using the New
statement).
3. Fill the typed DataSet object using the SqlDataAdapter object.
4. Access the typed DataSet row data.
The code declares an object called objAuthor, which represents a single row
in the authors table of the typed DataSet object. The For . . . Each loop uses
the objAuthor object as an iterator. Notice that when code is entered in the
VS.NET IDE, IntelliSense shows the columns of the authors table as class
member variables (see Lab Figure 7-6). VS.NET automatically built this class
and added the appropriate stub code to handle the application logic behind the
properties.
Lab Figure 7-6 IntelliSense showing columns of the authors table as class
member variables
7.10 Summary
Here are some critical points to remember about accessing data with
ADO.NET.
■ Data-access technologies from Microsoft have followed an evolutionary
path that includes technologies such as Embedded SQL, ODBC,
OLE-DB, ADO, and now ADO.NET.
■ ADO.NET brings many performance and architectural enhancements,
including XML-based data marshalling, an intuitive programming
model, and high scalability due to the disconnected fashion in which
data is handled.
■ The architecture of ADO.NET includes the DataSet class and the
.NET Managed Data Provider. The DataSet class and its related
classes, the DataTable, DataRow, and DataColumn classes, create an in-
memory representation of database data. The .NET Managed Data
Provider is the piece that talks to the database and supplies the
DataSet object with data.
■ The IDataReader interface and the SQL Server implementation of
that interface, SqlDataReader, provides quick and efficient read-only
access to data. It’s typically used for applications that need forward-
only access to record data in DataTable objects. The SqlConnection
object is used to establish a physical connection to an SQL Server.
■ ASP.NET Web Controls, like the DataGrid Control, can be bound with
data using the SqlDataReader object. The DataGrid Control can also
allow for editing of the data, using a combination of intrinsic function-
ality and the SqlCommand class for handling the updates.
■ The DataSet object is made up of a collection of DataTable objects.
DataTable objects in turn are comprised of DataRow and DataColumn
objects. The DataView class is used for filtering, searching, and sorting
data contained in DataTable objects.
■ The DataRelation class is used to set up relationships between
DataColumn objects in different DataTable objects. The DataRelation
class is used to model the functionality of foreign keys in databases.
■ Manual transactions are those types of transactions that have direct
support in ADO.NET. In SQL Server, you explicitly control the trans-
action by using the methods of the SqlTransaction class rather than
using a declarative method such as COM+ Component Services
provides.
7.11 What's Ahead 579
■ The typed DataSet object is a user-defined class that inherits from the
DataSet class. The typed DataSet object allows you to refer to row
data in a DataTable object as class member variables rather than using
a collection-based index.
Securing .NET
Applications
Keeping unwanted visitors out of your site is essential, and there are a number
of ways to ensure that intruders stay clear. If your site is used for a commercial
purpose and if financial transactions are taking place, security is paramount.
Protecting the privacy of users and preventing access to sensitive system
resources are equally important.
Protecting the site comes down to two tasks you need to accomplish as the
site administrator.
1. Provide a way to restrict site access so that only authenticated users can
visit the site.
2. Make sure that the data transmitted between the Web user and the
Web server cannot be intercepted by a third party.
581
582 Chapter 8 Securing .NET Applications
The Windows operating system is designed in such a way that any action you
perform on the computer involves a security check. It follows that whenever
you are working inside the Windows environment you (the user) should have
an identity. This is your user account (or user name). These user names are
stored in a user accounts database.
The user accounts database can exist in two different areas. The first is
on the server itself. When a user attempts to gain access to this server, the
security check is performed against the database residing on the server. The
accounts in this database are referred to as local user accounts. The other
area in which the user accounts database may live is on a machine called the
primary domain controller (PDC). The job of the PDC is to authenticate
users on a local area network. This local area network may contain several
servers. Collectively, these servers are logically grouped into a domain. The
job of the PDC is to provide a centralized area for authentication to occur
for machines in the domain. If a user wishes to gain access to a particular
server’s resources within the domain, the user need only log into the PDC.
Windows determines what type of authentication to perform (local or on
a domain) by determining whether or not the user elected to log into a
domain.
8.1 Windows Security 583
missions set on the file will not include accounts in the Guests group.
Thus, the system will deny access.
IIS sees that the file, passwd.aspx, is protected from Guest access, so it
returns a 401 status code in the HTTP response. The 401 status code indicates
that password authorization is required to access the file.
The 401 HTTP status code triggers a password dialog box to appear in the
user’s browser. Now the user needs to send the user name and password infor-
mation. When this information is entered, the user name and password are
concatenated into a single string separated by a colon (:). This string is then
encoded using the Base64 encoding algorithm. The encoded string is placed
inside the HTTP header with the following request:
HTTP/1.1 200 OK
Server: Microsoft IIS/4.0
586 Chapter 8 Securing .NET Applications
equipped with fast Pentium processors can break a 40-bit key in a matter of
hours. The U.S. government’s concern with national security has now resulted
in the switch to 128-bit encryption. Even the most powerful computers on the
planet cannot crack this key within any reasonable time. Having more power-
ful encryption is important domestically as well. Currently, this is the only
method that can be used to ensure that credit card and bank account informa-
tion is kept private.
3. The sender encrypts a message using the public key and sends it to the
holder of the private key. Using the decryption algorithm, the receiver
uses the private key to decrypt the message.
The level of security that an encryption scheme offers relies on two factors:
(1) the continued secrecy of the private key and (2) the length of the keys.
Some weaker encryption schemes rely on a secret algorithm. These are never
good encryption schemes because the program used to implement the secret
algorithm is subject to reverse engineering. This would expose the process used
for encryption and decryption. The most popular public/private key encryption
scheme used is the RSA (from RSA Data Security, Inc., named after its cre-
ators, Ron Rivest, Adi Shamir, and Len Adelman). The RSA algorithm is com-
mon knowledge in the information technology world, but its strength comes
from the use of large keys that are impossible to crack using current hardware
in a reasonable amount of time. Incidentally, the RSA encryption algorithm is
used to uniquely identify the publisher of a strong named assembly.
Imports System
Imports System.IO
Imports System.Security
8.4 Implementing Data Encryption (System.Security.Cryptography) 591
Imports System.Security.Cryptography
Imports System.Text
Module Module1
Sub Main()
EncryptFile("test.txt", "Encrypted.txt")
DecryptFile("Encrypted.txt", "Decrypted.txt")
End Sub
m_bytKey = bytearrayinput
End Sub
m_bytIV = bytearrayinput
End Sub
End Sub
End Sub
Try
h cryptostream.Write(bytearrayinput, 0, _
bytearrayinput.Length)
cryptostream.Close()
i m_bytKey = RC2Prov.Key
m_bytIV = RC2Prov.IV
SaveKeyFile()
SaveIVFile()
8.4 Implementing Data Encryption (System.Security.Cryptography) 593
Catch E as CryptographicException
Console.WriteLine(E.Message)
End Try
End Sub
j ReadKeyFile()
ReadIVFile()
RC2Prov.EffectiveKeySize = 128
RC2Prov.Key() = m_bytKey
RC2Prov.IV = m_bytIV
End Sub
End Module
Property Description
BlockSize* Gets or sets the block size (in bits) of the cryptographic
operation
EffectiveKeySize Gets or sets the effective size (in bits) of the secret key used by
the RC2 algorithm
FeedbackSize * Gets or sets the feedback size (in bits) of the cryptographic
operation
Key * Gets or sets the secret key for the symmetric algorithm
KeySize ** Gets or sets the size (in bits) of the secret key used by the RC2
algorithm
LegalBlockSizes * Gets the block sizes that are supported by the symmetric
algorithm
LegalKeySizes * Gets the key sizes that are supported by the symmetric
algorithm
Mode * Gets or sets the mode for operation of the symmetric algorithm
Padding * Gets or sets the padding mode used in the symmetric algorithm
Property Description
<system.web>
<trace enabled="false"
requestLimit="10"
pageOutput="false"
traceMode="SortByTime"
localOnly="true" />
<sessionState
mode="InProc"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString=
"data source=127.0.0.1;user id=sa;password="
cookieless="false"
timeout="20"
/>
8.5 ASP.NET Authentication Security 599
<globalization
requestEncoding="utf-8"
responseEncoding="utf-8" />
</system.web>
</configuration>
As you can see, this is an XML file. The web.config file is used to store
security settings for an ASP.NET application. There are two particularly inter-
esting sections in the file (set in boldface type) that relate to using the Forms-
Based Authentication Provider: the <authentication> and <authorization>
tags. Here you can list specific users who will be allowed to access the site.
But first, let’s make the changes needed to configure the Forms-Based
Authentication Provider. Here are some modifications that set up the
initial configuration.
<authentication mode="Forms">
<forms name="Ch8-Auth"
path="/"
loginUrl="cs8-03.aspx"
protection="All"
timeout="20">
</forms>
</authentication>
validation of the ticket is useful for Web farm situations, where you want all
machines that are replicating content for the site to be able to validate and
decrypt tickets using common keys.
The timeout attribute specifies how long the authentication ticket is valid.
The time is expressed in minutes.
Now that we’ve configured Forms-Based Authentication, we need to spec-
ify some users to allow into the site. Let’s modify the web.config file again to
include user account information.
<authentication mode="Forms">
<forms name="Ch8-Auth"
path="/"
loginUrl="cs8-03.aspx"
protection="All"
timeout="20">
<credentials passwordFormat="Clear">
<user name="mcrouch" password="secret"/>
<user name="jsmith" password="secret"/>
</credentials>
</forms>
</authentication>
The <credentials> node set in boldface type contains the user accounts
information, which are pairs of user names and passwords. Notice the
attribute called passwordFormat. The value for this is Clear, which signifies
that the passwords assigned to each user in the <credentials> section are
stored in cleartext format. You can specify two other options: SHA or MD5.
These correspond respectively to the SHA and MD5 hash algorithms used to
encrypt passwords. For simplicity in this example, we store our passwords in
cleartext.
Let’s say we want to access the following page. The HTML code is shown
first, followed by the code-behind file.
<form id="Form1"
method="post"
runat="server">
<h1>Welcome
<asp:Label id=lblUser
runat="server">
</asp:Label>
!</h1>
<p>
<asp:Button id=btnLogOut
runat="server"
Text="Log Out">
</asp:Button>
</p>
</form>
</body>
</html>
Imports System.Web
Imports System.Web.Security
lblUser.Text = HttpContext.Current.User.Identity.Name
End Sub
FormsAuthentication.SignOut()
Response.Redirect("cs8-03.aspx")
End Sub
End Class
Now we need to construct a login Web Form. Here’s a simple login form
with an accompanying code-behind file.
<form id="Form1"
method="post"
runat="server">
<h1>Authorization Required</h1>
<p>User name:
<asp:TextBox id=txtUsername
runat="server">
8.5 ASP.NET Authentication Security 603
</asp:TextBox>
</p>
<p>Password:
<asp:TextBox
id=txtPassword
runat="server"
TextMode="Password">
</asp:TextBox>
</p>
<p>
<asp:Button id=btnLogin
runat="server"
Text="Login">
</asp:Button>
<asp:Label id=lblInvalidLogin
runat="server"
ForeColor="Red">
</asp:Label>
</p>
</form>
</body>
</html>
The login form is pretty straightforward. It contains two text fields (one for
the user name and one for the password), a submit button, and a Label Con-
trol to display an invalid login message. In the code-behind file, authentication
is performed when the user clicks the submit button.
Imports System.Web
Imports System.Web.Security
If FormsAuthentication.Authenticate(txtUsername.Text, _
txtPassword.Text) Then
FormsAuthentication.RedirectFromLoginPage( _
txtUsername.Text, False)
Else
lblInvalidLogin.Text = "Invalid Login. Try again!"
End If
End Sub
End Class
Property Description
FormsCookieName Returns the configured cookie name used for the current
application
FormsCookiePath Returns the configured cookie path used for the current
application
8.5 ASP.NET Authentication Security 605
GetAuthCookie(ByVal
username As String, ByVal
createPersistentCookie As
Boolean, ByVal
strCookiePath) As
HttpCookie
(continued)
606 Chapter 8 Securing .NET Applications
RedirectFromLoginPage
(ByVal username As
String, ByVal
createPersistentCookie
As Boolean, ByVal
strCookiePath As String)
SetAuthCookie(ByVal
username As String, ByVal
createPersistentCookie As
Boolean, ByVal
strCookiePath As String)
The cs8-02.aspx Web Form also contains a logout button. Inside the
event handler for the logout button we find this code.
FormsAuthentication.SignOut()
Response.Redirect("cs8-03.aspx")
End Sub
When the user clicks the button, the code calls the SignOut() method,
which expires the authentication ticket immediately. Then we use the
HttpResponse class Redirect() method to perform a client-side redirect
to the login page.
<system.web>
<authentication mode="Windows" />
<identity impersonate="true" />
<authorization>
<allow users="RMDEVBIZ01\Joe,RMDEVBIZ01\matt"
roles="RMDEVBIZ01\SpecialGroup" />
<deny users="*" />
</authorization>
</system.web>
</configuration>
8.6 Summary
Here’s a summary of the important points covered in this chapter.
■ Windows, IIS, and ASP.NET work in concert to implement secure
Web applications and services. Authentication and authorization work
at both the Windows and IIS layers of the Web application model.
■ Windows can secure many different types of resources. These include
but are not limited to files, directories, and services.
■ Any object on the Windows system, be it a file, service, or registry key,
contains privileges associated with it in access control lists (ACLs).
■ IIS provides authentication and authorization services using a variety of
schemes, including anonymous access, BASIC Authentication, Inte-
grated Windows Authentication, Digest Authentication, and authenti-
cation by IP address and/or domain.
■ Cryptography is the process of applying a mathematical formula to a
message in order to scramble it. The strength of a particular encryption
algorithm lies in the size of the keys used to encrypt the data. Encryp-
tion is the process of taking unencoded data (cleartext) and converting
it to scrambled data (ciphertext).
■ Symmetric cryptography involves the use of a single key for both
encryption and decryption of the data. Symmetric encryption algo-
rithms are a good choice for bulk data encryption since they tend to be
fast.
■ Asymmetric cryptography uses two keys; one for encrypting the data
and one for decrypting the data. The two keys are mathematically
related. Asymmetric cryptography is sometimes referred to as public-
key cryptography since the encryption key portion of the key pair,
called the public key, can be used by anyone to encrypt data intended
for the recipient. The recipient is the only keeper of the decryption
key, called the private key.
■ One-way hashes are used to generate a fixed-length digest of a vari-
able-length message. Hash algorithms are designed to produce unique
hash values for any given input. Generating hash values involves revers-
ing the roles of the public and private keys. The private key is used to
generate the message digest. An outside party can use the originator’s
public key to verify the authenticity of the hash. Hashes used in this
way are referred to as digital signatures.
610 Chapter 8 Securing .NET Applications
.NET Framework
Class Library
Reference Tables
This appendix contains the following tables, which provide information on the
methods and properties of classes in the .NET Framework Class Library. The
tables are listed below in alphabetical order by class name to assist you in find-
ing the information you want.
ArrayList class, methods of: Table A-2
ArrayList class, properties of: Table A-1
Directory class, methods of: Table A-20
DirectoryEntry class, methods of: Table A-26
DirectoryEntry class, properties of: Table A-25
DirectoryInfo class, methods of: Table A-22
DirectoryInfo class, properties of: Table A-21
DirectorySearcher class, methods of: Table A-28
DirectorySearcher class, properties of: Table A-27
EventLog class, methods of: Table A-24
EventLog class, properties of: Table A-23
File class, methods of: Table A-15
FileInfo class, methods of: Table A-17
FileInfo class, properties of: Table A-16
FileStream class, methods of: Table A-14
FileStream class, properties of: Table A-13
FileSystemWatcher class, methods of: Table A-19
FileSystemWatcher class, properties of: Table A-18
Hashtable class, methods of: Table A-8
611
612 Appendix A .NET Framework Class Library Reference Tables
Property Description
Capacity Gets or sets the number of elements that the array list can contain
Count Gets the number of elements actually contained in the array list
IsFixedSize Gets a value indicating whether the array list has a fixed size
IsSynchronized Gets a value indicating whether access to the array list is synchronized
(thread-safe)
BinarySearch(ByVal index
As Integer, ByVal count
As Integer, ByVal value
As Object, ByVal comparer
As IComparer) As Integer
CopyTo(ByVal array As
Array, ByVal arrayIndex
As Integer)
Appendix A .NET Framework Class Library Reference Tables 615
CopyTo(ByVal index As
Integer, ByVal array As
Array, ByVal arrayIndex
As Integer, ByVal count
As Integer)
GetEnumerator(ByVal index
As Integer, ByVal count As
Integer) As IEnumerator
(continued)
616 Appendix A .NET Framework Class Library Reference Tables
Sort(ByVal index As
Integer, ByVal count As
Integer, ByVal comparer
As IComparer)
Property Description
SyncRoot Gets an object that can be used to synchronize access to the stack
(continued)
618 Appendix A .NET Framework Class Library Reference Tables
Push Puts an object onto the top of the stack Push(ByVal obj As
Object)
Property Description
SyncRoot Gets an object that can be used to synchronize access to the queue
Appendix A .NET Framework Class Library Reference Tables 619
Property Description
(continued)
620 Appendix A .NET Framework Class Library Reference Tables
Property Description
Item Gets or sets the value associated with the specified key
Property Description
Property Description
AutoFlush Causes all output bound for the stream to be written immediately
when the value is True
NewLine (inherited Gets or sets the line terminator string used by the current
from TextWriter) TextWriter class
Appendix A .NET Framework Class Library Reference Tables 623
WriteLine(Char())
WriteLine(Decimal)
WriteLine(Double)
WriteLine(Int32)
WriteLine(Int64)
WriteLine(Object)
WriteLine(Single)
WriteLine(String)
624 Appendix A .NET Framework Class Library Reference Tables
WriteLine(UInt32)
WriteLine(UInt64)
WriteLine(String, Object)
WriteLine(String,Object())
Property Description
Handle Gets the operating system file handle for the file that the current
FileStream object encapsulates; used with COM interoperability
with unmanaged code
(continued)
626 Appendix A .NET Framework Class Library Reference Tables
(continued)
628 Appendix A .NET Framework Class Library Reference Tables
Open(ByVal path As
String, ByVal mode As
FileMode, ByVal access
As FileAccess) As
FileStream
Appendix A .NET Framework Class Library Reference Tables 629
Open(ByVal path As
String, ByVal mode As
FileMode, ByVal access
As FileAccess, ByVal
share As FileShare) As
FileStream
Property Description
CreationTime Gets the date and time the specified file was created (inherited from
FileSystemInfo)
LastAccessTime Gets the date and time that the specified file was last accessed
(inherited from FileSystemInfo)
LastWriteTime Gets the date and time that the specified file was last written to
(inherited from FileSystemInfo)
Form 2: CopyTo(ByVal
destFileName As
String, ByVal
overwrite As
Boolean) As
FileInfo
Open(ByVal mode As
FileMode, ByVal
access As FileAccess)
As FileStream
Open(ByVal mode As
FileMode, ByVal
access As FileAccess,
ByVal share As
FileShare) As
FileStream
(continued)
632 Appendix A .NET Framework Class Library Reference Tables
Property Description
Filter Gets or sets the filter used to determine what subset of files
to monitor for changes.
InternalBufferSize Sets the size (in bytes) of the buffer to use to store change
data. Should be a minimum of 4096 bytes (4K) and a
multiple of that value for best performance.
Delete(ByVal path As
String, ByVal recursive
As Boolean)
GetFiles(ByVal path As
String, ByVal
searchPattern As String)
As String()
GetFileSystemEntries
(ByVal Path As String,
ByVal searchPattern As
String) As String()
(continued)
636 Appendix A .NET Framework Class Library Reference Tables
Property Description
LastWriteTime Gets or sets the time when the current file or directory was last
written to (inherited from FileSystemInfo)
Property Description
MachineName Sets the name of the computer to read and write events to
Source Specifies the source name to register with the Event Log
SynchronizingObject Gets or sets the object used to marshal the event handler calls
issued as a result of an EventLog entry written event
CreateEventSource(ByVal
source As String, ByVal
logName As String, ByVal
machineName As String)
Delete(ByVal logName As
String, ByVal machineName
As String)
DeleteEventSource(ByVal
source As String, ByVal
machineName As String)
Exists(ByVal logName As
String, ByVal machineName
As String) As Boolean
GetEventLogs(ByVal
machineName As String) As
EventLog()
WriteEntry(ByVal source
As String, ByVal message
As String)
(continued)
640 Appendix A .NET Framework Class Library Reference Tables
WriteEntry(ByVal message
As String, ByVal type As
EventLogEntryType, ByVal
eventID As Integer)
WriteEntry(ByVal source As
String, ByVal message As
String, ByVal type As
EventLogEntryType)
WriteEntry(ByVal message
As String, ByVal type As
EventLogEntryType, ByVal
eventID As Integer, ByVal
category As Short)
WriteEntry(ByVal source As
String, ByVal message As
String, ByVal type As
EventLogEntryType, ByVal
eventID As Integer)
WriteEntry(ByVal message
As String, ByVal type As
EventLogEntryType, ByVal
eventID As Integer, ByVal
category As Short, ByVal
rawData() As Byte)
WriteEntry(ByVal source
As String, ByVal message
As String, ByVal type As
EventLogEntryType, ByVal
eventID As Integer, ByVal
category As Short)
WriteEntry(ByVal source
As String, ByVal message
As String, ByVal type As
EventLogEntryType, ByVal
eventID As Integer, ByVal
category As Short, ByVal
rawData() As Byte)
Appendix A .NET Framework Class Library Reference Tables 641
Property Description
SchemaClassName Gets the name of the schema used for this directory entry.
Username Gets or sets the user name to use when authenticating the
client.
642 Appendix A .NET Framework Class Library Reference Tables
CopyTo(ByVal newParent As
DirectoryEntry, ByVal
newName As String) As
DirectoryEntry
MoveTo(ByVal newParent As
DirectoryEntry, ByVal
newName As String)
Property Description
CacheResults Returns True if the results are cached on the client machine
ClientTimeout Sets the maximum amount of time (in seconds) for the client to
wait for results
PropertiesToLoad Gets the set of properties retrieved during the search (defaults to
the Path and Name properties)
PropertyNamesOnly Returns True if search results are to contain only values that are
assigned
ServerPageTimeLimit Sets the time limit the server observes to search an individual
page of results
ServerTimeLimit Specifies the maximum amount of time (in seconds) that the
server is allowed to search
Property Description
Method Description
Property Description
Property Description
(continued)
646 Appendix A .NET Framework Class Library Reference Tables
Property Description
BasePriority Sets the base priority for the queue that is used to route
messages.
FormatName Gets the unique queue name generated at the time of the
queue’s creation.
(continued)
648 Appendix A .NET Framework Class Library Reference Tables
Property Description
LastModifyTime Gives the date and time the queue’s properties were last
modified.
ReadHandle Sets the native handle used to read messages from the
queue.
BeginPeek(ByVal timeout
As TimeSpan, ByVal
stateObject As Object)
As IAsyncResult
BeginPeek(ByVal timeout
As TimeSpan, ByVal
stateObject As Object,
ByVal callback As
AsyncCallback) As
IAsyncResult
BeginReceive(ByVal
timeout As TimeSpan,
ByVal stateObject As
Object) As
IAsyncResult
BeginReceive(ByVal
timeout As TimeSpan,
ByVal stateObject As
Object, ByVal callback
As AsyncCallback) As
IAsyncResult
(continued)
650 Appendix A .NET Framework Class Library Reference Tables
PeekByCorrelationId
(ByVal correlationId As
String, ByVal timeout
As TimeSpan) As
Message
PeekById(ByVal id As
String, ByVal timeout As
TimeSpan) As Message
Receive(ByVal timeout
As TimeSpan) As
Message
Receive(ByVal timeout
As TimeSpan, ByVal
transaction As
MessageQueueTransaction)
As Message
ReceiveByCorrelationId
(ByVal correlationId
As String, ByVal
transaction As
MessageQueueTransaction)
As Message
ReceiveByCorrelationId
(ByVal correlationId As
String, ByVal timeout
As TimeSpan) As Message
(continued)
652 Appendix A .NET Framework Class Library Reference Tables
ReceiveByCorrelationId
(ByVal correlationId As
String, ByVal timeout As
TimeSpan, ByVal
transaction As
MessageQueueTransaction)
As Message
ReceiveById(ByVal id As
String, ByVal
transaction As
MessageQueueTransaction)
As Message
ReceiveById(ByVal id As
String, ByVal timeout As
TimeSpan) As Message
ReceiveById(ByVal id As
String, ByVal timeout As
TimeSpan, ByVal
transaction As
MessageQueueTransaction)
As Message
Send(ByVal obj As
Object, ByVal
transaction As
MessageQueueTransaction)
Appendix A .NET Framework Class Library Reference Tables 653
Send(ByVal obj As
Object, ByVal label As
String)
Send(ByVal obj As
Object, ByVal label As
String, ByVal
transaction As
MessageQueueTransaction)
SetPermissions(ByVal
user As String, ByVal
rights As
MessageQueueAccess
Rights)
SetPermissions(ByVal
user As String, ByVal
rights As MessageQueue
AccessRights, ByVal
entryType As Access
ControlEntryType)
654 Appendix A .NET Framework Class Library Reference Tables
Property Description
Active Indicates whether the TCP connection is still active (true/false value)
NoDelay Causes a delay to be invoked when send and receive buffers are full
if the value is set to True
SendTimeout Sets the send time-out value (in milliseconds) of the connection
Connect(ByVal address As
IPAddress, ByVal port As
Integer)
Connect(ByVal hostname As
String, ByVal port As
Integer)
Property Description
Active Gets or sets a value that indicates whether the listener’s socket has been
bound to a port and started listening
LocalEndpoint Gets the active end point for the local listener socket
Property Description
ContentLength Sets the content length (in bytes) of the request data
Method Determines the HTTP protocol method used for the request
(for example, GET, POST, HEAD)
RequestUri Gets the URI of the Internet resource associated with the
request when overridden in a descendant class
Create(ByVal requestUri
As Uri) As WebRequest
Property Description
Headers The collection of HTTP header name–value pairs from the response
ResponseUri The URI of the Internet resource that responded to the request
Properties Description
HasChildNodes* Gets a value indicating whether this node has any child nodes
Appendix A .NET Framework Class Library Reference Tables 659
Properties Description
InnerText* Gives the XML text representing the node and all its
children
InnerXml Gives the XML text representing the children of the current node
OuterXml* Returns the XML text representing the node and all its children
CreateAttribute(ByVal
qualifiedName As String,
ByVal namespaceURI As
String) As XmlAttribute
CreateAttribute(ByVal
prefix As String, ByVal
localName As String,
ByVal namespaceURI As
String) As XmlAttribute
CreateElement(ByVal
qualifiedName As String,
ByVal namespaceURI As
String) As XmlElement
CreateElement(ByVal
prefix As String, ByVal
localName As String,
ByVal namespaceURI As
String) As XmlElement
CreateNode(ByVal type
As XmlNodeType, ByVal
name As String, ByVal
namespaceURI As String)
As XmlNode
CreateNode(ByVal type
As XmlNodeType, ByVal
prefix As String, ByVal
name As String, ByVal
namespaceURI As String)
As XmlNode
(continued)
662 Appendix A .NET Framework Class Library Reference Tables
Load(ByVal txtReader As
TextReader)
Load(ByVal reader As
XmlReader)
(continued)
664 Appendix A .NET Framework Class Library Reference Tables
Save(ByVal filename As
String)
Save(ByVal writer As
TextWriter)
Save(ByVal writer As
XmlWriter)
Property Description
InnerText Specifies the concatenated values of the node and all its children
InnerXml Specifies the XML text representing the children of this node
GetAttribute(ByVal
localName As String,
ByVal namespaceURI As
String) As String
GetAttributeNode
(ByVal localName As
String, ByVal
namespaceURI As
String) As
XmlAttribute
HasAttribute(ByVal
localName As String,
ByVal namespaceURI As
String) As Boolean
RemoveAttribute(ByVal
localName As String,
ByVal namespaceURI As
String)
RemoveAttributeNode
(ByVal localName As
String, ByVal
namespaceURI As
String) As
XmlAttribute
(continued)
668 Appendix A .NET Framework Class Library Reference Tables
SetAttribute(ByVal
localName As String,
ByVal namespaceURI As
String, ByVal value As
String) As String
SetAttributeNode
(ByVal localName As
String, ByVal
namespaceURI As
String) As
XmlAttribute
Property Description
LocalName Gets the name of the current node without the namespace prefix
Property Description
CanResolveEntity Returns True if the reader can parse and resolve entities
Depth Returns the depth of the current node in the XML document
HasValue Returns True if the node can have the Value property set
IsDefault Returns True if the current node is an attribute and the value of
the attribute was generated from the default value defined in the
DTD or schema
(continued)
670 Appendix A .NET Framework Class Library Reference Tables
Property Description
LocalName Returns the name of the node minus the namespace prefix
Name Gets the qualified name (with namespace) of the current node
NamespaceURI Gets the namespace URI (as defined in the W3C Namespace
Specification) of the node on which the reader is positioned
Prefix Returns the namespace prefix associated with the current node
QuoteChar Returns the quotation mark character used to enclose the value
of an attribute node
GetAttribute(ByVal
name As String) As
String
GetAttribute(ByVal
localName As String,
ByVal namespaceURI
As String) As
String
MoveToAttribute
(ByVal name As
String) As Boolean
MoveToAttribute
(ByVal localName As
String, ByVal
namespaceURI As
String) As Boolean
(continued)
672 Appendix A .NET Framework Class Library Reference Tables
Property Description
Indentation Specifies how many IndentChars to write for each level in the hierarchy
when Formatting is set to Formatting.Indented
674 Appendix A .NET Framework Class Library Reference Tables
Property Description
(continued)
676 Appendix A .NET Framework Class Library Reference Tables
WriteRaw(ByVal
buffer() As Char,
ByVal index As
Integer, ByVal
count As Integer)
WriteStart
Document(ByVal
standalone As
Boolean)
(continued)
678 Appendix A .NET Framework Class Library Reference Tables
Property Description
Load(ByVal url As
String)
Load(ByVal stylesheet
As XmlReader)
Load(ByVal stylesheet
As XPathNavigator)
Load(ByVal stylesheet As
IXPathNavigable, ByVal
resolver As XmlResolver)
Appendix A .NET Framework Class Library Reference Tables 679
Load(ByVal url As
String, ByVal resolver
As XmlResolver)
Load(ByVal stylesheet
As XmlReader, ByVal
resolver As
XmlResolver)
Load(ByVal stylesheet
As XPathNavigator,
ByVal resolver As
XmlResolver)
Transform(ByVal
inputfile As String,
ByVal outputfile As
String)
Transform(ByVal input
As XPathNavigator,
ByVal args As
XsltArgumentList) As
XmlReader
Transform(ByVal input
As IXPathNavigable,
ByVal args As
XsltArgumentList, ByVal
output As Stream)
(continued)
680 Appendix A .NET Framework Class Library Reference Tables
Transform(ByVal input
As XPathNavigator,
ByVal args As
XsltArgumentList, ByVal
output As TextWriter)
Transform(ByVal input
As XPathNavigator,
ByVal args As
XsltArgumentList, ByVal
output As XmlWriter)
Property Description
SmtpServer The hostname of the SMTP server to use. If omitted, the IIS 5.0 SMTP
service running on the local machine is used.
Property Description
UrlContentBase The base URL to use for all relative links included in the body
of the e-mail message
UrlContentLocation Gets or sets the Content-Location HTTP header for the e-mail
message.
682 Appendix A .NET Framework Class Library Reference Tables
Property Description
683
684 Appendix B ADO.NET Class Library Reference Tables
Property Description
RecordsAffected Specifies the number of rows affected by the execution of the SQL
statement
Property Description
ConnectionString Specifies the connection string to use when opening an SQL Server
database
ConnectionTimeout Sets the maximum time (in seconds) to wait for a successful
connection to the database
DataSource Specifies the SQL instance to which to connect (configured with the
SQL Server Client Network Utility)
PacketSize Sets the size (in bytes) of network packets to use when
communicating with SQL Server
BeginTransaction(ByVal iso
As IsolationLevel) As
SqlTransaction
BeginTransaction(ByVal
transactionName As String)
As SqlTransaction
(continued)
686 Appendix B ADO.NET Class Library Reference Tables
BeginTransaction(ByVal iso
As IsolationLevel, ByVal
transactionName As String)
As SqlTransaction
Property Description
CommandText Identifies the SQL/Transact-SQL statement to execute
CommandTimeout Sets the maximum time (in seconds) to wait for the completion of a
command
Property Description
(continued)
688 Appendix B ADO.NET Class Library Reference Tables
Property Description
(continued)
690 Appendix B ADO.NET Class Library Reference Tables
Property Description
Offset Sets the offset to the Value property for binary and string types
Precision Sets the maximum number of digits used to represent the Value
property
Scale Sets the number of decimal places to which the Value property is
resolved
Size Sets the maximum size (in bytes) of the data within the column
SourceColumn Specifies the name of the source column that is mapped to the DataSet
object and used for loading or returning the Value property
SqlDbType Specifies the SqlDbType of the parameter (maps to SQL Server data
types)
Property Description
HasErrors Has a value of True if there are errors in any of the rows of the
DataSet object
Prefix Specifies the XML prefix that aliases the namespace of the
DataSet object
InferXmlSchema(ByVal
fileName As String, ByVal
nsArray() As String)
InferXmlSchema(ByVal
reader As TextReader,
ByVal nsArray() As
String)
InferXmlSchema(ByVal
reader As XmlReader,
ByVal nsArray() As
String)
Merge(ByVal dataSet As
DataSet)
Merge(ByVal table As
DataTable)
Merge(ByVal dataSet As
DataSet, ByVal
preserveChanges As
Boolean)
Merge(ByVal rows() As
DataRow, ByVal
preserveChanges As
Boolean, ByVal
missingSchemaAction As
MissingSchemaAction)
(continued)
696 Appendix B ADO.NET Class Library Reference Tables
Merge(ByVal dataSet As
DataSet, ByVal
preserveChanges As
Boolean, ByVal
missingSchemaAction As
MissingSchemaAction)
Merge(ByVal table As
DataTable, ByVal
preserveChanges As
Boolean, ByVal
missingSchemaAction As
MissingSchemaAction)
ReadXml(ByVal fileName As
String) As XmlReadMode
ReadXml(ByVal reader As
TextReader) As
XmlReadMode
ReadXml(ByVal reader As
XmlReader) As XmlReadMode
ReadXml(ByVal stream As
Stream, ByVal mode As
XmlReadMode) As
XmlReadMode
ReadXml(ByVal fileName As
String, ByVal mode As
XmlReadMode) As
XmlReadMode
Appendix B ADO.NET Class Library Reference Tables 697
ReadXml(ByVal reader As
TextReader, ByVal mode As
XmlReadMode) As
XmlReadMode
ReadXml(ByVal reader As
XmlReader, ByVal mode As
XmlReadMode) As
XmlReadMode
ReadXmlSchema(ByVal
fileName As String)
ReadXmlSchema(ByVal
reader As TextReader)
ReadXmlSchema(ByVal
reader As XmlReader)
(continued)
698 Appendix B ADO.NET Class Library Reference Tables
(ByVal reader As
TextReader, ByVal mode As
XmlWriteMode)WriteXml
(ByVal reader As
XmlReader, ByVal mode As
XmlWriteMode)
WriteXmlSchema(ByVal
fileName As String)
WriteXmlSchema(ByVal
reader As TextReader)
WriteXmlSchema(ByVal
reader As XmlReader)
Property Description
DataSet Returns the DataSet object that contains the DataTable object
DefaultView Returns the default view of the DataTable object; used for some
data-binding situations
Appendix B ADO.NET Class Library Reference Tables 699
Property Description
DisplayExpression Gets or sets the expression that will return a value used to
represent this table in the user interface
HasErrors Has a value of True if any rows in the data table contain errors
MinimumCapacity Sets the minimum number of rows (starting size) for the data table
Namespace Specifies the namespace for the XML representation of the data
stored in the DataTable object
Prefix Specifies the XML prefix that aliases the namespace of the
DataTable object
PrimaryKey Specifies the array of columns that make up the primary key for the
data table
(continued)
702 Appendix B ADO.NET Class Library Reference Tables
Select(ByVal
filterExpression As
String, ByVal sort As
String) As DataRow()
Select(ByVal
filterExpression As
String, ByVal sort As
String, ByVal As
recordStates
DataViewRowState) As
DataRow()
Property Description
AllowDBNull Has a value of True if database NULL values are allowed for this
column
AutoIncrement Has a value of True if a new unique number is generated for this
column when a new row is added
Property Description
Expression Specifies the expression used to filter rows, calculate the values in
a column, or create an aggregate column
Prefix Specifies the XML prefix that aliases the namespace of the
DataColumn object
ReadOnly Has a value of True if the column’s data can’t be changed once a
row has been created
Unique Has a value of True if the values in each row of the column must
be unique
Property Description
RowState Gets the current state of the row: Added, Deleted, Detached, Modified,
or Unchanged (DataRowState enumeration)
GetChildRows(ByVal
relationName As
String) As DataRow()
GetChildRows(ByVal
relation As
DataRelation, ByVal
version As
DataRowVersion) As
DataRow()
GetChildRows(ByVal
relationName As
String, ByVal version
As DataRowVersion) As
DataRow()
GetColumnError(ByVal
columnIndex As
Integer) As String
GetColumnError(ByVal
columnName As String)
As String
GetParentRow(ByVal
relationName As
String) As DataRow
GetParentRow(ByVal
relation As
DataRelation, ByVal
version As
DataRowVersion) As
DataRow
GetParentRow(ByVal
relationName As
String, ByVal version
As DataRowVersion) As
DataRow
GetParentRows(ByVal
relationName As
String) As DataRow()
(continued)
706 Appendix B ADO.NET Class Library Reference Tables
GetParentRows(ByVal
relation As
DataRelation, ByVal
version As
DataRowVersion) As
DataRow()
GetParentRows(ByVal
relationName As
String, ByVal version
As DataRowVersion) As
DataRow()
IsNull(ByVal
columnIndex As
Integer) As Boolean
IsNull(ByVal
columnName As String)
As Boolean
IsNull(ByVal column
As DataColumn, ByVal
version As
DataRowVersion) As
Boolean
SetColumnError(ByVal
columnIndex As
Integer, ByVal error
As String)
SetColumnError(ByVal
columnName As
String, ByVal error
As String)
SetParentRow(ByVal
parentRow As DataRow,
ByVal relation As
DataRelation)
Property Description
Property Description
Event Description
Property Description
AllowDelete Has a value of True if deletes from the DataView object are
allowed
AllowEdit Has a value of True if edits of the DataView object are allowed
AllowNew Has a value of True if new rows are allowed to be added to the
DataView object
RowStateFilter Specifies the row state filter with these values: Added,
CurrentRows, Deleted, ModifiedCurrent,
ModifiedOriginal, None, OriginalRows, and Unchanged
(DataViewRowState enumeration)
Property Description
Property Description
Printed Resources
Aitken, Peter G. 2002. XML —The Microsoft Way. Boston, MA: Addison-
Wesley.
Anderson, Richard, et al. 2001. Professional ASP.NET. Birmingham, U.K.:
Wrox Press.
Crouch, Matt J. 2000. Web Programming with ASP and COM. Boston, MA:
Addison-Wesley.
Thai, Thuan L., and Hoang Q. Lam. 2001. .NET Framework Essentials.
Sebastopol, CA: O’Reilly & Associates.
Tittel, Ed. 2000. XML for Dummies. Foster City, CA: IDG Books Worldwide.
Online Resources
Microsoft COM+ Web site, http://www.microsoft.com/complus.
Microsoft GotDotNet Web site, http://www.gotdotnet.com/.
Microsoft Internet Information Server Web site,
http://www.microsoft.com/windows2000/technologies/web/default.asp.
Microsoft MSDN Library Web site,
http://msdn.microsoft.com/library/default.asp (includes the Visual Basic
Language Reference and Design Guidelines for Class Library Developers
as part of the .NET Framework SDK documentation).
Microsoft .NET Web site, http://www.microsoft.com/net.
University of Illinois Common Gateway Interface Web site,
http://hoohoo.ncsa.uiuc.edu/cgi.
715
This page intentionally left blank
Index
Note: Italicized page locators ACID principles (Atomicity, Add Web Reference dialog
indicate tables/figures. Consistency, Isolation, and in console application for
Durability), 402 Palindrome Web Service,
ACLs. See Access control lists 483
Symbols
ActivationOption.Library, 420 selecting Add Web Reference
+, 24, 33, 285
ActivationOption.Server, 420 in console application for
&, 39, 285
Active Directory Services, 391 Palindrome Web Service,
%, 285
displaying contents of, 347–351 482
–, 24, 33
modifying contents of, 353–355 ADO, 494, 578
*, 24, 33, 38
providers used with, 347 ADO.NET, 256, 259, 578
/, 24, 33, 34, 285
searching contents of, 351–353 code, 423
^, 33
working with, 346–355 command parameters in, 503,
\ , 33, 34
Active Server Pages.NET. See 505, 506–508
=, 34, 37
ASP.NET data display with, 498–515
^=, 34
ActiveX Data Objects.NET. See DataGrid Control bound to,
*=, 34
ADO.NET 253
/=, 34
AdCreatedEventArgs object, 224 and enterprise data access, 535
\=, 34
AddAProduct() method, 489 as next generation data-access
+=, 34
AddHandler statement, 341 technology, 494–495
–=, 34
Add() method, 158, 316 ADO.NET Class Library
&=, 34
AddNewInventory(), 567 reference tables, 683–713
<, 37
Add New Item dialog box, 200, ADO.NET programming
<=, 37
201, 573 objects/architecture,
>, 37
AddNewProduct(), 567 495–497
>=, 37
AddNewProduct() subroutine, DataSet class, 496–497
<>, 37
549 .NET Managed Data Provider,
AddPhrase() function, 310 497
Abandon method, 296 AddRange() function, 304 AdRotator Control, 221–226,
AcceptChanges(), 555, 556 Add Reference dialog, and 298
AcceptTcpClient(), 365 VB.NET class library, 407, adding to XYZ Corporation
Access control lists, 609 409 home page, 273
Access modifiers, VB.NET, AddtoOrder Test Web Form, in .aspx file, 224
55, 56 445–446 properties of, 222
717
718 Index
AdRotator Control example, Array lists, 252, 391 shared Web Control properties
output of, 226 Arrays, 30–31, 302 in, 147–149
Advanced Web Services, making, ASCII character set, 26 simple application
487– 489 ASCII text files, 316 configuration with, 94
AdvertisementFile property, 221 ASC keyword, 560 simple application created in,
Advertisement files, sample of, As clause, 56 196–208
223 .asmx file, 462 StateBag object and saving
Algorithms in console application for state in, 279–281
Base64 encoding, 585, 586 Palindrome Web Service, TextBox Control in, 170–175
bubble sort, 83 481 User Controls in, 274–279
encryption, 609 Imports statement in, 487 Validation Controls in, 227–246
one-way hash, 589 in Palindrome Web Service, Web Controls for creating
RC2, 590, 595, 610 472, 473 buttons in, 164–169
SHA hash, 600 ASP Web Controls used in, 147–164
Aliases, for namespaces, 212 ASP.NET backward and Web Forms, 8
allow node, 608 compatibility with, 95 Web Services part of, 462
AlternatingItemStyle, 262 and ASP.NET intrinsic objects, XYZ Corporation home page,
<alt> tag, 120 281 266–274
Ampersand character (&), name- ASP.NET, 2, 90 ASP.NET applications, compiled
value pairs delimited with, advanced session and code in, 297
285 application state ASP.NET authentication security,
AND truth table, 35 management with, 94–95 597–608
Anonymous access, IIS, 584–585 anatomy of pages in, 95–102 Forms-Based Authentication
APIs. See Application application configuration in, Provider, 597–607
Programmer’s Interfaces 108–109 Microsoft Passport
AppendChild() method, 374 application deployment with, 94 Authentication Provider, 608
ApplicationActivation attribute, backward compatibility with Windows Authentication
420 ASP, 95 Provider, 607–608
Application domains, 400 CGI compared with, 4–5 ASP.NET class, compiling, 96
Application Log, in Event Viewer, and code-behind feature, ASP.NET HelloWorld
342 107 application, building and
Application object, and state code structure of, 95–99 running, 205, 206, 207, 208
management in Web compiled code with, 93–94 ASP.NET intrinsic objects,
Services, 490 components of, 5 281–297, 298
Application variable, retrieving Data List Controls in, 246–265 HttpApplicationState object,
value of, 293 features of, 93–95 292–293
Archive flag, 332 HTML controls in, 109–147 HttpRequest object, 281–284
Arithmetic operators, in VB.NET, HTTP support with, 95 HttpResponse object, 285–289
24, 32–33 Hyperlink Control in, 195–196 HttpServerUtility object,
ArrayList, data binding to Web Image Control in, 196 289–292
Controls using class objects intrinsic objects, 281–297 HttpSessionState object,
and, 185 List Controls in, 190–195 293–296
ArrayList array, sorting items in, overview of, 7–8 ObjectContext object, 296–297
307 page directives in, 209–212 ASP.NET page directives, 97,
ArrayList class, 302–308 pages, 5, 297 209–212
methods of, 614–617 rich controls in, 213–226 @ Assembly directive, 212
properties of, 613 security with, 95, 582 @ Control directive, 209
ArrayList object, 187, 188, 304 Selection Controls in, 175–189 @ Import directive, 211
Index 719
ASP.NET page directives, 209 code for Product class, HTMLInputImage Control
for binding data to DataList 417–419 example, 132–133
Control, 262–263 CreateOrder Component Test HTMLInputRadio Control
CMyItemClass, 186 Web Form, 443–444 example, 134–136
and database access to SQL CustomValidator Control and HTMLInputText Control
Server, 510 CreditCardCheck, 244–245 example, 138–139
DataGrid Control, 256 data displayed in DataGrid HTMLSelect Control example,
editing for Web Forms, 204 Control, 508–510 141–142
event handler for data encryption HTMLTable Control example,
SelectionChanged event in, implementation, 590–593 143–145
220 DataGrid Control, 253–254 HTMLTextArea Control
Global.asax.vb, 108–109 data integrity with example, 146–147
IsCreditCardValid() function, DataRelation class, 563–566 ICreateOrder (namespace
245 DataList Control placed on Supermarket), 423–428
and login Web form, 603–604 Web Form, 260–261 Internet e-mail, 389–390
NotImageFileException, DataSet object and DataTable IReceiveOrder (namespace
528–534 objects creation, 544–546 Supermarket), 435–439
Palindrome Web Service, 473 Dim WithEvents objList as IUpdateInventory (namespace
for photo gallery application CNumberList, 86–88 Supermarket), 428–434
Web Form, 521 directory contents access, 336 Label Control, 150–151
Product Component Test Web event log, 343–345 ListBox Control, 190–192
Form, 441– 442 file-watching, 338–339 Load() method used for
ReceiveOrder Component Test free-threading, 80–81 processing XML data,
Web Form, 449– 451 function listing structure 375–376
server-side validation in, 243 members at runtime, 398 login form with code-behind
TextBox Control, 173 GasolineEngine class, 57–59 file, 602–603
and Web button controls, 168 global and local variables, manual database transaction,
WebControlPanel, 156–157 28–29 568–570
Code-behind modules, 107 Hashtables, 313–315 maximum/minimum value and
in Label Control example, 153 HTMLAnchor, 112–113 CompareValidator Control,
for Web Forms, 103, 105, 106 HTMLButton Control 233–234
Code labels, 50 example, 115 MyBase.DisplayInfo(), 64
Code samples HTML code for page access, obtaining directory
AddToOrder Test Web Form, 601–602 information, 334–335
445– 446 HTML for page querying user, overridden function, 64
AdRotator Control, 224–225 176–177 Page_Load and Page_Unload
ArrayList, 303–304 HTMLGenericControl events, 101
authors table queried in pubs example, 116–117 Panel Control, 155–156
SQL Server database, HTMLImage Control example, PasswordConfirm User
499–500 118–120 Control, 278
Calendar Control in HTML HTMLInputButton Control polymorphism of interfaces,
form, 218–219 example, 122 78
CheckBoxList Control, HTMLInputCheckBox Control print queues and Queue class,
182–183 example, 123–124 310–312, 313
checking for specific value with HTMLInputFile Control Product Component Test Web
CompareValidator Control, example, 126–128 Form, 440–441
231–232 HTMLInputHidden Control querying for information about
CNumberList class, 83–85 example, 130–131 computer, 348
722 Index
Common Type System, 457 Constructors, 57, 59–60 CType() function, 305, 515
data types, 395 Constructor strings, 421 CustomValidator Control,
CompareTo() method, 305 specifying in Component 240–246
CompareValidator Control, Services, 422 properties of, 242
230–234 Container keyword, 252 cvMagicNumber, 232
ErrorMessage property of, 277 Container objects, 346
properties of, 231 ContainsKey() method, 316 Data, 24
CompareValidator Controls, 275 Content, and code-behind adding to DataTable object,
Comparison operators, in feature, 107 549–550
VB.NET, 37–38 ContextUtil object, 423 binding to DataGrid Control,
Component-based software @ Control directive, 209 258
systems, limits with, 460 <%@ Control %> directive, 276, binding to DataList Control,
Component Object Model, 11, 278 262–263
71, 401, 457, 460, 494 @ Control page directive, displaying in DataGrid Control,
Component “plumbing” code, attributes used for, 210–211 508–514
409– 410 ControlToValidate property, 228, displaying in DataTable object,
Components, 274, 392, 393, 457, 242 550–551
460 Cookies, 285, 598 displaying in grid format, 253
described, 9–10 Cookies Collection editing in DataGrid Control,
roles assigned to, in attributes of, 290 514–516
Supermarket application, in HttpResponse object, 289 filtering and sorting with
456 CopyTo() method, 332 DataView class, 556–561
serviced, 393 CORBA, 460 HTMLSelectControl bound to,
Component Services, constructor CreateCommand() method, 501 140
string specified in, 422 CreateElement() function, 373 in-place editing of, 259
Component Services Console, CreateEncryptor() method, 595 “scraped,” 493
420, 421 CreatePublicQueue() function, separating from presentation,
Computer column, in Event 356, 357 with Web Services, 461–462
Viewer, 342, 343 CreateTextNode() method, 374 Web Controls for
Concatenation operators, 39 CreateXMLDocument() displaying/formatting,
Conditional processing, 42– 44 function, 373 149–163
If . . . then . . . else statements, CreationTime property, 335 Data access, 535
42– 43 credentials node, 600 universal, 494
Select Case statements, 43– 44 CRocketLauncher class, 77 on the Web, 491–494
Connection class, in .NET Cryptography, 587–590, 609 DataAdapter class, in .NET
Managed Data Provider, 497 asymmetric, 609 Managed Data Provider,
Connection string syntax, 500 digital certificates, 589–590 497
Connect() method, 361 digital signatures, 589 DataAdapter interface, 554
Consistency, 402, 457 hashes, 589 DataAvailable property, 365
Console.ReadLine() statement, public key, 588–589, 609 Database management systems,
90 symmetric, 588, 609 403, 492
Console.WriteLine() statement, CryptoStream class Database transactions, manual,
90 methods of, 596 567–570
Constants, 24, 32 properties of, 596 DataBind(), 250, 258, 263
Constraint class, 561 CryptoStream object, 595, 596, Data binding, 182, 188, 508
Constraints, 561, 568 597 to Repeater Control, 249, 250
ConstructionEnabled attribute, CSS. See Cascading Style Sheet to Web Controls using class
421, 423 CTS. See Common Type System objects and ArrayList, 185
724 Index
Data Collections DataRelation class, 491, 561, 578 DataTable object, 491, 535, 540,
(System.Collections), using, and DataSet class, 497 549, 560, 570, 578
302–316 maintaining data integrity with, in ADO.NET, 256
DataColumn, and DataSet class, 561–567 creating, 544–546
496 method of, 562, 712 data added to, 549–550
DataColumn class, 546, 578 properties of, 562, 712 data displayed in, 550–551
properties of, 547–548, DataRelationCollection object, and DataSet class, 496
702–703 and DataSet class, 497 DataTextField property, 187
DataColumnCollection, 546, 570 DataRelation object, 566 Data types, 9, 90
and DataSet class, 496 DataRow class, 578 converting, 31–32
DataColumn objects, 548, 549, and DataSet class, 496 of variables in VB.NET, 24
578 methods of, 704–707 Data validation, 227, 237
DataColumns, 258 properties of, 703 DataValueField property, 187
Data encryption, implementing, DataRowCollection class, 570 DataView class, 560
590–597 DataRowCollection object, and data filtered and sorted with,
datafield, 258 DataSet class, 496 556–561
DataGridCommandEventArgs DataRow object, 256, 258, 549, methods of, 557–558, 711
object, 514 550, 570, 578 properties of, 556–557, 710
DataGridCommandEventArgs DataRowView object, 561 DataView objects, 496, 508, 560,
parameter, 514 DataSet class, 495, 496–497, 571, 561
DataGrid Control, 247, 253–259, 578 DataViews, 253
298, 578 methods of, 536–540, 694–698 Date column, in Event Viewer,
code for editable, 511–514 properties of, 535–536, 693 342, 343
data displayed in, 508–514 DataSet information, displaying, Date data type, 27
editing data in, 514–516 548–549 Date information, and Calendar
programming with, 516–534 DataSet objects, 491, 496, 497, Control, 213
properties of, 255–256 535, 554, 570, 578 Dates, displaying in XYZ
revisiting, 508 creating, 544–546 Corporation home page,
valid controls for Columns EnforceConstraints property 273–274
Collection of, 259 of, 567 Date values, specifying, 32
DataGrid Control example, filling with values, 555 DBMS. See Database
output of, 260 loading and updating with management system
Data integrity, maintaining with IDataAdapter interface, DbType, 507, 508
DataRelation class, 561–567 551 DbType.Boolean, 508
DataItem, within RepeaterItem typed, 570, 571 DbType.String value, 507
class, 252 Data set types, 302 DCOM. See Distributed COM
DataKeyField, 510 DataSource property, 250, 258, Dead–letter queues, 356
Data Link Properties dialog, 572 264, 511 Decimal data type, in VB.NET,
DataList Control, 247, 298 Data sources, 182 26
placing on Web Form, 260–261 DataTable class, 258, 548, 570, Declarative role-based security,
programming with, 516–534 578 12
DataList Control example, output methods of, 542–544, 700–702 Decryption, 609
of for displaying images, 265 NewRow() method of, 549 Decryption keys, 587
DataList Controls, 246–265 properties of, 541–542, Delegates, in Common Type
Data lists, generating with 698–699 System, 395
ASP.NET, 246 DataTableCollection, 546, 549 Delete() method, 333
DataReader class, in .NET DataTableCollection object, and deny node, 608
Managed Data Provider, 497 DataSet class, 496 Dequeue() method, 312
Index 725
Dequeuing messages, 358 Display Selection button, 140 Dynamic setting, for Display
Derived classes, 60, 62 Distributed applications, and property, 229
DESC keyword, 560 Web services, 10–11 Dynamic Web pages, 93, 102
Desktop computers, 492 Distributed COM, 460
Destructors, 57, 60 Distributed software systems, and EditCommand event, 514
DictionaryEntry object, 252 Web Services, 459 EditItemIndex property, of
Digest Authentication, 587, 609 Dithering, 154 DataGrid Control, 514
Digital certificates, 589–590 DivideByZeroException, 51 EditItemTemplate command, in
Digital signatures, 589, 609 Division operator (/), in VB.NET, photo gallery application,
Dim command, 24, 27, 60 24 518, 526
Dimensionality, in arrays, 30 .dll files, 394 <EditItemTemplate> tag, 510
Dim WithEvents, 86 DLLs. See Dynamic link libraries EffectiveKeySize property, 595
Directories DocRecord class, 312 e.Item.ItemIndex, 514
creating, moving, and Document declarations, in XML Element nodes, 381
renaming, 333–334 files, 381 Elements, in arrays, 302
examples of, 346 DocumentElement property, Else clause, in If . . . then . . . Else
Windows security for, 583 373 statements, 42, 43
Directory class, 333, 334 Document Object Model ElseIf clause, in If . . . then . . .
methods of, 634–636 standard, 370 Else statements, 42
Directory contents, accessing, 336 Document Type Definition, 374, e-mail, 2
DirectoryEntry class, 352, 353 377 e-mail addresses
methods of, 642 Do keyword, 44 checking, 238
properties of, 641 Do . . . loops, 46 enabling entry of, in XYZ
DirectoryEntry object, 349, 352, DOM, 391 Corporation home page, 272
354 Domain names, authentication validating in XYZ Corporation
DirectoryInfo class, 333, 334 by, 587, 609 home page, 270
methods of, 637 DOM standard. See Document e-mail systems, as store-and-
properties of, 636 Object Model standard forward communication
DirectoryInfo object, 334 Done() event, 88, 89 type, 355
DirectoryInfo properties, 335 Dot (.) operator, 57 Embedded metadata, 10
Directory information, creating Double data type, in VB.NET, Embedded SQL, 493, 578
and getting, 334–335 26 Encoding.ASCII class, 361, 362
DirectoryName property, 333 Do Until, 46 Encryption, 587, 588
DirectorySearcher class, 352, 353 Do While, 46 algorithms, 609
methods of, 644 Down-level browsers, and implementing data and,
properties of, 643 validation code placement, 590–597
Dir() statement, VB.NET, 263 240, 241 EndEdit() function, 555
.disco file, 470 DropDownList Control, 184, End keyword, 40
disco namespace, 471 194–195, 231, 232, 235 EnforceConstraints property, of
Discovery files, 470 DTD. See Document Type DataSet object, 567
<discoveryRef> tag, 471 Definition Enqueue() method, 312
discovery root element, of Durability, 402 Entity references, 381
discovery file, 471 Dynamic arrays, 302, 391 Entries, checking against single
DisplayInfo() function, 63 Dynamic discovery, 459, 470, 471, values, 230
output of furniture class demo 490 Entries.Count property, 345
with call to, 66 Dynamic HTML, 8, 213 EntryType property, 345
DisplayNode() function, 376 Dynamic link libraries, 6, 394, Enumerated value types, in
Display property, 229 401 Common Type System, 395
726 Index
ErrMessage property, declaring, ExecuteReader() method, 511 FileStream object, 596, 597
277 EXEs. See Executables binary file I/O used with,
Err object, 50 Exists() method, 345, 357 322–324
Error handling, 48 Exists property, 332 methods of, 323–324
unstructured, 49–50, 51 Exit statements, 44–45, 46 properties of, 322
Error logging, 342 Explicit conversion, 31, 32 FileSystemEventArgs object
ErrorMessage text, colors for, 229 eXtensible Markup Language, 11, variable, 341
Event-based programming 13, 222, 391, 489 File systems, watching for
models, 102–103 and ADO.NET, 495 changes, 337–342
Event-based thread and data for List Controls, 246 FileSystemWatcher class, 337
synchronization program, files, 94 methods of, 340, 633
output from, 89 and Web Services, 460–461 properties of, 339, 632
Event column, in Event Viewer, Extensible Stylesheet FileSystemWatcher object, 339,
342, 343 Transformation, 384, 392 340, 341, 391
Event-driven applications, 8 Extensions, ISAPI, 6 File Transfer Protocol, 2
Event handlers IIS support for, 6
client-side, 173 File Allocation Table (FAT), File watching, 337–342
for SelectionChanged event, 583 Fill() method, 555
220 File attributes, obtaining, 332 Filters, ISAPI, 6–7
Event-handling procedures, 88 File class, 316, 317, 331, 333 Finallyblock, 52
Event Log, 342 methods of, 627–629 FindControl() method, 515
EventLog class FileInfo class, 331, 333, 335 Find() method, 561
methods of, 638–640 methods of, 630–632 Fingerprinting, 581
properties of, 638 properties of, 630 Firewalls, 11, 460, 495, 586
EventLogEntry objects, 345 FileInfo object, 332, 336 First-in-first-out (FIFO), 302,
EventLog object, 342, 345 File information retrieval, 310, 391
EventLog sample program, 331–332 Fixed-length files, 492
output of, 346 File/object security, 583 Flat files, 492
Events File operations, performing, data conversions from, to XML,
bubbled-up, 165 331 374
of Calendar Control, 219, 220 File permissions, 129 and data for List Controls, 246
of ObjectContext object, 297 File posts, encoding scheme for, Flow control statements, 42,
selecting for code-behind 128 44–48
editing, 205 Files Exit statements, 44–45
TextBox Control response via, copying, moving, and Goto statements, 45
170 renaming, 332–333 Flush() method, 320, 330
and thread synchronization, 83, copying for XYZ Corporation Font class, 154
85–89 home page, 266–267 Fonts
Event Viewer, 343 deleting, 333 adjusting with shared Web
launching, 342 discovery, 470 Control properties, 147
Exception exception, 51 flat, 492 in photo gallery application,
Exception handling, structured, uploading with 534
51–53 HTMLInputFile Control, Footers, list, 247
Exceptions, throwing, 52 126 FooterStyle, 262
<exclude> tag, 471 Windows security for, 583 For . . . Each loops, 185, 336
Executables, 5, 6 FileStream class For Each . . . Next loops, 48
ExecuteNonQuery() method, 515 methods of, 625–626 ForeColor property, 229
ExecuteReader() command, 501 properties of, 624 Foreign keys, 561, 568
Index 727
name attribute, 134, 599 sending Internet e-mail, 301, inheritance, 60–62
Names and naming 387–391 interfaces, 71–75
of variables in VB.NET, 24 XML data handling, 301, overloading, 67–68
of Web Controls, 202, 203 370–387 overridden functions, 63–67
Namespaces, 346 .NET Framework SDK, data polymorphism, 68–70
aliases for, 212 encryption classes in, 590 polymorphism implementation
defining in VB.NET, 406 .NET Managed Data Provider, with interfaces, 75–79
Name-value pairs, 281, 285 495, 497, 498, 499, 578 Object-oriented software reuse,
Native code applications, 394 .NET My Services, 13, 14 401
NDS. See Novell Directory .NET platform, 2 Object pooling, 12, 404, 412, 457
Services Netscape Navigator, 2 Objects
.NET .NET Web Services, 90 COM, 401
COM+ Component Services NetworkStream object, 361, 365 instances of, 59
and, 12 New command, 59, 60, 143, 160 in object-oriented
directions and plans for, 12–14 New Project dialog, 20 programming, 53
.NET classes, and COM+ New Project window, 198 self-describing, 9
Component Services, 405 NewRow() method, 549 Object type, 27
.NET Common Language New() subroutine, and ODBC. See Open Database
Runtime, 8–9 component instantiation, 410 Connectivity
.NET Framework, 17, 71, 93, 394 Nodes ODBC.NET Managed Data
and COM+ Component in Active Directory Services, Provider, 497
Services, 401 349 OldFullPath property, 341
components of, 5 allow, 608 OLE-DB.NET Managed Data
Data Providers with, 497 credentials, 600 Provider, 497
and extensibility of class deny, 608 OLE (Object Linking and
libraries, 571 locating, 392 Embedding)-DB, 494, 578
free-threaded applications in, in XML files, 381 OnAdCreated event, 224
80 Nodes XmlNode List object, 376 OnClick property, 165, 166
language independence in, 11 NodeType property, 376, 381 One-dimensional array, with five
managed components in, 9–10 NotEqual comparison, 232 elements, 30
and proxy class code, 481 Not equal to operator (<>), 37 On Error Goto statement, 50
and Web Services, 459, 462, NOT truth table, 35 One-way hash algorithm, 589
489 Novell Directory Services, 347 One-way hashes, 609
.NET Framework Class Library, NT File System (NTFS), 583 OnRenamed() event handler, 341
5, 9, 90 Null references, 382 OnRowUpdated() subroutine,
Active Directory Services, Numeric data types, in Visual 555, 556
346–355 Basic.NET, 25 OnServerChange event, 140
and ADO.NET, 495 OnServerClick event, 140
common features of, 301 ObjectContext object, 296–297 OnServerClick event-handler
Data collections, 301, 302–316 events of, 297 code, 113
event logging, 301, 342–345 methods of, 297 OnServerClick procedure, 112
file input/output, 301, 316–336 Object-oriented languages, 9 OnTextChanged event, 170, 172,
file system changes, 337–342 Object-oriented programming, 173
Internet communication, 301, 17, 45, 53–79, 90 OOP. See Object-oriented
358–370 class basics, 53–56 programming
message queuing, 301, class properties, 56–57 Open Database Connectivity,
355–358 constructors and destructors, 493–494, 578
reference tables, 611–682 57–60 Open() method, 501
732 Index
OpenText() method, 317, 331 stub code for, 474 Placeholders, for Web Controls in
Open With dialog, in Palindrome testing IsPalindrome() Web XYZ Corporation home
Web Service, 473 method, 477 page, 269
Operator property, NotEqual test page, 476 Point() method, 154
comparison in, 232 Panel Control, 154–158, 449, Polymorphism, 9, 90
Optional keyword, 41 451 implementing by using
Optional parameters, 41– 42 Panel Control example, output of, interfaces, 75–79
Option Compare Binary 159 inheritance, 70
statement, 38, 39 ParameterDirection.Input, output of demo, 71
Option Compare Text statement, 507 overview of, 68–70
38 ParameterName property, 507 Pop() function, 310
Oracle, 497 Parameters, for subroutines, 41 POST, HTTP, 468, 490
OrderDetails table, 451 Parent controls, and bubbled-up Post-backs, 140
column names and data types events, 165 and CompareValidator Control,
for, 414 PasswordConfirm User Control, 231
Orders Table, column names and 275, 277, 278 and ImageButton Control,
data types for, 414 passwordFormat attribute, 600 165
Ordinal index, 302 Passwords and LinkButton Control, 166
OR truth table, 35 and authentication, 581 and RequiredFieldValidator,
OtherWebService.disco, 471 and BASIC Authentication, 229
@ OutputCache directive, 212 586 and reset buttons, 121
Overloading, 67–68, 90 and Integrated Windows and TextBox Control, 170
Overridden functions, 63–67 Authentication, 586 and TextChanged event, 175
storing, 600 POST command, 4
Packages, 403 path attribute, 599 PostedFile object, 129
Packets, 2–3 Pattern-matching characters, in POST mechanism, and
PadRight() method, 330 VB.NET, 38 HTMLForm Control, 111
Page, and .aspx file, 96 PDAs. See Personal digital POST request, 6
Page class, 96, 100–101, 106 assistants Preserve keyword, 30, 31
@ Page directive, 209 PDCs. See Primary domain Primary domain controllers,
attributes used for, 210–211 controllers 582
Page directives, ASP.NET, 97, Peek() method, 310 PrimaryKey property, 548
209 PERL, regular expressions used Primary keys, setting for table,
Page events sample code, output in, 237 548
of, 102 Permissions, and security rights, Primitive data types, and
Page_Init, 106 583 VB.NET equivalents, 396
Page_Load, 106 Personal digital assistants, 12 Primitive types, in Common Type
Page_Load event, 100, 101, 113, Internet sites accessed with, System, 395
120, 157 461 Privacy protections, 581
Page_Unload event, 100, 101 Web services data delivery for, Private access modifier, 55, 56
PalindromeTester, class view of, 11 Private keys, 420, 588, 609
484 Personal information Private queues, 356
Palindrome Web Service management software, 13 Procedural security, 405
console application for, PIM software. See Personal Product class, 416, 417–419, 421,
481– 485 information management 489
creating, 472– 478 software Product component, 442, 487
Open With dialog, 473 Pixel dithering, 154 Product Component Test Web
proxy class for, 479– 480 Pixel() method, 154 Form, 440–441
Index 733
Product table, 548, 561 PubsDS class, class view showing, References folder
column names and data types 575 in Solution Explorer, 451
for, 414 Push() method, 310 and VB.NET class library, 407,
DataRow object added to, 549 pwd values, 500 408
Program flow control, 42– 48 Refrigerators, Internet sites
conditional processing, 42– 44 Queue class, 310–313 accessed with, 461
flow control statements, 44– 45 methods of, 619 @ Register directive, 211–212
loops, 46– 48 properties of, 618 Registry keys, Windows security
Programming Queued components, 12, 404 for, 583
multithreaded, 79–89 Queues, 302, 391 Regular Expression Editor
structured, 53. See also Object- creating, 356–357 opening, 238
oriented programming messages sent to, 357 VS.NET, 239
Programs types of in MSMQ, 356 Regular expressions, 237
event-based thread Quizlets, 267 RegularExpressionValidator
synchronization, 86–88, 89 Control, 237–240, 270
GasolineEngine, 57–59. See also RadioButton Control, 180 RejectChanges(), 556
Code; Code samples; Labs RadioButtonList, placing in XYZ Relational database management
Progress() event, 88, 89 Corporation home page, 271 systems, 492
Properties, and VB.NET RadioButtonList Control, 180, Relational databases, and data for
managed component 181, 182, 184, 188–189 List Controls, 246
development, 411 demonstration of, 188–189 Remote procedure calls, 460
Properties collection, 355 properties of, 181–182 RenamedEventArgs object, 341,
Properties window, 203 in XYZ Corporation home 342
activating, 202 page, 267, 269 Repeater Control, 247–265, 262
PropertyCollection class, 355 Radio buttons, 134, 175 templates used in, 248
PropertyCollection object, 349 RaiseEvent statement, 86 Repeater Control example,
Property keyword, 44, 56, 57 RangeValidator Control, 234–237 output of, 251
PropertyNames property, 349 properties of, 235 RepeaterItem class, 252
Property Pages dialog, in RC2 algorithm, 590, 595, 610 RequiredFieldValidator Control,
VB.NET class library, 406, RC2 class, 594 228–230, 238, 245
408 RC2CryptoServiceProvider class, RequiresNew option, 487
Property tags, 262 597, 610 Reset buttons, 120, 121
Proprietary database APIs, 493 methods of, 595 Resizing, dimensions of arrays,
Protected access modifier, 55, 56 properties of, 594 30–31
Protected Friend access modifier, RC2CryptoServiceProvider Retinal scans, 581
56 object, 593, 595, 597 Reuse of code, 60
protection attribute, 599 Readability of code, improving, Reverse() method, 307
Proxy classes, Web Services 39 RGB values, 158
created with, 478– 481 ReadApplicationLog() Rich applications, with ASP.NET,
Public access modifier, 55, 56 subroutine, 345 93
Public-key cryptography, Reading Rich controls, ASP.NET, 213–226
588–589, 609 binary files, 324–328 Rich data-editing features, 259
Public keys, 420, 588 text files, 316–317 Role-based security, 412
Public keyword, 55 Read() method, 328, 361, 502 with COM+, 405
Public queues, 356 ReadToEnd() method, 317 with COM+ Component
pubs database, 568 Receive() method, 358, 451 Services, 12
Server Explorer dialog showing Recursion, and stacks, 302 console application for testing,
tables of, 573 ReDim statement, 30 454
734 Index
SmtpMail class, 387, 391 SqlDataReader object, 501, 503, Statelessness, 3, 100
method of, 368, 680 578 State management
property of, 368, 680 SQL INSERT command, 515 in ASP.NET, 94–95, 99–100
sn.exe, 420 SQL INSERT statement, 527, in Web Services, 485–486, 490
strong name specified for 528, 570 Static arrays, 302
assembly using, 421 SQL ORDER BY clause, 560 Static discovery, 459, 470–471,
Sniffing, 586 SqlParameter class, properties of, 490
SOAP. See Simple Object Access 505, 692 Static MessageQueue class
Protocol SqlParameter objects, 505, 507, methods of, 645–647
Sockets, 2 511 property of, 645
Software, PIM, 13 SqlRowUpdatedEventArgs class, Step keyword, 47
Solution Explorer window, 556 Store-and-forward
199 SQL SELECT statement, 501, communication, for message
Sort() method, 304, 306 554 queuing, 355
Sort property, of DataView class, SQL Server, 578 Stream-based XML data
560 SQL Server Enterprise Manager reading, 380–382
Source column, in Event Viewer, Console, 517 writing, 382–384
342, 343 SQL Server .NET Managed Data Stream class, 595
Source property, 345 Provider, 497, 498, 500 Stream classes, 316
Spaghetti code, 39– 40, 45 SqlTransaction class, 578 StreamReader class, 317, 322
<span> tag methods of, 568, 713 methods of, 318, 622
and HTMLGenericControl property of, 567, 712 properties of, 318, 621
example, 116 SQlTransaction object, Commit() StreamReader object, 597
output of method of, 570 Streams, 391
HTMLGenericControl SQL UPDATE command, 515 StreamWriter class, 317, 322
example with, 117 SQL UPDATE statement, 554 methods of, 320–321, 623–624
SQL. See Structured Query SQL WHERE clause, 507, 560 properties of, 320, 622
Language SSL. See Secure Socket Layer StreamWriter() method, 597
SqlCommandBuilder class Stack class, 308–310 String data type, 24, 27
method of, 554, 709 methods of, 617–618 String object, 317, 357
properties of, 554, 709 properties of, 617 Strings, 9, 395
SqlCommand class, 578 Stacks, 302, 391 StringToBytes(), 330
methods of, 504, 687–688 Standard APIs, 493 String values, 305
properties of, 686–687 Start() method, 365 String variables, 31
SqlCommand object, 501, 511, Start page, setting for ASP.NET Strong name, 420
570 HelloWorld application, 206, specifying for assembly using
SqlConnection class, 500, 567 207 sn.exe, 421
methods of, 502, 685–686 Start Without Debugging, from Strong Name Utility (sn.exe),
properties of, 501, 685 Debug menu, 207 420
SqlConnection object, 500, 511, State, saving with StateBag StrReverse() function, VB.NET,
554, 560, 578 object, 279–281 475
SqlDataAdapter class, events of, StateBag class StructuredErrorHandler()
555, 709 methods of, 280 function, 51
SqlDataAdapter object, 554 properties of, 280 output of, 52
SqlDataReader, 578 StateBag object, saving state with, Structured exception handling,
SqlDataReader class, 499, 502 279–281 51–53
methods of, 688–691 StateBag type, and ViewState Structured programming, 53
property of, 688 object, 279 Structured Query Language, 493
736 Index
Transform() method, 386 User column, in Event Viewer, scope and lifetime of, 28–29
Transmission Control 342, 343 with session scope, 293
Protocol/Internet Protocol, User Control in Web Form in VB.NET, 24–27
2, 3, 358 example, output of, 279 VB.NET, 4, 7, 95
Tree-based XML documents User Controls, 298 arithmetic and comparison
creating, 370–374 ASP.NET, 274–279 operators in, 37–39
loading and searching, custom properties added to, binary data types in, 27
374–380 277 bit-wise operators in, 34–36
Truck class, 70 Web Forms made into, class access modifiers in, 55, 56
Truth tables 276–277 description of, 17–18
AND, 34, 35 User Datagram Protocol, 358 fractional data types in, 25, 26
for comparison operators, 37 User interface controls, 9 functions defined in, 40
NOT, 34, 35 User names gasoline engine defined as
OR, 34, 35 and authentication, 581 object in, 53–55
XOR, 34, 35 and BASIC Authentication, integral data types, 25
Try block, 51 586 logical operators in, 37
Try . . . Catch block, 332 and Integrated Windows and managed components, 393
Try keyword, 44, 51 Authentication, 586 numeric data types in, 25
Type column, in Event Viewer, in user accounts databases, 582 pattern-matching characters in,
342, 343 User rights, 583 38
Typed DataSet application, User roles, in Supermarket primitive data types and
output of, 577 application, 452, 455 equivalents in, 396
Typed DataSet objects, 491 Users, Windows identification of, variables in, 24–27
VS.NET and, 571–577 583 Web application built with, 196
working with, 570 users attribute, 608 VB.NET managed components
Type-safety, 8 development, 406–412
Validation code, 227, 241 and class library, 406–407
UBound() function, 31 Validation Controls, 298 class library used in application,
UBound() return value, 307 ASP.NET, 227–246 411–412
UDP. See User Datagram multiple, 238 component “plumbing” code,
Protocol properties of, 228 409–410
uid values, 500 Valid XML documents, 375 and initialization code, 410
Undo feature, and Stack class, 308 Value property, 508 and methods creation, 410
Undo operation, 402 Values, entries checked against, namespace definition, 406
Unicode characters, 26, 27 230 and property creation, 411
Unicode text files, 316 Values() method, 316 VB.NET serviced components,
Unit structures, 154, 163 Values property, 349 building, 415–456
Universal data access, and ADO, ValueTypeDemoFunction(), 398, VB.NET Web applications,
494 399 creating, 266
UNIX operating system, 2 ValueType example, output of, VBScript, 94
Unmanaged code, 393 399 Vehicle class, 68, 70
Unstructured error handling, ValueType.NET class, 395 View Code, 271
49–50, 51 ValueType object, 398 selecting for Button control,
UpdateCommand event, 514 Variables, 24, 90 204
UpdateCommand property, 554 declaring and assigning, 27 ViewState, writing to and
UpdateInventory class, 416, 423 global, 28, 29 retrieving from, 281
Update() method, 556 instances of, 59 _VIEWSTATE hidden form field,
User accounts databases, 582 local, 28 100
Index 739
ViewState object, 279, 281 Web browsers, 2, 99, 461 placement of, on Web Form,
ViewState State Bag, 451 sample .aspx file rendered in, 149
Visual appearance definition, with 98 RadioButton Control, 180
Web Controls, 147 and Validation Controls, 227 RadioButtonList Control, 180,
Visual Basic, 11, 17 Web button controls 181, 182, 188–189
Visual Basic.NET. See VB.NET demonstration of, 166–169 shared properties in ASP.NET,
Visual Studio.NET. See VS.NET output of demonstration for, 147–149
Voice prints, 581 169 Table Control, 158, 159, 160
VS.NET Web client communication, TableRow Control, 158, 159,
calendars put on pages with, protocols for, 2–3 160
217 Web clients, 2 TextBox Control, 170
Code Editor window, 21 Web color values, adding, XYZ Corporation home page
creating Web Service project 250–251 with placeholders for, 269
in, 472– 478 web.config file, 610 WebControlTable class, 162–163
debugger, 207 sample, 598–599 Web Forms, 5, 102–103, 105
home page, 19 user account information in, adding to ASP.NET project,
lab code sample, 21–22 600 199–200
launching, 197, 266 for Windows Authentication adding to ASP.NET Web
progress message displayed Provider, 607–608 application, 103
with new Web page created WebControlCheckBox class, code ASP.NET, 8
by, 199 for, 177 DataList Controls in, 260
Regular Expression Editor in, Web Controls, 109, 298 editing, 202–203
238, 239 adding to Web Forms, 202 Label Control dragged onto,
and SOAP, 469 adding to XYZ Corporation 152
and typed DataSet objects, home page, 267, 269–271, saving, 106
571–577 273–274 and User Controls, 274
Web application created in, 104 adjusting shared properties for, Validation Controls in, 298
Web applications, 103–106 153–154 Web Controls in, 149
writing applications for, 18–23 in .aspx file, 97 Web guest account, 584
VS.NET Control Toolbox, Label binding to, 508 WebMethod() attribute, 486,
Control in, 149, 150 and building XYZ Corporation 490
VS.NET Integrated Development home page, 266–274 Web methods
Environment (IDE), 90 Button Control, 164–165 request for, using SOAP, 469
and component “plumbing” for button creation, 164–169 and Web Service classes,
code, 409 CheckBox Control, 175–179 462–463
launching, 18 CheckBoxList Control, Web pages, and User Controls,
and typed DataSet objects, 571 180–188 274
Web Forms and, 103, 106 data binding to, using class WebRequest class, 369
VS.NET Properties window, objects and ArrayList, 185 methods of, 366–367, 656–657
152 DropDownList Control, properties of, 366, 656
194–195 WebResponse class
WatcherChangeType property, Hyperlink Control, 195–196 methods of, 368, 658
enumeration values of, 341 ImageButton Control, 165–166 properties of, 368, 658
Web, 1 Image Control, 196 Web-safe palette
data access on, 491– 494 Label Control, 149–154 charts, 155
Web applications LinkButton Control, 166 colors in, 154, 158
creating in VS.NET, 104 ListBox Control, 190–194 Web server communication,
creation of new, 197, 198 Panel Control, 154–158 protocols for, 2–3
740 Index
XmlTextWriter class, 382, 383 XSLT. See Extensible Stylesheet confirming change to file name
methods of, 674–678 Transformation extension, 268
properties of, 673–674 XslTransform class, 384, 387 confirming creation of new
XMLTextWriter object, 383 methods of, 678–680 class file, 268
XML tree, locating nodes in, property of, 678 enabling entry of e-mail
378 x-url-encoding system, 4 addresses in, 272
XmlValidatingReader class, 374, XYZ Corporation home page with placeholders for Web
378 adding items to project, 267 Controls, 269
XML Web services, 11 AdRotator Control placed in, RadioButtonList, Label, and
XOR truth table, 36 273 Button Controls placed in,
XPath, 378 building, 266–274 271
XSD Design View, authors Calendar Control placed in, selecting files to add to project,
DataSet object in, 574 272 268