XML Web Services
XML Web Services
Teach Yourself
.NET XML
Web Services
in 24 Hours
800 East 96th St., Indianapolis, Indiana, 46240 USA
ASSOCIATE PUBLISHER
Sams Teach Yourself .NET XML Web Jeff Koch
Services in 24 Hours ACQUISITIONS EDITOR
Copyright ©2002 by Sams Publishing Neil Rowe
All rights reserved. No part of this book shall be reproduced, stored in a DEVELOPMENT EDITOR
retrieval system, or transmitted by any means, electronic, mechanical, photo- John Gosney
copying, recording, or otherwise, without written permission from the pub-
MANAGING EDITOR
lisher. No patent liability is assumed with respect to the use of the information
contained herein. Although every precaution has been taken in the preparation Matt Purcell
of this book, the publisher and author assume no responsibility for errors or COPY EDITOR
omissions. Nor is any liability assumed for damages resulting from the use of Michael Kopp,
the information contained herein. Publication Services, Inc.
International Standard Book Number: 0-672-32330-3 INDEXER
Library of Congress Catalog Number: 2001094811 Richard Bronson,
Publication Services, Inc.
Printed in the United States of America
PROOFREADER
First Printing: December 2001 Publication Services, Inc.
04 03 02 01 4 3 2 1 PRODUCTION EDITOR
Theodore Young, Jr.,
Trademarks Publication Services, Inc.
All terms mentioned in this book that are known to be trademarks or service TECHNICAL EDITOR
marks have been appropriately capitalized. Sams Publishing cannot attest to the Daniel N. Griffis
accuracy of this information. Use of a term in this book should not be regarded
as affecting the validity of any trademark or servicemark. TEAM COORDINATOR
Denni Bannister
Index 427
Contents
Introduction 1
Q&A ....................................................................................................................69
Workshop ............................................................................................................70
Quiz................................................................................................................70
Exercises ........................................................................................................70
Workshop ..........................................................................................................379
Quiz..............................................................................................................379
Exercises ......................................................................................................380
Part V The Quote Server (Using What You Have Learned) 383
Hour 23 Building the Quote Server XML Web Service 385
QuoteServer—A Fully Functional XML Web Service ....................................386
Loading QuoteServer with Relational Data......................................................386
Choosing Namespaces for Data Handling ..................................................387
Building a Data Loading Subroutine ..........................................................387
Using Global Events to Load Application Data ..........................................388
Returning Historical Quotes..............................................................................388
Adding a Service to QuoteServer ................................................................388
Returning a Random Quote ........................................................................389
Returning the Entire List of Quotes ............................................................390
Return N Random Quotes............................................................................392
Using Sessions When Returning a Quote....................................................396
Returning the Quote of the Day ..................................................................398
Revising QuoteServer—Adding New Functionality ........................................401
Loading XML Data into QuoteServer ........................................................401
Returning All Quotes of a Given Type ........................................................404
Returning a Random Quote of a Given Type ..............................................406
Summary ..........................................................................................................408
Q&A ..................................................................................................................408
Workshop ..........................................................................................................408
Quiz..............................................................................................................409
Exercises ......................................................................................................409
Index 427
xiv Sams Teach Yourself .NET XML Web Services in 24 Hours
Dedication
For Charlotte and Francis Brown
xvi Sams Teach Yourself .NET XML Web Services in 24 Hours
Acknowledgements
First of all, I would like to thank the following people, in no particular order, who helped
me along in the process of writing this book: Neil Rowe, Molly Redenbaugh, Matt
Purcell, John Gosney, and the other great people at Sams and Publication Services. This
book certainly would never have been finished without you.
I would also like to thank my parents, Richard and Frances Augustyniak, and my sister,
Monica Lewandowski, for all of their support.
Thanks also to Rowan, Morrigan, Naya, Melissa, and Lorindol. They know what they did.
I would especially like to thank Danielle for putting up with me while I worked all those
long nights. I love you.
Contents xvii
E-mail: [email protected]
Mail:
Sams Publishing
800 East 96th Street
Indianapolis, IN 46240 USA
Introduction
This book is written for programmers with experience coding in Visual Basic or C# who
want to take advantage of a powerful new technology in application development, XML
Web Services. Throughout the course of this book, readers will learn both the techniques
used to create and work with XML Web Services in Microsoft’s Visual Studio.Net as
well as the framework of technologies that rests beneath XML Web Services. If you can
write a function in Visual Basic or C#, you are ready to tackle XML Web Services.
The book itself is divided into twenty-four one-hour chapters. These chapters can be read
one a day or in groups as you have the time. The main goal, though, is to provide you
with the maximum amount of information in a relatively small amount of time. You
should be more than ready to add XML Web Services to your programming arsenal by
the time you are finished reading this book.
Source Code
I highly urge you to do the examples in the book, as well as the exercises at the end of
the chapters, yourself. However, if you should need it, the source code for the programs
in this book can be found on the www.samspublishing.com website.
Feel free to use this source code in any way that you see fit. If you manage to further
your career, upstage your coworkers, or turn a profit on anything that you found in this
book, then it has served its purpose. Feel free to drop me a line and let me know about it.
Getting Started
Congratulations on your decision to learn XML Web Services. The technology can best
be described as emerging, and it is always nice to get in on the ground floor of these
things. The first section of this book, “Core Concepts,” outlines the technologies behind
XML Web Services. Those of you wishing to jump right into coding can skip this section
and precede to the second section, “Building an XML Web Service,” if you promise to
go back and read section one before you get too much farther into the book.
PART I
Core Concepts
Hour
1 What Are XML Web Services and How Do
They Fit into the .NET Framework?
2 An XML Primer
3 Defining XML Web Service Operations
with WSDL
4 Remote Procedure Calls with SOAP
5 Finding XML Web Services with UDDI and
DISCO
HOUR 1
What Are XML Web
Services and How Do
They Fit into the .NET
Framework?
Welcome to Teach Yourself XML Web Services with .NET in 24 Hours. XML
Web services represent an exciting new tool in software creation, and this
first hour will introduce you to the technologies and tools behind it. You will
become familiar with the protocols used in the XML Web services model,
and you will also learn about the .NET framework and how XML Web ser-
vices fit into it.
In this chapter we will discuss the following:
• What XML Web services really are
• Where to apply XML Web services technology
6 Hour 1
Distributed Computing
In the past, developers started to move away from the “all in one” style of development,
in which all of an application’s functionality was contained in one code module.
Developers began to move code into objects, called components, which existed outside
of the initial project. These components could be updated independently of each other
and the main program, thus making for smaller and more efficient tasks.
With code now being developed from these component building blocks, it became easier
to build a project in teams and to reuse code. Components from one project could be
combined with new components to form different applications. It wasn’t long before
third-party companies began selling components to software developers for use in their
own projects.
With the rise of networking and technologies such as DCOM, developers also began to
move these components onto different machines across the network. This gave users
access to great processing power, via the distribution of tasks to varying machines, and it
gave developers the ability to change one component and simultaneously affect all users.
Now, with XML Web services, you have the ability to distribute your application across
not only a network but also the Internet. Components can be built and hosted anywhere
in the world and consumed by other components. Third-party companies no longer just
create and sell components; they host them as well.
What Are XML Web Services and How Do They Fit into the .NET Framework? 7
For a small example, think of a DLL or function library that contains spell-checking soft-
ware. If you were writing several applications to handle your company’s word processing
and e-mail capabilities, you would want to add this component into all of your applications.
1
Now, if someone created this spell-checking component as a Web service, you could sim-
ply use that component in all of your applications. If the component were ever to be
updated—say an expanded word list were added—none of your applications would be
impacted at all. They would all simultaneously have access to the expanded word list.
Leading up to .NET
The road to XML Web services has been a long one. Probably the first major step in the
development of the distributed model seen in XML Web services was the creation of
object technologies such as COM and CORBA. The introduction of these object design
technologies allowed developers to build programs in smaller components and allowed
these components to be reused in other programs.
From COM sprang DCOM and other, similar technologies that allowed these components
to be moved off the user’s machine and onto servers. This allowed components to be
simultaneously used by multiple users and multiple applications.
The rise of the Internet and Internet-enabled applications took the concept of distributing
applications one step further by allowing components to be called by Web applications
8 Hour 1
written in ASP or CGI and being used all over the world. Since the rise of the Internet,
developers have searched for better ways to expose functionality and services to their
user community.
ASP, briefly mentioned above, was another big step in the move toward more distributed
applications. ASP allowed developers to write applications using a stripped-down version
of the Visual Basic programming language known as VBScript. Previous to ASP, Web pro-
gramming was done primarily with CGI, or Common Gateway Interface, written in lan-
guages such as Perl and C++. ASP provided a much easier method of development, used a
commonly known language, and also provided a rich set of built-in objects to help devel-
opers quickly put together applications.
The last piece to fall into place in the creation of XML Web services was XML itself.
Finally, developers had a standard way in which to describe data and services. From there
it was not long before someone, actually several someones, began to write applications
that communicated with each other by passing XML documents. These were the first
Web services.
Suppose you wished to develop an application that allowed users to track sports scores.
You build your application and utilize a Web service that provides updated listings of
game scores for several major sports.
Next, you decide that you also wish to provide player statistics for every player in each
of the major American sports. You search around and find one that provides such statis-
tics for football and baseball, and you decide to use it in your application. Later, you dis-
cover two additional services, one that provides basketball statistics and another that
provides statistics for NHL games. You decide to use these as well.
Using this type of component model means that the developer of an application need not
worry about every facet of its design. The developer need only worry about what a com-
ponent does and the data that it returns; he or she does not need to bother with the inner
workings of the component. This eliminates the need to duplicate the development
efforts of others and greatly reduces the time required to create new applications.
Most of these new XML Web services fall into one of the following rather broad cate-
gories: intranet applications development, exposure of current customer services, and
preexisting Web applications.
1
If you are already building applications to post item quantities and costs, product
descriptions, stock evaluations, or even football handicaps to Web sites, then you can
leverage your efforts into something much more robust. Simply build the functionality
that you are already planning to deliver via standard ASP, CGI, custom DLLs, or what-
ever into a Web service. Your Web site can still use the service, but now the same devel-
opment can be used again and again in a host of other applications. These applications
need not be Web applications, or even be developed by your company. Depending on the
arrangement that you have with your customer, these XML Web services could be used
in the customer’s own development initiatives as a free service or accompanied by some
billing model.
Even if you don’t share information via the Internet already, XML Web services could be
created that securely expose up-to-the-minute information on your business. Then either
your company or a third party can roll out applications that make doing business faster
and more efficient.
all communicate seamlessly. Updated versions of technologies such as ASP and ADO
make creating XML Web services easier, while tools such as the WSDL.EXE and Visual
Studio’s Web References Dialog make consuming an XML Web service as easy as using
1
a DLL.
Microsoft plans to add more services to the Hailstorm project in the future, creating a
very centralized set of services for developers to tap into. Using Hailstorm as a business
model, it is not too difficult to imagine companies switching from traditional consulting
services to the XML Web services market—either providing XML Web services for
third-party software developers to use or creating XML Web services that they them-
selves integrate into the applications they build for clients.
Summary
In this hour, you learned what XML Web services are. You also examined the core con-
cepts behind the XML Web services platform, such as SOAP and HTTP protocols. In the
last half of this hour, you explored the .NET framework of technologies and how they
support XML Web services. Finally, you learned about Hailstorm and how it represents
Microsoft’s vision of the distributed-development paradigm of the future.
What Are XML Web Services and How Do They Fit into the .NET Framework? 17
Q&A
Q How do Web Services written in languages such as Java or C++ and running 1
on platforms like Unix communicate so seamlessly with .NET applications?
A As you will see throughout this book, XML Web services send and receive infor-
mation using simple text-based protocols such as SOAP. This way, all data and
function requests, regardless of type, are sent across with standardized text markup
to denote their actual types. The Web service simply has to read these standardized
formats and return data using the same protocol.
Q How do developers use XML Web services in their code without having to
write handlers for SOAP messaging?
A Visual Studios provides tools such as WSDL.EXE that create the SOAP handling
code, in the form of auto-generated proxy classes, for each XML Web service that
a developer uses in his or her projects. You will learn all about these in Hours 8
and 9.
Q If XML Web services are actually ASP+ applications, why am I writing them
in Visual Studio using Visual Basic or C#?
A Under the .NET framework, ASP+ applications, whether they are written in
Notepad or Visual Studio .NET, compile to native code and use the CLR. Since the
CLR is used, ASP+ applications can be written in any language, including C#.
Along with this switch to native code, Microsoft also created several new project
types in Visual Studio, ASP+, and XML Web services to give ASP+ developers the
benefit of a full tool suite.
Workshop
Quiz
1. What is the name of the protocol that XML Web services use to return data?
A SOAP, or Simple Object Access Protocol
2. What is the name of the description language that Microsoft uses for defining an
XML Web service?
A WSDL, or Service Contract Language
3. Microsoft and several other major companies have joined together in providing an
online index or repository of available XML Web services. What is this registry
called?
A UDDI, or Universal Description, Discovery, and Integration
18 Hour 1
4. What type of file provides information that points developers to an XML Web ser-
vice and its WSDL files?
A Disco, or discovery files
5. What feature of .NET allows for the ease of communication between components
written in different languages, such as Visual Basic, C#, and even mediated C++?
A CLR, or Common Language Runtime
Exercises
Now that you know what XML Web services are, try to think up some useful examples
for yourself. Include the service’s methods and functionality in your examples. By the
time you finish this book, you will be able to create these services.
HOUR 2
An XML Primer
In this hour, you will learn the basics of XML. You will learn how XML is
used in the XML Web services framework and how a foundation in XML
knowledge can help you when creating and consuming XML Web services
outside of the classroom.
In this hour we will discuss the following:
• XML’s role in XML Web services
• XML document syntax
• XML document content
• XML namespaces
What Is XML?
XML is a syntax for describing data. Working in much the same way as
HTML does in describing Web content, XML can be used to describe
almost any data, including Web content via XHTML.
20 Hour 2
XML’s power lies in its extensibility. Anyone can add tags to XML to create their own
vocabulary. A vocabulary is simply a set of XML tags and attributes that are used to
describe data. When individuals, groups, or companies decide to adopt a vocabulary for a
particular set of data, that data can be shared more easily.
As an example, look at the XML fragment in Listing 2.1. This XML fragment shows
data from a video store that contains information on their stock. Do not worry about
what the tag actually means; you will learn that later in this hour.
If every video store adopted this as their syntax, Web sites could be built that searched all
of the video stores in your area and let you know who had the movie you were seeking
in stock.
If the above vocabulary was truly complete, it would probably contain the film’s actors, a
plot synopsis, the category of the film, the date it was made, and so on, so that you could
really search for a film that suits you.
XML Prolog
The Prolog of an XML document is optional, but when one does exist, it may contain the
following XML entities: a declaration, processing instructions, and comment lines.
The Prolog may also contain, as its last element, the document type declaration, known
as the DTD.
An XML Primer 21
XML Epilog
Like the Prolog, an XML epilog is an optional structure. When an Epilog is present, it
may include comments and processing instructions.
XML Body
The XML Body is the one required portion of an XML document. It may contain any
number of elements, comments, processing instructions, and other entities, which are 2
beyond the scope of this book.
Declaration
As described earlier, the optional Prolog section of an XML document may contain an
optional declaration. Since Microsoft’s SCL contains the declaration and other XML
Web service vendors may also include it, we will discuss it here.
The minimum XML declaration, and the one used in SCL, looks like this:
<?xml version=”1.0”?>
Aside from version, the declaration may also contain attributes that describe the docu-
ment’s encoding method, whether or not it is a standalone XML document, or if it relies
on other documents for its completion.
If the standalone attribute is included, its values can be either “yes” or “no”. Encoding,
on the other hand, can support a very large range of encoding schemes. These include
“UTF-8” and “UTF-16.”
Elements
An element is the most basic structure in any XML document. Elements consist of case
sensitive start and end tags that may surround some type of data. Listing 2.2 shows some
examples of XML elements.
You will note that line 2 of Listing 2.2 contains an element with a start tag and an end
tag but no data. This is called an empty element, which is simply an element that contains
no data.
The element shown in line 3 is an example of the empty element tag. The space between
“Chair” and “/” is provided to ensure compatability with Netscape Navigator and sev-
eral other XML parsing programs. Internet Explorer will correctly handle the element
even if the space is not present. Since using the space ensures readability in both browser
types, as well as every major parser, this syntax is highly recommended. This tag is
merely a shortcut to writing out the full start and end tags. It is equivalent to
<Chair></Chair>
Document Elements
Data in an XML document is represented in a tree structure, with elements nested
inside of other elements in order to form a hierarchy. The document element is the
top element of the document body. It is also the only element that is actually required
to be present in an XML document. With that in mind, the following is a legal XML
document:
<Data/>
The above could represent the return of a database query that turned up zero matches
for the contents of a container, truck, box, and so on that was represented in another
XML document.
Children Elements
Since an XML document is a tree structure with the document element at its root, all
other elements are subelements of the root. These elements, known as children elements,
will make up the bulk of most XML documents. Also, in order to facilitate complex data
hierarchies, children elements may have children elements of their own. There is no prac-
tical limit to the complexity of the nesting that can be done with elements.
Listing 2.3 shows an example of a complex hierarchy of data in an XML document.
continues
An XML Primer 23
As you can see, you can nest elements to achieve complex hierarchies fairly easily. This 2
example barely touched on how complex relationships can get.
Attributes
Attributes are a way of attaching additional data to an element. For example, say we
wished to add an ISBN to an element tag containing the title of a book. We could do
something similar to Listing 2.4.
Attribute data must always be a string type and enclosed in quotation marks. Integer
values are not allowed, although they could be enclosed in quotes and represented as
string data.
Elements can contain any number of attributes, as long as the same attribute is not
repeated for a single element. Listing 2.5 shows our book example with the first printing
date and the Library of Congress number included.
Comments
Comment lines, like those in programming languages, provide a place to record notes and
information that may help people who need to work with the XML document. The syn-
tax for comment lines; a less-than symbol followed by an exclamation point and two
dashes, some comment text, and then the closing two dashes and greater-than symbol, is
taken directly from the world of Web programming and is as follows:
<!-Your Comments Go Here
Listing 2.6 shows some XML data that has been commented.
Processing Instructions
Processing Instructions are like comment lines, only they are designed as a way to
pass information along to a processing application on how the XML document should
be handled.
The syntax for a processing instruction is
<?target instruction ?>
The target is some name that is used to signify an object that should handle the instruc-
tion portion of the processing instruction element. instruction is merely a string of text
that the target application would decipher and use.
The most common use of processing instructions is to signify the association of style
sheets with various sections of an XML document.
Namespaces
Namespaces are a topic that comes up a lot in XML Web services, both in developing
them in .NET and in describing them, such as in SCL and DISCO documents.
An XML Primer 25
This attribute would associate the element that it was declared within, and all of that ele-
ment’s children, with the namespace “SomeAddress”.
Optionally, a namespace can be given an alias as seen here:
xmlns:alias=”someAddress”
Once a namespace has been declared, its alias can be added to the beginning of element
or attribute names in order to create qualified names.
<alias:Element> </alias:Element>
If this XML document were to be combined with another document, say the owner’s book
collection, we would have little to fear as far as processing applications mistaking book titles
for music titles.
A full discussion of DTDs would take far more space then we have in this
book. Suffice it to say, DTDs are used in a manner similar to Schemas, but
with a lot less flexibility to create complex structures.
name is the name of the element being created, type is the type of data that the element
can contain, and minOccurs and maxOccurs are optional attributes that describe how
many times the element may appear. This will become more important when you exam-
ine complex types. Our example above would allow for the following to appear in the
XML document:
<name>Mark Augustyniak</name>
New simple element types can be created by restricting elements via the restriction
element. This allows for elements to be created that are restricted to certain values or
ranges. For example, if you were trying to create an element for a five star movie rating
system, you could do the following:
<xsd:simpleType name=”Stars”>
<xsd:restriction base=”xsd:integer”>
<xsd:minInclusive value=”1”/>
<xsd:maxInclusive value=”5”/>
</xsd:restriction>
</xsd:simpleType>
This restriction element, along with the enumeration element, is what is used to create
enumerations such as the following, which describes a color enumeration limited to val-
ues of red, blue, or green:
<xsd:simpleType name=”Color”>
<xsd:restriction base=”s:string”>
<xsd:enumeration value=”red”/>
<xsd:enumeration value=”blue”/>
<xsd:enumeration value=”green”/>
</xsd:restriction>
</xsd:simpleType>
28 Hour 2
Expanding up this idea, more complex elements can be created by adding simple elements
together. The following schema declaration defines an element, named person, that may
contain, in order, elements of type fname, lname, and age.
<xsd:complexType name=”person” >
<xsd:sequence>
<xsd:element name=”fname” type=”xsd:string”/>
<xsd:element name=”lname” type=”xsd:string”/>
<xsd:element name=”age” type=”xsd:int”/>
</xsd:sequence>
</xsd:complexType>
ized XML vocabulary, makes this task much easier than the task would be if every devel-
oper created his or her own definition files. You will learn more about SCL in Hour 3.
At the time of this writing, Visual Studio is still using SDL, a subset of WSDL,
in order to create its contracts. This is to have changed by the time this book
goes to print.
2
Using SOAP to Communicate with XML Web Services
An XML subset, known as SOAP, is the medium through which most communication is
done between XML Web service consumers, either client applications or other XML
Web services, and the services themselves. SOAP, or Simple Object Access Protocol, is
an XML vocabulary used to facilitate remote procedure calls across the Internet.
Summary
In this hour, you learned the basic syntax of XML documents and how they are used
within XML Web services. You learned how to add elements to your XML documents
and how to further define these elements through the use of attributes. You also saw how
namespaces and DTDs are used to define XML documents and validate their contents.
Q&A
Q Why is it important to learn the basics of XML if Visual Studio .NET does all
of the XML work behind the scenes?
A Well, there are two main reasons to learn XML, aside from it being a useful and ever
more present technology. Reason one is that not every XML Web service that you
encounter will have been created using Microsoft tools. With other vendors getting
into the XML Web service market, you may find yourself delving into XML docu-
ments in order to bring a new service into your application framework. The second
reason is that it is always nice to know what is going on behind the scenes. This is
especially true when something goes wrong and you have to find out where and why.
30 Hour 2
Q Is there a rule for when I should put data in an attribute and when I should
place it in an element?
A No, unfortunately there is no rule involving what constitutes an attribute or an ele-
ment. Any data that you could place in an attribute could conceivably be given an
element of its own and vice versa. It is up to you, or whoever develops the vocabu-
lary, to determine what will be placed in attributes.
Q What is the importance of using DTDs and Schemas? Which should I use?
A DTDs and Schemas are important because they help validate XML documents and
define what a document can and cannot hold. It is through the use of these docu-
ments that we define our vocabularies and, with the use of XML parsers and val-
idators, determine if XML documents that we encounter are valid forms of said
vocabulary. That being said, DTDs are slowly losing favor in the development
community and Schemas are now the dominant technology. If you have the option,
you are probably better off using the Schema.
Workshop
Quiz
1. What is the XML subset used when publishing an XML Web service?
A DISCO.
2. True or False: Elements are limited to a single attribute.
A False, elements may contain many attributes.
3. True or False: Attributes contain data types that can not be represented as elements.
A False, the decision to use attributes instead of elements to describe some data
is purely a matter of preference.
4. What are used to differentiate between entities using the same name that originate
from different source documents?
A Namespaces.
5. Write out an attribute declaration for an attribute called color that is used on a sky
element and defaults to blue.
A <!ATTLIST sky color CDATA (blue)>
An XML Primer 31
Exercises
Try creating some XML structures of your own. Take some of your interests or hobbies
and see if you can come up with some simple vocabularies for them. There is no right or
wrong answer; as long as you follow the guidelines given in this hour, your XML docu-
ments should be fine.
2
HOUR 3
Defining XML Web
Service Operations with
WSDL
In this hour, you will learn how WSDL is used to describe XML Web ser-
vices. You will see how WSDL is used to define how a service exposes itself
to various types of HTTP request types. You will also see how the WSDL
language is used to inform client applications about argument and return
types that are used by the service’s methods.
In this hour, we will discuss the following:
• Typing in WSDL
• Messages
• Ports
• Bindings
34 Hour 3
What Is WSDL?
WSDL, or Web Services Description Language, is an XML-based language used to define
XML Web services. WSDL describes the service and its methods as well as the manner
in which communication between a client and a service should be carried out.
continues
Defining XML Web Service Operations with WSDL 35
continues
36 Hour 3
WSDL documents are fairly complex and can be extremely confusing to any-
one who isn’t accustomed to them and, for that reason, Visual Studio/ .NET
generates a WSDL document for every XML Web Service that you create.
The purpose of this hour is to help you understand what an XML Web
Service does based on its WSDL document. Do not worry about memorizing
all of the rules and syntax that comprise WSDL as you will probably never be
forced to make changes to a WSDL document.
3
• (lines 10 through 33)—Provides data type definitions that will be used for
Types
communication between the XML Web Service and its clients.
• Messages (lines 34 through 53)—Provides a message name, associated with a type,
that will be used for communication.
• PortTypes (lines 54 through 71)—Associates specific messages with port types,
such as HttpPost.
• Bindings (lines 72 through 111)—Binds specific ports and XML Web service
methods to Internet protocols, such as SOAP.
• Services (lines 112 through 125)—Supplies the address information for a ser-
vice’s different ports of communication.
Also contained within the port element is the address element. This element points to the
actual URL address that client applications will use to contact an XML Web service via
the given port. You will notice that the example in Listing 3.2 gives the same address for
all three ports. This is typically the case when creating services with Visual Studio .NET,
but WSDL allows for developers to create services that utilize different addresses to han-
dle the various port communications.
Defining Ports
When a method is created for an XML Web service, Visual Studio/ .NET will automati-
cally generate code capable of handling requests from multiple types of HTTP protocols.
The WSDL document generated for the service defines the ports on which these various
protocols may contact the service. In WSDL, a port is defined as follows:
<portType name="nmtoken"> *
<-- extensibility element -->
</portType>
In the above definition, name represents a unique name among the ports being defined.
The extensibility element represents a list of operation elements, one for every
method exposed by the service. The port defined in Listing 3.3 defines a service,
DataTypes, exposing its functionality via SOAP. The service contains one operation, or
method, called StringReturn.
Defining XML Web Service Operations with WSDL 39
The code in Listing 3.4 shows the same service exposing its functionality via HttpGet.
Operations
As you have already seen, operations represent the various methods being exposed by the
service. A typical operation contains two elements, input and output, but may also con-
tain documentation and fault.
The input and output elements of an operation basically link the services method,
StringReturn in the case of Listing 3.4, to SOAP messages that will provide the trans-
port for input parameters and output results. Line 6 of Listing 3.4 lets you know that the
StringReturn method will be called using the message StringReturnHttpGetIn and
will return its results using StringReturnHttpGetOut. A little later in this hour you will
see how to define the messages themselves.
Like the input and output elements, fault defines the message that will be used to
transport error messages should errors be encountered. In addition, the documentation
element, lines 3 through 5 of Listing 3.4, provides a method for attaching comments to a
service’s methods.
40 Hour 3
Bindings in WSDL
Bindings provide a method for WSDL to bind operations and ports to protocols. The
basic format for this is given below:
<wsdl:binding name="nmtoken" type="qname"> *
<wsdl:operation name="nmtoken"> *
<wsdl:input name="nmtoken"? > ?
</wsdl:input>
<wsdl:output name="nmtoken"? > ?
</wsdl:output>
<wsdl:fault name="nmtoken"> *
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
In the previous code, name is a unique identifier for the particular binding and type is the
name of the portType being bound. Typically, Visual Studio.NET will simply use the
portType name as the identifier in name.
SOAP Bindings
Listing 3.5 shows a binding for a SOAP port. The port was named DatTypesSoap, and
thus, the binding is named this as well. As you can see, the binding binds the portType,
DataTypesSoap to the SOAP transport protocol, line 2. Furthermore, each operation—
StringReturn in this example—has its input, output, and (optionally) its fault messages
further defined.
HttpGet
Since XML Web services must deal with client applications other than those utilizing
SOAP protocols, WSDL supports bindings for both HttpGet and HttpPost. As
with SOAP, HttpGet bindings bind the portType, DataTypesHttpGet in Listing 3.6, to
the HttpGet protocol.
The most important detail here is the specifics of transports for each message. Input
communications are set to use the urlEncoding method, line 6, whereas outbound infor-
mation will be presented as the body of an HTML document (line 9).
HttpPost
Listing 13.7 shows the binding for an HttpPost operation. This binding is very similar to
that used by HttpGet. Of note here is the use of the HttpPost method of passing argu-
ments as Form data instead of encoded data in the requesting URL, line 6.
Messages
Messages define the way information is actually transmitted during communication
between the service and its clients. In the case of SOAP clients, the message would help
to define the SOAP messages that are being sent. In the case of clients using HTTP pro-
tocols, the message would define Form or URI string messages.
The message element itself contains a name attribute that is used to uniquely identify the
message. When Visual Studio/ .NET creates a WSDL document for you, it typically cre-
ates a message whose name is built by combining the method’s name, the Port type, and
the direction of travel, relative to the service, of the message. For example,
myMethodPostIn, would be the name of a message calling a method named myMethod
using the Post port.
A message also contains zero or more part elements. part elements define the actual
parts of the message being sent. These part elements represent parameters and results
being sent back and forth between the client and the service. A part consists of two
attributes, name and element. The name attribute is either the name of an argument of the
method, or as in the case of SOAP port messages, simply the "parameters". The
element attribute is used to determine the type of the argument or response part.
The return message for this method looks very similar, with the substitution of Out for In
in the message’s name.
<message name="StringReturnSoapOut">
<part name="parameters" element="s0:StringReturnResponse" />
</message>
When one of the HTTP protocols is being used, the part elements actually contain the
parameter’s name and type, as seen below. This message would describe calling a
method, ParamLongReturn, via HttpPost and passing in two strings named iNum1 and
iNum2.
<message name="ParamLongReturnHttpPostIn">
<part name="iNum1" type="s:string" />
<part name="iNum2" type="s:string" />
</message>
Defining XML Web Service Operations with WSDL 43
The return of the method would make use of the message below to return a long. The
return, or Out, messages of HTTP protocol messages are always named Body.
<message name="ParamLongReturnHttpPostOut">
<part name="Body" element="s0:long" />
</message>
Types
WSDL makes use of XSD, XML Schema Definition, for its type system. Some of the
more common types, a few of which you have seen used as the types in message ele-
ments, are shown in Table 3.1.
WSDL’s type system allows for more complex data types, such as arrays, enumerations,
and even objects to be defined by combining the simple types shown in Table 3.1. The
following example shows a new type, called NewType, which contains an integer named
Var1 and a byte named Var2.
<s:element name="NewType">
<s:complextype>
<s:sequence>
<s:element minOccurs="1", maxOccurs="1"
name="Var1" type="s:int">
<s:element minOccurs="1", maxOccurs="1"
name="Var2" type="s:byte">
</s:sequence>
</s:complextype>
</s:element>
Now, apply this to the StringReturn method that you have been looking at throughout this
hour. The message for the StringReturn method defined a message part containing an ele-
ment named StringReturn. StringReturn is defined in Listing 3.8 as being an empty ele-
ment (line 6). This would suggest that the method StringReturn accepts no input parameters.
The return of the method, on the other hand, does return data. Lines 8 through 15 define a
type, StringReturnResponse, which contains one, and only one, string type variable.
If you needed to return an even more complicated type, such as the enumeration shown
in Listing 3.9, you would define the enumeration, lines 9 through 15, as a simple type. 3
Yes, a simple type because it will not be made up of other types but will in fact be the
building block of more complex types. This enumeration can then be used to create more
complex types, such as the EnumReturnResponse shown in line 1.
Summary
In this hour, you saw how to use WSDL to describe a service and point clients to the
URL used to contact the service. You also learned how to utilize XSD type schemas to
type arguments and returns used by the method of an XML Web service. In addition to
this, you examined how WSDL defines the content of messages that can be sent back
and forth between client applications and services.
46 Hour 3
Q&A
Q Why Learn about WSDL?
A WSDL documents tell you the specifics about an XML Web service. If you are
building a client application, especially if your client is not using .NET as its plat-
form, it is often invaluable to be able to look into a WSDL document and see how
your programs can access the service’s functionality. It is also important to have a
very good understanding of WSDL if you should ever come across a situation that
calls for the WSDL document to have to be hand altered, such as a situation where
you wish to force clients to use one specific port and disallow the others.
Q Why is s always used as the namespace for simple data types?
A If you look at the definitions element of the Visual Studio .NET–generated WSDL
files, you will see that s is the name given to the XMLSchema namespace. This is the
namespace that defines XML’s common data types. The use of s is, of course, arbi-
trary and can be replaced with any other valid XML token.
Q WSDL seems very complicated. How do I create a document and not have
errors?
A The odds are that you will never have to create WSDL documents by hand. Tools
such as Visual Studio/ .NET create them for you. As stated previously, the purpose
of learning WSDL is so that you can understand the documents when you
encounter them and alter them if you absolutely need to.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future lessons.
Quiz
1. How would you declare an array of integers using XSD?
A <s:complexType name="ArrayofInt">
<s:Sequence>
<s:element minOccurs="0" maxOccurs="unbounded"
name="int" type="s:int">
</s:sequence>
</s:complexType>
Exercises
Work through the following WSDL file and see if you can figure out the name of the ser-
vice, the number of its methods, and what each method actually looks like (that is, its 3
name, arguments, and returns).
<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
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="Add">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="iNum1" type="s:int" />
<s:element minOccurs="1" maxOccurs="1" name="iNum2" type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="AddResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="1" maxOccurs="1" name="AddResult"
type="s:int" />
</s:sequence>
</s:complexType>
</s:element>
<s:element name="Subtract">
<s:complexType>
<s:sequence>
48 Hour 3
<message name="AddSoapOut">
<part name="parameters" element="s0:AddResponse" />
</message>
<message name="SubtractSoapIn">
<part name="parameters" element="s0:Subtract" />
</message>
<message name="SubtractSoapOut">
<part name="parameters" element="s0:SubtractResponse" />
</message>
<message name="MultiplSoapIn">
<part name="parameters" element="s0:Multipl" />
</message>
<message name="MultiplSoapOut">
<part name="parameters" element="s0:MultiplResponse" />
</message>
<message name="DividedSoapIn">
<part name="parameters" element="s0:Divided" />
</message>
3
<message name="DividedSoapOut">
<part name="parameters" element="s0:DividedResponse" />
</message>
<message name="AddHttpGetIn">
<part name="iNum1" type="s:string" />
<part name="iNum2" type="s:string" />
</message>
<message name="AddHttpGetOut">
<part name="Body" element="s0:int" />
</message>
<message name="SubtractHttpGetIn">
<part name="iNum1" type="s:string" />
<part name="iNum2" type="s:string" />
</message>
<message name="SubtractHttpGetOut">
<part name="Body" element="s0:int" />
</message>
<message name="MultiplHttpGetIn">
<part name="iNum1" type="s:string" />
<part name="iNum2" type="s:string" />
</message>
<message name="MultiplHttpGetOut">
<part name="Body" element="s0:int" />
</message>
<message name="DividedHttpGetIn">
<part name="iNum1" type="s:string" />
<part name="iNum2" type="s:string" />
</message>
<message name="DividedHttpGetOut">
<part name="Body" element="s0:int" />
</message>
<message name="AddHttpPostIn">
<part name="iNum1" type="s:string" />
50 Hour 3
<operation name="Subtract">
<input message="s0:SubtractHttpGetIn" />
<output message="s0:SubtractHttpGetOut" />
</operation>
<operation name="Multipl">
<input message="s0:MultiplHttpGetIn" />
<output message="s0:MultiplHttpGetOut" />
</operation>
<operation name="Divided">
<input message="s0:DividedHttpGetIn" />
<output message="s0:DividedHttpGetOut" />
</operation>
</portType>
<portType name="Calc1HttpPost">
<operation name="Add">
<documentation>This function adds to integers</documentation>
<input message="s0:AddHttpPostIn" />
<output message="s0:AddHttpPostOut" />
3
</operation>
<operation name="Subtract">
<input message="s0:SubtractHttpPostIn" />
<output message="s0:SubtractHttpPostOut" />
</operation>
<operation name="Multipl">
<input message="s0:MultiplHttpPostIn" />
<output message="s0:MultiplHttpPostOut" />
</operation>
<operation name="Divided">
<input message="s0:DividedHttpPostIn" />
<output message="s0:DividedHttpPostOut" />
</operation>
</portType>
<binding name="Calc1Soap" type="s0:Calc1Soap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"
style="document" />
<operation name="Add">
<soap:operation soapAction="http://tempuri.org/Add" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
<operation name="Subtract">
<soap:operation soapAction="http://tempuri.org/Subtract"
style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
52 Hour 3
</output>
</operation>
<operation name="Divided">
<http:operation location="/Divided" />
<input>
<http:urlEncoded />
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
</binding>
<binding name="Calc1HttpPost" type="s0:Calc1HttpPost">
<http:binding verb="POST" />
<operation name="Add">
<http:operation location="/Add" />
<input>
<mime:content type="application/x-www-form-urlencoded" />
3
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
<operation name="Subtract">
<http:operation location="/Subtract" />
<input>
<mime:content type="application/x-www-form-urlencoded" />
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
<operation name="Multipl">
<http:operation location="/Multipl" />
<input>
<mime:content type="application/x-www-form-urlencoded" />
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
<operation name="Divided">
<http:operation location="/Divided" />
<input>
<mime:content type="application/x-www-form-urlencoded" />
</input>
<output>
<mime:mimeXml part="Body" />
</output>
</operation>
</binding>
54 Hour 3
<service name="Calc1">
<port name="Calc1Soap" binding="s0:Calc1Soap">
<soap:address location="http://localhost/FourFunctionCalc/Calc1.asmx" />
</port>
<port name="Calc1HttpGet" binding="s0:Calc1HttpGet">
<http:address location="http://localhost/FourFunctionCalc/Calc1.asmx" />
</port>
<port name="Calc1HttpPost" binding="s0:Calc1HttpPost">
<http:address location="http://localhost/FourFunctionCalc/Calc1.asmx" />
</port>
</service>
</definitions>
What Is SOAP?
Many people hear about SOAP, and a magical technology comes to mind—similar to the
images XML conjured up just a few years ago. Most people, however, are still confused
about SOAP’s (and sometimes XML’s) application.
Recall that XML is a way to easily transfer data—almost any kind of data—across a net-
work or the Internet. Because XML is plain text, it can be sent anywhere that plain
HTML can, which is virtually everywhere—often even through firewalls. This means
that you can share your data with anyone, no matter where they are. This is a very impor-
tant part of SOAP.
The Simple Object Access Protocol, as its name implies, is a way to easily access objects
across a network. That object can be anything from an application, such as Microsoft
Word, to a stock quotes database. SOAP is a protocol that allows two objects, no matter
where they are, to communicate with each other.
So how are XML and SOAP tied together? XML is the language that SOAP speaks in.
Because XML can send data virtually anywhere, it makes sense that a protocol that
needs to converse between objects that could potentially be located anywhere uses XML.
These objects create all types of information that need to be exchanged, such as com-
mands, data, images, and so on. XML is versatile enough that it can handle all of these
data types.
Similarly, XML provides a way to “mark up” plain text so that it is more meaningful.
One application can generate as much data or XML as it wants, but without a person
feeding the results to another application, the two wouldn’t be able to communicate with
each other unless specifically built to do so (and it’s near impossible to build all applica-
tions so that they can speak with one another).
SOAP steps in and provides a method for those applications to communicate. It repre-
sents all communications as XML. With SOAP, one application can view another across
the Internet. Figure 4.1 illustrates this concept.
XML is great at representing data, just as HTML is great at formatting text to look like a 4
Web page. SOAP and HTTP allow these two languages to be put to use delivering infor-
mation.
Note that SOAP isn’t necessarily the only application of XML. It simply pro-
vides the mechanism for two objects to communicate. Someone could
potentially come up with another protocol that also uses XML to represent
its data, but for the purposes of XML Web services, SOAP is the only proto-
col of interest.
Also, note that SOAP is actually sent over the HTTP protocol as well. Thus it
can be sent anywhere HTML can.
It’s difficult to visualize these concepts in one’s head. You’ll take a look at examples of
SOAP using XML later this hour.
scope of this task has changed to include global applications. The problem has been find-
ing a universally acceptable format that can be used anywhere, without limits on plat-
forms or networks.
The Component Object Model (COM) is a widespread protocol used to enable interoper-
ation between applications. With it, applications can share data and execute each other’s
functions. Much of the foundations of Microsoft Windows are based on COM interfaces.
ActiveX is another protocol similar to COM. This is how, for example, much of
Microsoft Office provides the cross-application data sharing. Microsoft Word can contain
an Excel spreadsheet without Microsoft Excel being open.
There are several problems, however, with these and other protocols. First, they are pro-
prietary. This means that only Microsoft Windows computers can use COM and ActiveX,
which leaves out Unix, Macs, and other operating systems—hardly a universal solution.
A second limitation is that these protocols were not built with the Internet in mind. This
means they inherently don’t support accessing objects across a network—your com-
puter’s copy of Microsoft Word cannot use your friend’s computer’s copy of Excel.
The third largest limitation is that the types of communication messages that protocols
such as COM and ActiveX generate are very complex and would have trouble being car-
ried over any medium other than what they were specifically built for. It would be diffi-
cult if not impossible to send COM messages over the Internet, especially through
firewalls.
SOAP addresses all of these issues. It is standard and nonproprietary, meaning it can be
used by any computer platform or operating system. It was built specifically for commu-
nication across the Internet, and because it uses XML to represent its messages, it can
travel across nearly any medium.
Now that you’ve got a firm background on SOAP, let’s take a look at the technical
aspects, and how you’ll be able to use it.
What’s in SOAP?
According to the official SOAP specification (http://www.w3.org/TR/SOAP), there are
three main parts of SOAP: an envelope; the encoding rules, which govern how data and
commands are represented as XML; and a means for SOAP to communicate with its
objects, specifically via the request and response model. The third part is usually in the
form of HTTP headers (a set of instructions at the beginning of the message). Together,
these components make up a SOAP message.
Remote Procedure Calls with SOAP 59
It is helpful to think of a SOAP message as an actual letter (see Figure 4.2). The enve-
lope defines what the message is—when you receive an envelope in the mail, you know
it’s a letter. Likewise, when an object receives a SOAP envelope, it knows to expect an
encoded XML letter.
FIGURE 4.2
A SOAP message con-
sists of an envelope, an Encoded Message
encoded message, and
headers.
Envelope
Somesender
45 Some Drive
Yip Yip town, FL
32897
To: Somebody
1231 Someplace Lane
Sometown, FL
Header
4
32898
The encoded message is the XML data that is to be sent, be it commands to an object or
returned data. Finally, the header provides instructions for the sender and receiver
objects, just as address labels provide instructions to the Postal Service.
Let’s take a look at each of these items in the next few sections.
The Envelope
Let’s look at a sample SOAP message, shown in Listing 4.1. On line 1 you can see that
the SOAP envelope is simply an XML tag, <SOAP:Envelope> (literally, the SOAP enve-
lope is the word “envelope”). This provides the wrapper for the rest of the SOAP mes-
sage and lets whoever receives this message know what they’re dealing with.
continues
60 Hour 4
Line 2 describes the namespace used for the SOAP envelope. Just as you provided name-
spaces for XML messages in Hour 2, “An XML Primer,” you do so with SOAP messages
as well. You should never have a reason to change the namespace from
http://schemas.xmlsoap.org/soap/envelope.
Additionally, you must specify the <SOAP:Body> tag as part of the envelope. Inside this
tag is where your encoded message will go (lines 4–7)—but more on that in the section,
“The SOAP Body.” Finally, on lines 8 and 9 we close the <SOAP:Envelope> and
<SOAP:Body> tags.
As you can see, the SOAP envelope is very simple. You’ll create your own later this hour
in “A Simple SOAP Application,” but for now, let’s move on to the headers.
Headers
There are two different types of headers SOAP uses for its messages. The first is a standard
HTTP header that’s also used for retrieving or sending HTML pages. This is appropriate,
as SOAP messages are also relayed via HTTP. An example is shown in Listing 4.2.
The HTTP header in Listing 4.2 is typical when using an Http-POST to send a SOAP
message. The server would respond with a header as follows:
HTTP/1.1 200 OK
Content-Type: text/xml; charset=”utf-8”
Content-Length: xxxx
The second type of header, and probably more useful to you as a developer, is known
specifically as a SOAP header. This header is used to convey additional information that
isn’t included in the body of the message or in the HTTP headers. Listing 4.3 shows an
example SOAP message with a SOAP header.
The <SOAP:Header> tag goes inside the envelope along with the <SOAP:Body> tag. In this
case, the SOAP header has an element authHeader, which supplies a password, as shown
on line 4. This password can be used by the receiving object to verify that the sending
object has the necessary permissions to do whatever it wants to do. 4
The optional mustUnderstand attribute, shown on line 2, tells the receiving object that is
must process the header—it cannot ignore the information contained within. This is use-
ful in this situation where a password must be evaluated before anything else occurs.
You’ll examine SOAP headers again in Hour 18, “Security and the Soap Toolkit.”
Imagine that you’ve built an XML Web service that simply multiplies two numbers and
returns the results. Listing 3.4 shows the SOAP message that would be generated by your
XML Web service client to initiate the calculation (you’ll take a look at the service’s
response to the client in a moment).
On line 3, inside the <SOAP:Body> element, you have another element named multiply.
This is presumably the name of the function in your service that calculates the product of
two numbers. The multiply element has two subelements, valueA and valueB, which
represent the numbers to be multiplied (8 and 9 in this case).
With this simple SOAP body, you’ve told an XML Web service to execute a function and
supplied it with values as well. In this way, you can instruct virtually any XML Web ser-
vice to perform whatever action you want (provided that the service allows you to do so).
This simple method for accessing remote objects and applications is the beauty of SOAP.
Imagine a message, such as that shown in Listing 4.5, that would instruct Microsoft
Word to open a document.
On line 3 you instruct Word to execute the OpenFile function, passing it a filename (line 4)
to open as read-only (line 5).
At the time of this writing, there is no Microsoft Word XML Web service, so
the SOAP message shown in Listing 4.5 won’t actually do anything.
The XML Web service’s response to Listing 4.4 would look like Listing 4.6.
Remote Procedure Calls with SOAP 63
The response is very simple, and it always follows a pattern. Note on lines 3 and 5 that
the only element in the body that the service returns is the name of the function that was
executed (multiply, line 3 of Listing 4.4) followed by the word Response. Inside the
multiplyResponse element is simply the value of 8*9, or 72.
In the next section, you’ll look at how to return more complex types of data.
continues
64 Hour 4
There are a few new lines in this listing, but nothing too complex. First, on lines 2–6,
you specify additional namespaces that need to be used so that you can encode your data.
Again, these are standard values, and you usually won’t have to change them.
The only other change is on lines 9 and 10. We now have the attribute
xsi:type=”xsd:integer” in the valueA and valueB elements. This simply tells us that
these values are integers and should not be interpreted otherwise. When the XML Web
service receives this SOAP message, it knows what types of data should be in the valueA
and valueB elements, and if they don’t match, the values will be rejected.
The XML namespace provides quite a few data types. For instance, if we wanted to pass
characters instead of numbers, we could change line 9 to read:
<valueA xsi:type=”xsd:string”>8</valueA>
The response from the XML Web service would look like Listing 4.8.
Again, the only change from the previous response is the addition of the namespaces on
lines 2–6 and the xsi:type=”xsd:integer” attribute on line 8.
Remote Procedure Calls with SOAP 65
What if you need to represent a more complex data type? Let’s imagine the multiplica-
tion service again, but instead of returning an integer, it returns an array including the
product, quotient, sum, and difference of the values. The response would change to
Listing 4.9.
On line 8, the response now has a type of SOAP-ENC:Array, and line 9 specifies the
names by which the array elements are referred to—Item, in this case. Each element of
the array is then contained in an item element, with name and value pairs to represent
each index. Again, each value is encoded in its proper data type.
On line 15, you might notice something a bit odd. The quotient of 8 and 9 is approxi-
mately .8889, yet the response returns 1. This is because you’ve encoded the value as an
integer, and an integer cannot have decimal places. Therefore, the value was rounded to 1.
66 Hour 4
Thus, you can see that SOAP together with XML can represent quite a large number of data
types. You’ll see how to use them to return database results in Hours 12, “Passing DataSets
from XML Web Services,” and 13, “Consuming DataSets in XML Web Services.”
FIGURE 4.3
Viewing an XML Web
service in your
browser.
Remote Procedure Calls with SOAP 67
We’re not going to go over much of the code—we’ll save that until Hour 7, “Building
the Four Function Calculator.” For now, just know that this XML Web service does one
thing: add and return two integers.
Figure 4.3 provides a lot of interesting information, especially if you want to build a
client for this service. Click the Add link near the top of the page (this is the name of the
service’s only function), and you’ll see Figure 4.4.
FIGURE 4.4
The XML Web service
description.
Here you can actually test out the service. Enter two numbers in the text box provided,
and press the Invoke button. You’ll see the XML response generated by the XML Web
service. It amounts to the following code:
<?xml version=”1.0” encoding=”utf-8” ?>
<int xmlns=”http://tempuri.org/”>17</int>
You can see that it returns a very simple XML document with the sum of the two values
you entered (8 and 9 in our case).
Scroll down a bit in the window shown in Figure 4.4, and you’ll see a sample SOAP
message provided by the service. This code is shown in Listing 4.11.
68 Hour 4
Lines 1–5 show the HTTP header. You should be familiar with this by now. The length
value on line 4 is a placeholder that is substituted with an actual value when the XML
Web service is in action.
On lines 8 and 9 you see the familiar <SOAP:Envelope> element, along with several
namespace definitions. On line 11, you’ll notice the <SOAP:Body> element, and on lines
12–15 you’ll find the body of the message. Line 12 is the name of the XML Web service
function that will be called, Add, and lines 13 and 14 show the values that will be passed
to that function. Again, intA and intB are placeholders for values that will be inserted
when you call the service.
All of the SOAP parts that you’ve learned about this hour are there. You’ll notice
that there is an additional namespace used in several places in the message,
http://tempuri.org/. This namespace doesn’t actually exist; rather, the service inserts
it so that any undefined element in the message will belong to a namespace. This isn’t
necessary, but it adheres to strict SOAP guidelines, which is always a good thing to do.
Feel free to modify the service shown in Listing 4.10 to see how the SOAP messages
change.
Summary
You’ve learned quite a bit about SOAP in this hour. SOAP is a protocol that allows
remote objects to communicate with each other via XML. It allows commands and data
to be exchanged easily, which is a key requirement of XML Web services.
Remote Procedure Calls with SOAP 69
A SOAP message consists of three parts: a header, an envelope, and a body. The enve-
lope is simply an XML wrapper to let the receiving object know what it’s looking at. It
contains a <SOAP:Envelope> and a <SOAP:Body> tag.
There are two types of headers: HTTP and SOAP headers. The former is used to instruct
HTTP how to send the SOAP message, whereas the latter is used to provide additional
information not sent in the SOAP body. SOAP headers are represented in XML with the
<SOAP:Header> tag.
Finally, the SOAP body is the actual XML message that you want to send. The data can
be encoded to bring added versatility to your messages.
Q&A
Q Is SOAP secure?
A Not necessarily. It is sent as plain text, so anyone who intercepts the message can
view its contents, just like XML; there is nothing to prevent this unless you build
an algorithm to encrypt the contents.
You can, however, implement SOAP headers so that an XML Web service is
secure. That is, so that unauthorized users or objects are unable to access its func- 4
tionality.
Q Do I have to write SOAP messages every time I use an XML Web service?
A Fortunately, no. The XML Web services that you’ll likely be using will generate
the SOAP commands automatically, saving you a lot of headache. When you start
to build your first XML Web service in Hour 7, “Building the Four Function
Calculator,” you’ll see how this is done.
Q Where can I get more technical details on SOAP?
A The first place to look would be the official specification at
http://www.w3.org/TR/SOAP.
There are quite a few tutorials online that explain SOAP to varying degrees.
http://www.soaprpc.com/tutorials/ lists quite a few good ones.
70 Hour 4
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. What does SOAP stand for?
A Simple Object Access Protocol
2. (True or False) HTTP messages are sent over the SOAP protocol.
A False. SOAP messages are sent via HTTP.
3. What is the standard namespace for the SOAP envelope?
A http://schemas.xmlsoap.org/soap/envelope/
SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/”
xsd=”http://www.w3.org/1999/XMLSchema/”
xsi=”http://www.w3.org/1999/XMLSchema/instance/”
SOAP-ENV:EncodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”
6. (True or False) You can send complex data types over SOAP.
A True.
Exercises
1. Write an example of a SOAP message, including an HTTP header, that executes
the “SaveDocument” function, sending a filename as a parameter.
A
1: POST /MyWebService HTTP/1.1
2: Host: MyHost
3: Content-Type: text/xml; charset=”utf-8”
4: Content-Length: xxxx
5:
6: <SOAP:Envelope>
7: <SOAP:Body>
8: <SaveDocument>
9: <filename>myfile.doc</filename>
10: </SaveDocument>
11: </SOAP:Body>
8: </SOAP:Envelope>
Remote Procedure Calls with SOAP 71
3. Write the encoded response for the Exercise 1. It should return true or false
depending on if the save was successful.
A
1: <SOAP:Envelope
2: xmlns:SOAP-ENV=”http://schemas.xmlsoap.org/soap/envelope/”
3: xmlns:SOAP-ENC=”http://schemas.xmlsoap.org/soap/encoding/”
4: xmlns:xsd=”http://www.w3.org/1999/XMLSchema/” 4
5: xmlns:xsi=”http://www.w3.org/1999/XMLSchema/instance/”
6: SOAP-ENV:EncodingStyle=”http://schemas.xmlsoap.org/soap/encoding/”>
7: <SOAP:Body>
8: <SaveDocumentResponse xsi:type=”xsd:Boolean” >true
9: </SaveDocumentResponse>
10: </multiplyResponse>
11: </SOAP:Body>
12: </SOAP:Envelope>
HOUR 5
Finding XML Web
Services with UDDI and
DISCO
Before you can use an XML Web service, you have to find it. There are
many different ways to do so, and in this hour we’ll take a look at several.
UDDI (or Universal Description, Discovery, and Integration) is a standard
method for deploying and finding XML Web services. DISCO (or Discovery)
is a tool bundled with the .NET Framework that provides a more hands-on
method for finding an XML Web service. In this hour, you’ll take a look at
using the service description directly to find the information you need.
In this hour we will discuss the following:
• What it means to discover an XML Web service
• What UDDI is and how to use it to find services
• How to use the disco.exe tool
74 Hour 5
Before we examine the different discovery methods, let’s first take a look at what a client
needs to know about a service.
To find this description, you need the URL of the service itself—
http://www.myserver.com/services/calculator.asmx, for example. Typing this URL
into the browser would produce something like Figure 5.1, which is very user-friendly
but not very client-application-friendly. By tacking the string “?WSDL” on the end of the
URL, the client can view the XML description directly, as shown in Figure 5.2.
FIGURE 5.1
The service
description page.
FIGURE 5.2 5
The XML service
description page.
76 Hour 5
Glancing through this XML description, you’ll see elements that describe the data the ser-
vice expects and returns. You’ll also notice several additional elements named AddSoapIn,
AddSoapOut, AddHttpGetIn, AddHttpGetOut, and so on. These elements describe the dif-
ferent methods of accessing the service, via SOAP, HTTP-GET, and HTTP-POST.
Using this information, the client has everything it needs to know to consume the XML
Web service. There are different ways of obtaining the URL of the service, and the next
few sections will describe them in detail.
Using UDDI
The UDDI specification is a set of rules that tells XML Web services and their clients
how to look for each other—essentially, rules for searching. With all the millions of Web
sites and businesses all over the Internet, you can imagine that a good search engine is
the only way you’ll be able to find what you’re looking for easily and accurately.
UDDI provides a standard way for services and clients to interact with this specialized
search engine. Many businesses are now using these rules to not only list the XML Web
services they provide, but also provide more information about the business itself.
As you may have guessed, the UDDI rules are simply XML schemas that define how
discovery messages should be formatted. You can access the XML schema at
http://www.uddi.org/schema/uddi_v2.xsd. Figure 5.3 shows the schema in Internet
Explorer.
FIGURE 5.3
The UDDI specifica-
tion schema.
Finding XML Web Services with UDDI and DISCO 77
There are elements to describe the business’s name, the type of service it offers, and the
names and URLs of those services, along with gobs of other information. Thankfully,
you don’t have to build any of this information—not yet, anyway. For now, let’s take a
look at how to put UDDI to good use.
FIGURE 5.4
The UDDI Web site.
You can register your business and its services to allow other organizations to find you,
but we’ll skip that step for now. Right now, we’re interested in searching for XML Web
services, not registering them.
As you will see in Hour 22, registering your service is simply a matter of visit-
ing www.uddi.org and clicking the “Register” link. The entire process doesn’t
take more than a few minutes.
78 Hour 5
Currently, only IBM and Microsoft provide searchable directories, or nodes, of services.
This doesn’t mean that the only services you find will be from Microsoft or IBM, but
rather that these two companies provide the actual search engines. Searching Microsoft’s
node for “calculator” brings up three XML Web services, as shown in Figure 5.5.
FIGURE 5.5
Searching for a
calculator XML Web
service.
The results are XML Web services available for use. Clicking the “details” links will
give you more information about each service directly from the UDDI documents. For
example, the first result returned in Figure 5.5 is a service that returns shipping rates for
various locations around the United States.
Once you’ve found the service you were looking for, you can get the URL and use it in
your XML Web service client, and that’s all there is to it! UDDI provides a very easy
way to find the services you’re looking for. Next, you’ll learn about a more hands-on
method of finding XML Web services.
The UDDI business directory actually uses SOAP and XML Web services itself
to provide the search features for you.
Finding XML Web Services with UDDI and DISCO 79
Using DISCO
Aside from UDDI, XML Web services can advertise themselves using discovery docu-
ments. We’ll examine these documents more in Hour 22, “Publishing an XML Web
Service,” but for now let’s just look at a sample, shown in Listing 5.1.
The discovery document is just another XML file with links to an XML Web service
description, shown on line 4. Let’s save this file as service.disco on your Web server’s
root directory. We’ll get back to it in a moment.
Assuming you know the URL of this discovery document, you can use the disco.exe
tool provided by the Microsoft .NET Framework SDK to retrieve and parse the
information. This tool examines the .disco file on a Web server and lets the client
know what services are available. Let’s first take a look at the syntax of this tool,
shown in Table 5.1.
Thus, the command to connect to the .disco file shown in Listing 5.1 would look like
Disco /out:c:\temp http://localhost/service.disco
Type this command at the command prompt. You should see the results shown in
Figure 5.6.
80 Hour 5
FIGURE 5.6
The results of the
disco.exe tool.
Let’s take a look at the files that were output from this tool. The first,
c:\temp\service.disco, is shown in Listing 5.2.
This file doesn’t tell you much—the output is basically a confirmation that the tool found
a service. Let’s look at the other file, results.discomap, shown in Listing 5.3.
This file is much more interesting. Lines 2–4 tell us what we’re looking at—that is, a
discovery results file. Line 5 provides a wrapper for what the disco tool discovered.
Lines 6–10, the actual results, provide a reference to the .disco file from Listing 5.1.
Finding XML Web Services with UDDI and DISCO 81
Summary
As you’ve learned this hour, discovery is a process by which a client locates and interro-
gates an XML Web service. This process is used by the client to determine what the ser-
vice is capable of and what kind of data it expects or returns.
There are a few different ways discovery can be accomplished. The first involves UDDI,
a specification that details a standard set of rules for exposing and consuming services.
www.uddi.org also provides a business registry that you can search to find services that
meet your needs.
The second method is to use the disco.exe tool, which requires a .disco file on the
server. This .disco file provides links to the XML Web services on a particular server.
Unfortunately, this method often requires you to know specific URLs—not a very com-
5
mon situation.
Finally, once you have either the .disco file or the service’s URL, you can examine in
more detail the functionality offered by the service.
After the past few hours, you should have a strong background on XML Web services
and the technologies that they use, including SOAP, XML, and WSDL. You can now rec-
ognize the difference between a SOAP message and a normal XML file, understand what
is contained in a WSDL service description, and know how to find services on the
Internet. Beginning in the next hour, you will start to build your own XML Web services
in Visual Studio.NET.
82 Hour 5
Q&A
Q Can I use the .disco tool on any XML Web service?
A No. The .disco tool can examine only .disco files, so if the creators of an XML
Web service don’t want people to find out about it, they just don’t create the .disco
file. That won’t stop you, however, if you know the exact URL of the service.
Q What if I can’t find an XML Web service using UDDI or DISCO?
A Unfortunately, XML Web services are a relatively new technology, and chances are
that the service with the particular functionality you need doesn’t exist. On the
other hand, the creator of such a service may have decided not to allow discovery
or register with UDDI.
In these situations there is, unfortunately, nothing you can do. It is a perfect oppor-
tunity, though, to test your own skills at creating a service, and then you can make
it available to others.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. (True or False) Discovery is a required step to use an XML Web service.
A False. Discovery only helps you determine what XML Web services are avail-
able. If you already know of a service to use, you don’t need discovery.
2. What does UDDI stand for?
A Universal Description, Discovery, and Integration.
3. Imagine an XML Web service with the discovery document
ShippingCalculator.disco. What are two files that would be output when using
the disco.exe tool?
A results.discomap and ShippingCalculator.disco.
4. Why is UDDI necessary?
A It is often very difficult to find what you’re looking for on the Internet; some-
times it’s impossible to find the service that you need. Therefore, UDDI pro-
vides a standard way for any service creator to publish their service for all to
see and register it in a convenient search engine, as well.
Finding XML Web Services with UDDI and DISCO 83
Exercises
1. Explore more of the UDDI Business Registry. Find XML Web services that are
freely available, and try to use discovery on them. Also view their WSDL service
descriptions.
5
PART II
Building an XML
Web Service
Hour
6 Visual Studios Environment or
Server Setup
7 Building the Four Function Calculator
8 Windows Client for the Four Function
Calculator
9 Web Clients for the Four Function
Calculator
HOUR 6
Visual Studios
Environment or
Server Setup
Over the past five hours, you’ve learned quite a bit about XML Web ser-
vices, such as the way they work and the types of data they use. Now it’s
time to get some hands-on training. In this hour, you’ll set up the develop-
ment environment and start to build your very own XML Web services.
Then, in Hour 7, you’ll build a more complex calculator service.
In this hour, we will discuss the following:
• What Visual Studio.NET is and how to set it up
• How to create an XML Web service using VS.NET
• What code-behind forms are and how to use them
• How the special \bin directory works
• What proxy classes are
• How to call an XML Web service from a client application
88 Hour 6
Visual Studio.NET
Visual Studio.NET is Microsoft’s integrated development environment (IDE) that allows
you to build .NET applications quickly using visual tools. With it, you can build .NET
applications (including ASP.NET pages and XML Web services) from a central location.
If you’ve used previous versions of Visual Studio (6.0 and below), you’ll know that it
came with several different environments: VB, C++, Interdev, and so on. VS.NET fea-
tures a single development environment that you can use to build any type of application
in any language you want. Let’s get started with this tool.
FIGURE 6.1
The VS.NET setup
Window.
Visual Studios Environment or Server Setup 89
1. The first step is to update your system so that it is capable of running VS.NET
(option 1). This step installs necessary components such as the Windows 2000
Service Pack 2, the .NET Framework SDK, Internet Explorer 6, and various other
utilities that are all required by VS.NET. Even if step 2 (Visual Studio.NET) in
Figure 6.1 is not grayed out, it may be a good idea to perform step 1 anyway to
ensure the utmost compatibility.
2. After you’ve installed the updated components, step 2 will be available to you.
Click it, read the user-agreement that pops up, accept it, and then click next. You
should see something similar to Figure 6.2. The left-hand box allows you to select
only the components of VS.NET that you want. For this exercise, you’ll need at
least Visual Basic (under language tools), and you’ll probably want to install the
MSDN documentation package as well.
FIGURE 6.2
Select the components
you wish to install.
6
3. Once you’ve chosen the items to install, click the Install Now! button and sit
back—this may take a while. The installer provides you with some reading mater-
ial while you wait.
4. Finally, once VS.NET is installed, select option 3, Service Releases. This step
allows you to check for updates to the Visual Studio environment, which could fix
potential bugs or provide additional functionality. Selecting this option will show
you Figure 6.3, where you can choose to check for updates via the Internet or with
a service pack disk.
90 Hour 6
FIGURE 6.3
You can update via
service pack disk or
the Internet.
FIGURE 6.4
Running VS.NET for
the first time.
Visual Studios Environment or Server Setup 91
Select the options you want and press the “Get Started” link. First you’ll want to create a
new project, so click on the “Create a New Project” link, or go to File, New, Project.
You’ll see a dialog similar to Figure 6.5. Depending on the components you installed
during setup, you’ll see different items to choose from in the list. We want to create an
XML Web service, so click on the XML Web service icon in the right-hand pane, enter
an appropriate name (we’ll use “MyWebService”), and click OK.
FIGURE 6.5
VS.NET has many
options when creating
a new project.
When VS.NET is done churning, the Solution Explorer (upper right of the interface) will
show all of the files created for you:
• AssemblyInfo.vb—Contains class information that will be used by your service
• global.asax—Used for configuration of your service
• MyWebService.vsdisco—Visual Studio.NET’s version of a .disco file
• Web.config—Like the global.asx file, this will be used for configuration of your
service
• Service1.asmx—The front end of your XML Web service; often is the main and
only page of an XML Web service
Click on the “Show all Files” icon at the top of the Solution Explorer. There will be sev- 6
eral additional files displayed, including the bin directory, where you’ll save any custom
components (.dll files—more on that later this hour). One file you should pay particular
attention to is Service1.asmx.vb. This file is known as the code-behind form. This file
is where you’ll place any functionality you write—you’ll learn why in the “Building an
XML Web Service with VS.NET” section later.
Additionally, you’ll see a References folder that shows all of the .NET classes your pro-
ject is referencing, such as System, System.Web, and so on.
92 Hour 6
For more information on the global.asax and web.config, see Hour 22,
“Publishing an XML Web Service.” For more information on .disco files, see
Hour 5, “Finding XML Web Services with UDDI and Disco” or Hour 22.
Take some time to explore the interface, as it will be helpful to you later on. Also, try
adding and removing files, typing in some code, and using the Toolbox (upper right-hand
corner) to add elements to your pages by dragging and dropping.
Let’s take a look at the files created by VS.NET. First, in the “My Documents” directory
(c:\Documents and Settings\username\My Documents), you’ll notice a new folder,
named Visual Studio Project. Inside this folder will be subfolders—one for each new
VS.NET project you create. Inside the MyWebService folder is the solution file for your
project. This file serves as a collection of the items you add to your project—files,
resources, and so on; it acts as a container.
Next, go to the root Web directory (c:\Inetpub\wwwroot\), where you’ll see a folder
named MyWebService. This is where all your individual files will be kept. You should see all
the files shown in the Solution Explorer, including global.asax and Service1.asmx. Most
of the files in this directory are plain text, so if you ever get tired of the VS.NET interface,
you can open these files in your favorite text editor and continue to work on them.
continues
Visual Studios Environment or Server Setup 93
We won’t cover this in depth because you’ll be learning it in detail in the next hour. Line 1 is a
VB.NET command that tells your application that it will need the objects in the
System.Web.Services .NET namespace. This namespace has all the objects, methods, and
properties you’ll need to create your XML Web service. Lines 4 and 5 declare the name of 6
your XML Web service and declare that it inherits from the System.Web.Services.-
WebService object. That is, your XML Web service will automatically contain all the methods
and properties from the aforementioned object; thus, they are inherited.
Finally, lines 7–33 contain code that is generated by VS.NET. It is used to allow VS.NET
to control your service. You shouldn’t modify this code, so let’s move on.
This service will send only a string to the clients, who can do with it whatever they wish.
Type the code in Listing 6.2 after line 34.
Again, you’ll learn more about the syntax of this function in the next hour. For now, just
know that any method you want your XML Web service to expose to clients must have
the <WebMethod()> attribute before the declaration of the function.
On line 2, you simply assign the string “Hello World” to the function name, which
effectively sends that string to the client when this function is called.
Note that VS.NET is a very smart IDE. If you make simple mistakes while typ-
ing, or if you type in the wrong syntax, VS.NET tries to correct it for you. For
example, replace line 1 with the following:
Public Function <WebMethod()> HelloWorld() As String
VS.NET will automatically reformat the line so it looks like line 1 from Listing
6.2. Talk about a smart IDE! Don’t forget to save the changes you made.
When placed in the special \bin directory, .NET knows that it must load this file when-
ever your application is requested by a client. That way, any files in your application can
access the functions that are compiled in this file. The Service1.asmx file, when
requested by a client, will then access the compiled Service1.asmx.vb file and use it to
process the commands sent by the client.
So the next step is to compile Service1.asmx.vb. Under the Build menu in
VS.NET, select Build. This will compile your files and make your service ready for
action. Before you do that, though, let’s take a look at the \bin directory
(c:\inetpub\wwwroot\MyWebService\bin) again.
Visual Studios Environment or Server Setup 95
You should now see two files: MyWebService.dll (the compiled Service1.asmx.vb file)
and MyWebService.pdb. The former, as discussed, is the assembly for your XML Web
service. The latter is known as a symbols file. It allows VS.NET to help you debug
your service—we’ll ignore it for now.
The beta version of VS.NET has a few inconsistencies with the latest versions
of the .NET Framework. When you try to execute your service, you may
receive an error in the web.config file regarding the value “inproc.” VS.NET
inserts this word into your web.config file as all lowercase, when in fact it
should be “InProc.” After this simple change your service should run fine.
FIGURE 6.6
VS.NET’s
preview mode.
The page displayed is known as the service description. It is created by ASP.NET to pro-
vide additional information about your service, including links to the WSDL XML
description and links to any functions you’ve built. Click on the HelloWorld link, and
96 Hour 6
press the Invoke button that appears on the next page. The response that would be sent
from your service to a client is shown in XML:
<?xml version=”1.0” encoding=”utf-8” ?>
<string xmlns=”http://tempuri.org/”>Hello World</string>
That’s all there is to it! You’ve successfully built an XML Web service using Visual
Studio.NET. In the rest of the book you can now use this IDE to develop your applications.
FIGURE 6.7
Adding a reference to
your XML Web service.
Visual Studios Environment or Server Setup 97
Three links are provided: one for Microsoft’s UDDI server (see Hour 5), one for a test
server, and one to view to services on your local computer, which is what you want.
Click the third link, “Web References on Local Server.” This will bring up the dialog
shown in Figure 6.8.
FIGURE 6.8
The projects on your
local computer.
The left-hand pane shows a .disco file for your server. In the right-hand pane,
you’ll see references to your projects. Click on the first link,
http://localhost/MyWebService/MyWebService.vsdisco. The right-hand pane will be
replaced with links to the service’s WSDL service description. Click on the Add
Reference link in the bottom of the window to finish this step.
In the Solution Explorer, you should now see a new folder called Web References.
Under this you’ll see localhost (your server) and under that a few files: Reference.map,
Service1.wsdl, Service1.vb, and MyWebService.disco. Service1.wsdl is the service
description of the XML Web service, and MyWebService.disco is simply a copy of the
.vsdisco file that VS.NET created for your service. Reference.map simply tells you 6
where these files were created on your computer. To figure out what Service1.vb is,
let’s examine what VS.NET did when you added the Web reference.
Service1.vb may not be visible to you when you first open the Solutions
Explorer. If it is not, click the “show all files” button at the top of the
Solutions Explorer. After you have done that, Service1.WSDL should have a
plus sign next to it. Clicking this will expand the entry and allow you to have
access to the previously hidden Service1.vb file.
98 Hour 6
VS.NET invisibly accessed the MyWebService XML Web service and examined the
WSDL service description. Using this, it created a proxy class. This proxy class is
responsible for one thing—encapsulating the mechanism for you to send and receive
calls to the XML Web service, so you don’t have to worry about it. In other words, send-
ing and receiving messages involves a few steps that are rather complicated and that
we’d rather not have to deal with. Thus, the proxy class was generated to make our lives
easier.
continues
Visual Studios Environment or Server Setup 99
This file can get pretty complex, but as long as you know what it is for, you don’t need
to know the details. In fact, that’s what this class is for—hiding the details of accessing
an XML Web service. When you compile this file, it will also be placed in your project’s
\bin directory for use with the rest of your application.
Return to the Solutions Explorer and click on WebForm1.aspx again. This time, click on
the View Code button at the top of the Solutions Explorer; this option is also available
for the View Menu. This brings up the WebForm.aspx.vb form, which, as mentioned ear-
lier, is the code that runs behind the actual ASP page. Go to the Page_Load event and
type in the code in Listing 6.4. Don’t worry too much about what it does; you will see
that in future chapters.
6
LISTING 6.4 The Code to Access Your Service
1: Private Sub Page_Load(ByVal sender As System.Object, _
2: ByVal e As System.EventArgs) Handles MyBase.Load
3: ‘Put user code to initialize the page here
4: Dim objService As New localhost.Service1()
5:
6: lblmessage.text = objService.HelloWorld
7: End Sub
100 Hour 6
Select Build from the Build menu, and then right-click WebForm1.aspx and click View in
Browser. You should see Figure 6.9.
FIGURE 6.9
The output from
your XML Web
service client.
The output “Hello World” is now displayed. Let’s examine the process of calling your
XML Web service in more detail:
1. Line 4 in Listing 6.4 created a new instance of your proxy class, not the XML Web
service.
2. Line 6 makes a call to the HelloWorld function of the proxy.
3. The proxy creates a SOAP message based on the function you called and any para-
meters you passed in and sends the message to the service.
4. The service received the SOAP message, executed the function instructed
(HelloWorld, in this case), and sent the output as XML back to the proxy.
5. The proxy received the XML message, parsed it, and returned only the return value
from the HelloWorld function.
6. Your ASP.NET page then displayed this output in the label control that you place
in the designer.
It’s a relatively lengthy process, but recall that you wrote very few lines of code!
VS.NET handled steps 2–5, and all you were left to do was call the function and display
the results. This process can be repeated for any XML Web service you find, no matter
where on the Internet it is.
Visual Studios Environment or Server Setup 101
Summary
The Visual Studio.NET environment is integrated to allow you to develop any .NET
application from a central location. In this hour, you used it to create two projects: an
XML Web service and an XML Web service client.
To create the XML Web service, you needed only to create a new XML Web service pro-
ject from VS.NET’s list of choices. All the necessary files were created for you, and all
you had to do was add a 3-line function to the service to make it functional. Don’t forget
to select Build from the Build menu so that your application will be compiled and the
appropriate assemblies created. The View in Browser option allows you to preview the
service as if you were a potential client.
To build a client, you created a new Web application project and added a Web reference
to your XML Web service. VS.NET created some additional files for you, including the
proxy class that acts on your behalf to call the XML Web service. This class encapsulates
all the complexity of making Internet calls so you don’t have to deal with it. Then you
simply added some code to an ASP.NET file and called your XML Web service, display-
ing the results in a label.
VS.NET is a very powerful tool, as you learned today, hiding much of the complexity of
creating applications. In the next few hours, you’ll put this knowledge to use to create a
useful calculator XML Web service.
Q&A
Q I hate this VS.NET auto-complete mechanism. Can I turn it off or customize
VS.NET?
A You bet. To turn off the auto-complete, go into the Options under the Tools menu.
In the Environment folder, select General, and then uncheck “Enable Command
Window autocompletion.”
Additionally, you can customize the IDE to look however you want. Drag each win- 6
dow’s title bar around to find the look and feel you prefer. You can close any win-
dow by clicking on the little ‘x’ icon or by highlighting the window and selecting
Hide from the Window menu.
Q Do I have to put my service code in the .asmx.vb code-behind file?
A No, you can place your code directly into your .aspx pages via the HTML view, but
this does violate the basic reason for having the asmx.vb code behind in the first
place. The .aspx.vb files allow developers to separate form and function, allowing
for greater ease of maintenance and design. If, at some stage, you find yourself
102 Hour 6
working with teams of Web Developers, it is much easier to allow the Web designer
to make their changes without fear of breaking the ASP.NET code, as well as allow
the actual ASP developers to work without fear of breaking HTML content.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. What is a proxy class, and what does it do?
A A proxy class is auto-generated by VS.NET and contains methods that receive
and send XML and SOAP messages, so you don’t have to build them yourself. You
can interact with the proxy class just as if you were interacting with the XML Web
service directly.
2. What is the <WebMethod()> attribute?
A Any functions that you wish to expose in your Web client (that is, make avail-
able to clients) must have this attribute. It is placed immediately before the declara-
tion of the function.
3. What is the web.config file used for?
A It contains configuration settings for your application.
4. What is the file extension for assemblies?
A .dll
A Yes. You didn’t create an instance of the proxy class. Add the following code
after line 4:
dim objService as New Calculator.Calculator
Exercises
1. It’s time to create an XML Web service and client on your own. Create an XML
Web service, in VS.NET, that returns the current time. Don’t forget to build and
test it!
A Create a new XML Web service project in VS.NET and name it TimeService.
Open the Service1.asmx file and change its filename (in the Properties box) to
TimeService.asmx. The code (not including VS.NET auto-generated code) for this
file is as follows:
<WebMethod()> Public Function CurrentTime() As DateTime
CurrentTime = System.Date.Now
End Function
Build the project (Build menu, Build), right-click TimeService.asmx, and select
View in Browser. You should now be able to test the output of your function.
2. Build the client for your TimeService service.
A Create a new Web application project in VS.NET and name it
TimeServiceClient. Add a Web reference to your TimeService service by going
to Project, Add Web Reference, Web References on Local Web Server, and select
the TimeService service. Click Add Reference. Insert the following code into
WebForm1.aspx.vb and place a Label on the designer
service the needed functionality. For this demonstration, we will create a very
simple design.
My suggestion for designing an XML Web service is to list all the functions that
you plan to expose in this manner:
Public Function Add(ByVal iNum1 as Integer, ByVal iNum2 as Integer) as Double
The preceding function declaration uses standard VB notation to describe input parame-
ters, their variable types, and the return type.
The actual function declarations in an XML Web service are slightly different.
This declaration is just to be used for the conceptual design of your service.
We want client applications to be able to use our service to add, subtract, multiply, and
divide two integers. We will return a double in each instance. All the function declara-
tions look identical to the one for Add, so I won’t repeat them here.
FIGURE 7.1
Creating the new XML
Web service project.
Building the Four Function Calculator 107
1: [WebMethod]
2: Public String HelloWorld()
3: {
4: Return “Hello World”
5: }
Obviously, your calculator doesn’t use the Hello World function, so you will leave the
example code commented out, but it nicely reminds you what our calls should look like.
7
If you create an XML Web service and find that some of your methods cannot
be called from your client application, go back and check that you have
included the <WebMethod> tag in your calls. Failure to include this tag will create
methods that are exposed only to code within your XML Web service project.
108 Hour 7
The second is the declaration of your service class, which has the following form:
Public Class ServiceName Inherits System.Web.Services.WebService
These two lines of code will exist in every XML Web service that you create, and they
give you access to the framework of the XML Web services architecture. By building
your class upon the WebService class, you can override the WebService constructors and
destructors as well as add new methods.
The Web Service Template Project in Visual Studio .NET will include
WebService namespace and class declarations for you. Removing or altering
these lines is a surefire way to ensure that your service doesn’t function.
continues
Building the Four Function Calculator 109
Our four-function calculator doesn’t require any initialization code, so we will leave the
constructor as it is at this point. In Hours 11 and 17, we will see several examples of
using the New() method in XML Web services.
.NET also allows you to add a method called Finalize. Finalize is the actual destructor
of the service. In traditional object-oriented programming, this is where you would do 7
your cleanup. Under the .NET model, however, both Dispose and Finalize can be
called by the garbage collector. This is done with no guarantee as to the order in which
those calls will be made or even as to when they will occur during execution. In fact,
110 Hour 7
Microsoft goes so far as to caution that you cannot guarantee that the Finalize method
will ever get called. Indeed, if you create a service and test for this method, you will see
it occur infrequently.
Because of this, I recommend using Dispose for all your cleanup code and explicitly
calling it in all your client applications. Finalize should then be used as a backup to
ensure that references are dropped in the event that Dispose is not called explicitly by
client code.
You will use the Dispose and Finalize methods heavily in Hours 14 and 17. Until then,
just know that these methods are how you can exit your service gracefully.
C# programmers should have no trouble at all creating the other three methods after
looking at the example. Simply copy the Add() method three more times, being very
careful to include the [WebMethod] tag above every method that you intend your XML
Web service to expose. Then, rename each method to correspond to the three additional
methods in Listing 7.4, and change the plus sign to the corresponding mathematical
symbol.
To add a description to your Add() method, for example, change the <WebMethod> decla-
ration as follows:
<WebMethod(Description:=”This is a function to add two integers”)>
The description will show up in the services WSDL file, which we described in Hour 3,
and when you run the service. Figure 7.4 shows the Add() method with the new
description.
Using Regions
You may have noticed that the first line of code in Listing 7.4 contained a #Region com-
piler directive. For those of you who haven’t discovered regions in your use of .NET,
they are an extremely useful new element.
A region is a related group of code, possibly a group of functions, such as our four math-
7
ematical functions, that can be minimized by the developer. This allows you to “close
down” code that you aren’t currently working on and view only that which is important
at the moment. This makes the code window much easier to navigate.
112 Hour 7
“Region Name” represents any meaningful description of the region that you care to
enter. After this line is added, navigate to the end of the area of code that you want to
include in this region and add this line:
#End Region
Figure 7.2 shows the region in our four-function calculator. Notice the minus sign next to
our new region. This allows us to minimize the region. The plus sign next to the line
“Web Services Designer Generated Code” can be used to open up the group of functions
included in our code when we first created the service.
FIGURE 7.2
Regions in action.
Building the Four Function Calculator 113
7
114 Hour 7
FIGURE 7.3
Our four-function
calculator in Internet
Explorer.
The Internet Explorer interface to your service is very slick and can be used to expose a
lot of information to potential users. Notice in Figure 7.3 that the names of all of your
methods are listed. Also note that you are provided with a link to the WSDL contract.
This is a very important feature; you will make use of this link in just a few moments.
By clicking on any of the method names, you will be taken to a page that Internet
Explorer includes for each of your methods. In these pages, you are shown the names of
input parameters and the variable type to be returned by the method, as well as SOAP,
HttpPost, and HttpGet return and response information.
You are also given a Web form with which to use each method. Figure 7.4 shows your
Add Method in Internet Explorer. Type a few values for the Add method and click on the
button labeled “Invoke.”
Internet Explorer now opens a new window containing the XML that will be returned to
clients that use your service (see Figure 7.5). Notice that you receive your value wrapped
in XML tags that contain the data type being returned. This allows your client applica-
tion to type check data in much the same way that COM applications do.
Building the Four Function Calculator 115
FIGURE 7.4
Using the Add method
of your XML Web
service.
FIGURE 7.5
The answer returned
by your XML Web
service.
7
Creating an XML Web Service Contract
As we discussed in Hour 3, an XML Web service is defined using a WSDL contract.
This WSDL contract file is then used by .NET to create proxy classes that allow client
applications to interface with the XML Web service. You will build your first proxy class
in Hour 8 when you create a client-side interface for the Four-Function Calculator.
116 Hour 7
Creating the WSDL file is extremely easy. If you look back at Figure 7.3, you will see a
link to the WSDL file near the top of our ASMX file labeled Service Description. If you
click on this link, the entire WSDL file will be opened in Internet Explorer. Figure 7.6
shows a portion of the WSDL file used to define the calculator service. Simply save this
file to disk as Service1.WSDL and you are done. Client applications can now be devel-
oped that use your XML Web service.
FIGURE 7.6
This WSDL file acts as
a contract between the
Four-Function
Calculator and client
applications.
When you deploy your service on a different server, you will have to create a
new WSDL contract file because the complete path of your service is listed in
the WSDL. In Figure 7.6, you can see the path to the FourFunctionCalc listed
in SOAP <address> space. Failure to create a new SDL file may cause a client
application to point to the wrong server and thus cause your XML Web ser-
vice to fail.
LISTING 7.6 ASP Code for Creating the SmallCalc XML Web Service
1: <%@ Web Service Language=”VB” Class=”SmallCalc” %>
2:
3: Imports System
4: Imports System.Web.Services
5:
6: Public Class SmallCalc:
7:
8: <WebMethod()> Public Function Add(iNum1 as Integer, _
9: iNum2 as Integer) As Double
10: Return (iNum1 + iNum2)
11: End Function
12:
13: End Class
The first item that you should notice is the header of the ASP file (line 1 in Listing 7.6).
The addition of the Web Service tag lets the ASP compiler know that you are building a
service.
Line 4 of the code is where you import the System.Web.Services namespace. This
namespace contains the Web Service class that our class, SmallCalc, is built upon. This
is done when SmallCalc is declared, in line 6, as inheriting from Web Service.
Last, note that the function declaration for Add(), line 8 of Listing 7.6, is identical to the
declaration used in your Visual Basic code, line 2 of Listing 7.4.
You should be able to add the other three functions to this code and create the WSDL
contract file for this service. Doing so should help get you used to working with XML
Web services.
In ASP.NET, asax and asmx files are compiled on their initial use. This means
that, even if you use Notepad to create your files, you create robust applica-
tions built on native code.
Summary
In this hour, you learned the steps of creating simple XML Web services and running
them in .NET. You also learned about some of the important methods that take place 7
inside a service, and you looked at the SDL contract and the steps used to create one.
You ended with a brief lesson in how to create XML Web services with simple ASP
tools, including Notepad.
118 Hour 7
Q&A
Q Why use Visual Studio if the .NET Framework allows you to create XML Web
services in Notepad?
A Although Notepad is sufficient for the small examples that you worked on in this
hour, your code will quickly become more difficult to manage without the help of
Visual Studio. The ability to create code regions, place code in modules, access
help files, and use a myriad of other features provided by Visual Studio will prove
invaluable when you begin creating real-world services.
Q Can a single XML Web service project provide multiple services?
A Yes, you can add multiple services to your XML Web service project. These ser-
vices are all compiled as different asmx files and share the same Global.asax file.
For example, we could have added a second set of functions to our calculator to
support working with hexadecimal numbers. We could have placed these functions
in a second service and allowed clients to access them separately. In future hours,
we will see examples of XML Web service projects that expose multiple services.
Q Is adding the optional description to methods worth the extra effort?
A Yes, it certainly is. If your methods are exposed to external clients, life is much
simpler if they can see a small description of each method when they write code to
use your service. Even if your methods are exposed only internally and used only
by the people who wrote them, you will eventually forget what some functions do;
having these little reminders can save you the trouble of having to look up refer-
ence material or seeking out the source code to read the comment lines.
Workshop
The workshop is designed to help you review what you’ve learned in this hour and to
prepare you for the material that will be covered in future hours. The answers to the quiz
are in Appendix A.
Quiz
1. You have created an XML Web service that compiles correctly but when run
exposes no methods. Why?
A You forgot to include the <WebMethod()> declaration in your code.
2. Why is it important to create a new WSDL file after deploying your XML Web ser-
vice?
A The original WSDL file points to your development server, not the location
where the service has been deployed.
Building the Four Function Calculator 119
3. You need to close down a connection to a database and drop some object refer-
ences. Where should this be done?
A The Dispose() method is where XML Web services do their cleanup.
Exercises
Experiment with the four-function calculator. Try creating other simple mathematical
functions, such as squaring an integer, returning the sine and cosine of a number, or
returning the value of pi to some user-requested number of decimal places. You can cheat
on that last function by simply storing pi as a constant of some arbitrary length and
rounding it to fit the user’s request.
A. The following code could be added to your FourFunctionCalc code to create a
squaring function:
1: <WebMethod()> Public Function Squared(iNum1 as Integer) _
2: As Long
3:
4: Return (iNum1 * iNum1)
5: End Function
7
HOUR 8
Windows Client for the
Four Function Calculator
In this hour, you will learn to create client applications that consume
XML Web services. You will also learn how to create proxy classes that
enable your application code and XML Web services to easily communi-
cate via SOAP messages. Also in this hour, you will see how to use the
WebServiceUtil.exe file to accomplish many important XML Web
service–related tasks.
In this hour, we will discuss the following items:
• Consuming XML Web services
• Using dialogs to create proxy classes
• Adding Web references
• Using the WSDL.exe
122 Hour 8
FIGURE 8.1
The client for the four
function calculator.
Proxy Classes
To use your four function calculator XML Web service, you need to create a proxy class
to handle the calls to your service. What the proxy class does is expose methods to your
application that are identical to the methods used by the XML Web service. For example,
Windows Client for the Four Function Calculator 123
if you have an XML Web service method named Chance that accepts an integer and a
string and returns a long, your proxy class will also have a method named Chance that
accepts and integer and a string and returns a long.
8
Behind the scenes, the proxy class wraps your parameters (an integer and a string in this
example) into a SOAP call to the Web class method (Chance in this case). The Web class
then returns a SOAP package containing the long return value to the proxy class, which
unwraps it and passes the long value to your application.
If you wish to review how to use UDDI in searching for XML Web services,
reread Hour 5.
FIGURE 8.2
Using the Web
Reference dialog.
124 Hour 8
Now Visual Studio brings up a list of all the discovery (DISCO) files as Linked
Reference Groups, related services that are usually members of the same project, on your
local server (see Figure 8.3). Search through this listing and find the URL to
FourFunctionCalc.disco.
FIGURE 8.3
Finding the XML Web
service on the server.
After you select the link to an XML Web service (in this case, Service1 of your
FourFunctionCalc Group), the discovery file is displayed on the screen, and you are
provided with links to the contract and documentation for this service (see Figure 8.4).
These links are important when you are using multiple XML Web services to develop
applications and you cannot remember what they all do.
Choose the link View Documentation to bring up the auto-generated documentation files
(seen in Figure 8.5) that you became familiar with in Hour 7. If you choose the View
Contract link, the XML Web services WSDL file is displayed in place of documentation
file in Figure 8.5.
The ability to understand the XML syntax of the WSDL document is a major
boon when you are trying to decide whether a given XML Web service
meets the needs of your application. If you are having trouble deciphering
the WSDL files, go back and reread Hours 2 and 3 again.
Windows Client for the Four Function Calculator 125
FIGURE 8.4
Viewing the DISCO
file of the XML Web 8
service.
FIGURE 8.5
Viewing the documen-
tation of the XML Web
service.
After you have navigated to the service that you wish to reference in your project, click
the Add Reference button and Visual Studio.Net will add the appropriate reference to
your project and create a proxy class for the service.
126 Hour 8
Now that Visual Studio.NET has created the proxy class for you and included it in your
CalcClient application, you can add any other references that you need for your project.
In this case, you will need to add a reference to the System.Web.Services.dll. This
DLL exposes some extra functionality that comes in handy when developing XML Web
service clients, and it is good practice to include it in your client applications.
To add the System.Web.Services.dll to your project, choose Add Reference from the
Project menu. This brings up the Add Reference window, shown in Figure 8.6. Double-
click the System.Web.Services.dll to display it in the bottom window, Selected
Components. Once you have done this, you can click Okay to close the window and add
the reference to your project.
FIGURE 8.6
Adding a reference
to the System.Web.
Services.dll.
If you are using C#, your object declaration should be the following:
localHost.Service1 oCalc = New localhost.Service1;
Windows Client for the Four Function Calculator 127
With the new oCalc object created in your application, you can begin using the methods
of the XML Web service, via the proxy, in your application. The general syntax for call-
ing a XML Web service’s method is
8
proxyObject.MethodName(args)
where proxyObject is the name of your object, oCalc is the case of your CalcClient
application, and MethodName is the name of the method that you are trying to access. Any
arguments that the XML Web service’s method expects are represented by args.
One tremendous benefit of the proxy class is that, because it contains local
methods for all the methods exposed by the service, it allows you to take
advantage of Visual Studio .NET’s autocompletion features. This saves you
from having to memorize all of the function calls and their methods when
you try to implement a service in your applications.
Listing 8.1 shows the Visual Basic code to add the FourFunctionCalc methods to the
button-click events of your form. Each of the calls uses the CInt function to convert the
contents of the text boxes into the integer variables that the method requires. You then
use the ToString method to convert the type long answer returned by the service’s
method into a string that can be displayed in the output text box.
Once you have finished coding the button-click events, save your project. Now, choose
Start from the Build menu, or simply press F5. This will start the CalcClient applica-
tion, shown in Figure 8.7.
FIGURE 8.7
The four-function cal-
culator at work.
Try typing some variables and testing that the code works. Remember that we have not
added any code to ensure that only integers are typed into the text boxes. If you wish
to add code to ensure that the data entered into TextBox1 and TextBox2 is of type inte-
ger, you are free to do so.
Windows Client for the Four Function Calculator 129
Table 8.1 shows the various switches used by the WSDL.exe application. The switches
pertaining to working with a proxy server and to switching base URLs have been left
out. If you need to accomplish one of these tasks, you can get help by simply typing
Wsdl /?
The out switch and path or url are the two settings that you will need to concern your-
self with the most when creating proxies. In order to create a proxy, the out switch needs
to be set to a valid file name—for example, SomeName.VB, in the case of a Visual Basic
proxy. The path needs to be set to the URL or local file path of the Web Service’s
WSDL file.
It is a good idea to use a tool such as Internet Explorer to confirm the path
to a Web Service’s WSDL file before you enter it into the WSDL.exe’s path
switch. Errors will result if the path switch has the utility pointing to an
incorrect URL.
LISTING 8.3 Using WSDL.exe to Create a Proxy Class for the Four-Function
Calculator
C:\>WSDL.exe /language:CS /namespace:FourCalc /out:c:\Captures\FourCalc.cs
http:\\localhost/FourFunctionCalc/Service1.asmx?sdl
You can use the optional language tag to create the proxy class in Visual
Basic if you wish to examine the code and are more comfortable with Visual
Basic. There is almost never a reason to alter this class yourself. For the pur-
poses of this example, you can let the proxy be created using the default
language, C#.
Figure 8.8 shows how the DOS window should appear if you have successfully created
your proxy class.
Now, you can compile the class into a usable dll. This can be done by either opening the
class in Visual Studios, or by using one of the command line compilers that ships with
the .NET framework. Those compilers, reachable through a DOS prompt, are csc, to
Windows Client for the Four Function Calculator 131
FIGURE 8.8
Creating the Four
Function Calculators 8
Proxy Code
compile C# code, and vbc, for compiling Visual Basic code. With these compilers, it is
possible, though not at all advisable, to write complete programs in a Word Processor,
even one as simple as Notepad, and compile them.
Listing 8.4 shows the command syntax for compiling your C# class.
The /t or target switch is set to library, which lets the compiler know that you are try-
ing to create a DLL. The /r or reference switch tells the compiler to include a reference
to System.Web.Services.dll.
The final switch of the command is the /out switch, which sets the name and path of the
DLL you wish to create. In this case, you are creating a DLL called FourCalc to be placed
in the directory c:\Book. You may feel free to change the directory to whatever you like.
132 Hour 8
The last portion of the command is the path to the proxy class that was created by the
WSDL.exe, c:\Captures\FourCalc.cs or whatever path you saved the file to.
To obtain help on the csc, C# compiler, type in the following command at a DOS
prompt:
csc /?
In order to obtain help on the Visual Basic command line compiler, vbc, type the follow-
ing in at a DOS prompt:
vbc /?
These compilers include the ability to generate bug reports, link additional resources, set
precompiler directives, and much more.
FIGURE 8.9
Adding a reference to
the four function cal- 8
culator’s proxy.
FIGURE 8.10
Adding all the refer-
ences to the four
function calculator.
After creating the oCalc object, you can add code to the button events of Form1. The code
for these events is identical to that of the CalcClient application, shown in Listing 8.1.
You can now run the application and verify that both versions of the four-function calcu-
lator’s clients behave in exactly the same manner.
134 Hour 8
Summary
In this hour, you learned how to create proxy classes that help your applications use
XML Web services. You also learned how to declare XML Web services in your code
and to use their methods. Finally, you used the WSDL.exe to create proxy classes that
were used by a client application.
Q&A
Q Is it necessary to create a proxy class for my XML Web service clients?
A Yes. The alternative to creating a proxy class via one of the tools described in this
hour is to write all of the SOAP-handling functionality yourself and, for all intents
and purposes, to recreate a proxy from scratch. This may be interesting as a learn-
ing exercise but is not practical for most development scenarios.
Q Is there a way to create a single class that can broker selected references from
several XML Web services?
A It is possible to create a single class that handles the methods of multiple XML
Web services. This is done using WSDL.exe. To selectively eliminate unwanted
methods from the resultant class, you have to directly remove them from the
generated source code before compiling. This is beyond the scope of this book;
attempting to alter these files can cause them to fail.
Q Is there ever a reason to use WSDL.exe if you have Visual Studio .NET?
A Yes, there are several reasons. The first is that WSDL.exe allows you to create a
class from multiple XML Web services at one time. This allows one class to serve
all of your XML Web service functions, or at least to group together related ser-
vices into several classes. The second reason is that you can control the location of
the output DLL, making it easier to create one DLL and reuse it in multiple pro-
jects. You should expect Microsoft to add many of these features to the Web
Reference dialogues in future releases.
Workshop
The workshop is designed to help you review what you’ve learned in this hour and to
prepare you for the material that will be covered in future hours. The answers to the quiz
are in Appendix A.
Windows Client for the Four Function Calculator 135
Quiz
1. Where is WSDL.exe found? 8
A At the DOS prompt of any machine with the .NET framework installed.
2. How do you add a Web reference to a project in Visual Studio .NET?
A By using the dialog displayed by Add Web Reference under the Project menu.
3. How do you create a new object, called oService, based on the Accounting class
of a XML Web service DLL called AccountSoft
A In Visual Basic:
Dim oService as new AccountSoft.Accounting
In C#:
AccountSoft.Accounting oService = new_ AccountSoft.Accounting
Exercises
Create code for any new method that you added to the four-function calculator in the last
hour. Also, if you have created any new XML Web services, try creating clients for them
as well.
Here is the code for the squaring function that was added at the end of Hour 7.
Public Sub Button5_Click(ByVal sender As Object, _
ByVal e As System.EventArgs)
TextBox3.Text = oCalc.Squared(CInt(TextBox1.Text)).ToString
End Sub
HOUR 9
Web Clients for the Four
Function Calculator
In this hour, you will look at the standard HTTP protocols httpGet and
httpPost, and you will learn how to use them to make requests of XML
Web services. You will make further use of these protocols in building
client applications that work on operating systems that are not running the
.NET platform. Finally, you will learn about the XML Web service method
and how it can be used to create Web-embedded scripts that make calls to
XML Web services.
Throughout this hour, we will discuss the following:
• Accessing XML Web services via httpGet
• Using httpPost to access XML Web services
• Building clients using Get and Post
• The XML Web service method
138 Hour 9
LISTING 9.1 HTML Form Using httpGet to Access the Four Function Calculator
1: <html>
2: <head>
3: <title>Four Function Adder httpGet Client</title>
4: </head>
5:
6: <body>
7: Add Method
8: <form METHOD=”GET” target=”_blank” 9
9: action=’http://localhost/FourFunctionCalc/Service1.asmx/Add’>
10: <input type=”text” size=”50” name=’iNum1’\”>
11: <input type=”text” size=”50” name=’iNum2’\”>
12: <BR>
13: <input type=submit value=”Invoke”>
14: </form>
15: </body>
16: </html>
The important thing to notice here is the action method of the form in line 8. Notice that
you call the XML Web service directly from its URL and not via some reference to a
proxy application. When you run this in a browser and click the Invoke button—see
Figure 9.1—the answer will be brought up in a new window.
FIGURE 9.1
The Add method of the
FourFunctionCalc
XML Web service via
httpGet.
140 Hour 9
Note the URL inside of the new window. This address can be used to directly contact the
XML Web service and request a method. Try typing the following URL directly into
Internet Explorer:
http://localhost/FourFunctionCalc/Service1.asmx/Add?iNum1=4&iNum2=4
If you change the values of iNum1 and iNum2 and refresh the screen, the
FourFunctionCalc’s Add method will be called with those values. This will be useful to
you when you create an httpGet client application later in this hour.
When you run this example, see Figure 9.2, you will note that the parameters string is
not appended to the end of the requesting URL. This means that you will need to pack-
age variables into the packet sent back to the Web server.
It should be noted that httpPost and httpGet could have been used inter-
changeably in the example above. Keeping that in mind, httpPost is generally
the preferred method, next to the SOAP method demonstrated in Hour 8, for
communicating with Web services. This is due to the manner in which each
sends arguments across the Intenet. HttpGet, the older protocol, simply
appends the arguments to the end of the URL and is therefore a much less
secure method of transmitting data.
Web Clients for the Four Function Calculator 141
FIGURE 9.2
The Add method of the
FourFunctionCalc
XML Web service via
httpPost.
Much of the code in this section is written in Visual Basic 6.0. If you do not
have Visual Basic 6.0 available to you for these projects, you could adapt the
code to work in other languages, including any language found in Visual
Studio .NET. Although Visual Studio would normally provide a proxy, you
can still write your code this way as a learning exercise.
Open a new Standard EXE project in Visual Basic 6.0 and call it GetCalc. To this project
we will add the Microsoft Internet Transfer Control to handle all of our HTTP communi-
cations with the Web server. To add this component, choose Components from the
Project menu. This will bring up the Components Dialog seen in Figure 9.3. Find the
Microsoft Internet Transfer Control and check it, and then select Okay.
Now add three text boxes and four buttons to the form, as shown in Figure 9.4. The four
buttons should be in a control array, but the three text boxes should not. Set the
TextBox3, the large text box at the bottom of the form, MultiLine property to True.
Then add an Internet Transfer Control to the form. Don’t worry about where you place it,
as it is invisible at run time.
142 Hour 9
FIGURE 9.3
Adding the Microsoft
Internet Transfer
Control.
FIGURE 9.4
The Visual Basic 6.0
form for GetCalc.
A control array is a group of controls of the same type, that is, Textboxes,
Listboxes, and so on, each having the same value for their name property.
These controls are then distinguished by an integer-valued index in the same
manner as other arrays that you have worked with. The easiest way to cre-
ate a control array is to place a control upon a form and set its properties.
Then, when this is done, use copy and paste to create additional copies of
the control. Visual Studios will prompt you to ask if you wish to create a
control array.
Use the code in Listing 9.3 to initialize the Internet Transfer Control, named Inet1, to
work with HTTP.
Web Clients for the Four Function Calculator 143
Now add the code in Listing 9.4 to the Click event of the button array.
9
LISTING 9.4 Using httpGet to Communicate with an XML Web Service in
Visual Basic 6.0
1: Private Sub Command1_Click(Index As Integer)
2: Dim sType As String
3:
4: Select Case Index
5: Case 0
6: sType = “Add”
7: Case 1
8: sType = “Subtract”
9: Case 2
10: sType = “Multiply”
11: Case 3
12: sType = “Divide”
13: End Select
14:
15: Text3.Text = Inet1.OpenURL(“http://localhost/FourFunctionCalc/
Service1.asmx/” _
16: & sType & “?iNum1=” & CInt(Text1) & “ &iNum2=” & CInt(Text2), icString)
17:
18: End Sub
The first portion of the code, the Select statement, merely determines which calculator
function button you choose and stores the name of the corresponding XML Web ser-
vice’s method to a string variable called sType.
In line 15, you set the OpenURL property of the Internet Transfer Control to the URL of
the service. The OpenURL method of the Internet Transfer Control sends a URL request to
a server and returns a string containing the returned HTML or XML document. Notice
that, after the URL, name-value pairs are appended to the URL.
When you run the GetCalc program, as shown in Figure 9.5, the return value is currently
the entire SOAP return message from the FourFunctionCalc XML Web service.
There are several ways that you could deal with this return-value SOAP document. The
first would be to use an XML handling Library, such as MSXML 3.0. This works fine,
and in fact, you will use it in the next example. Another method is simply to parse the
144 Hour 9
FIGURE 9.5
Running the GetCalc
client application.
returned string. Since you know that the resulting SOAP message will always be of the
same format, you can just drop the XML tags and keep the number value. Listing 9.5
shows an example of some code that may be added to your button click event in order to
reduce the return value to just the expected numeric result.
LISTING 9.5 Parsing the String Returned from the FourFunctionCalc XML Web
Service
1: sReturn = Inet1.OpenURL(“http://localhost/FourFunctionCalc/Service1.asmx/” _
2: & sType & “?iNum1=” & CInt(Text1) & “ &iNum2=” & CInt(Text2), icString)
3: sReturn = Right(sReturn, Len(sReturn) - 59)
4: sReturn = Left(sReturn, InStr(sReturn, “<”) - 1)
5: Text3.Text = sReturn
If you replace line 15 in Listing 9.4 with the code in Listing 9.5, remember to declare the
variable sReturn as type String before using it, and then run the program. You now have
a calculator that returns a more conventional result (see Figure 9.6).
FIGURE 9.6
Returning the parsed
value from the
FourFunctionCalc
XML Web service.
You will not need the Internet Transfer Control for this example. Instead, you will be
using Microsoft’s XML (MSXML) library, which is available for download at
http://msdn.microsoft.com/downloads
Bring up the References Dialog, shown in Figure 9.7, by selecting References from the
Project menu. Search through the listing until you see a listing for “Microsoft XML, v3.0”;
check it and then select Okay.
FIGURE 9.7
Adding a reference to
Microsoft XML v3.0.
With the form set up, you can add the code in Listing 9.6 to the Click event of your
button array.
146 Hour 9
The first section of the code, determining your method name via the Select Case, is
already familiar to you. Lines 18–22 use the XMLHTTP library to send an HTTP request
to the XML Web service.
Line 18 uses the Open method to create the request and set its type to POST. It is here
that we set the URL of the service, as well. Notice that the parameter data is not
appended to the string.
After you open the request, you set the request header to use URL encoding. This ensures
that MSXML sends the data over as an HTML form. This is important if your methods
parameters are to be correctly interpreted by the XML Web service being summoned.
Finally, you use the send method to append the parameters, in name-value pairs, to the
request and send it to the server.
Next, we create a DOMDocument object to hold the returning SOAP document (see line 24 of
Listing 9.6), and we use the object’s Text property to return only the value of the returned
value to Text3. Figure 9.8 shows PostCalc after a successful XML Web service call.
Web Clients for the Four Function Calculator 147
FIGURE 9.8
Running the PostCalc
Client.
At the time of this writing, the Web service behavior only works of the Web
age being called is running in the same domain as the XML Web service
being called. If you are having trouble getting your page to call a service
and you think that you have done all of your coding correctly, try moving
the HTML page into the directory that the service is in. If it doesn’t function
there, then the odds are that you still have a coding error to work out.
148 Hour 9
The XML Web service behavior works through the use of an HTML component call
webservice.htc. This component is placed on the XML Web server along with any
pages that make use of it.
If you are unfamiliar with DHTML and Web scripting, you may wish to come
back to this section after you have gained some experience in those areas.
Figure 9.9 shows an example of a Web page that you can use to consume the
FourFunctionCalc XML Web service.
FIGURE 9.9
The form for the XML
Web service behavior
FourFunctionCalc
client.
The first step in using an XML Web service behavior is to bind it to a DHTML element.
In the example in Figure 9.7, line 47 shows the XML Web service behavior being bound
to a DIV tag. The syntax for binding the XML Web service behavior is as follows:
<tag id=”name” style=”behavior:url(webservice.htc)”>
With the XML Web service behavior bound to a control, you can begin to make refer-
ences to XML Web services. This is accomplished by using the useService method of
the XML Web service behavior to create a service reference as follows:
Tag.useService(“URL”, “name”)
Web Clients for the Four Function Calculator 149
Tag is the name of the tag that the XML Web service behavior is bound to, URL is the
URL of the XML Web service being called, and name is the name that you will use to
refer to the service in code.
Line 10 of Listing 9.7 shows the useService method being used to refer to the
FourFunctionCalc XML Web service. It has been given the name calc for use in further
scripting. Additionally, you could have referenced additional XML Web services from
within this project.
9
When you need to call the service, you use the callService method of the XML Web
service behavior. Lines 35 through 45 show the callService method being used in the
onClick events of the form’s buttons in order to call specific methods of the service. This
is done in the following format:
IRet = Tag.name.callService([“Handler”],”method”, “param1”, “param2”,…”paramn”)
Again, Tag is the name of the DHTML element that the XML Web service behavior is
bound to, name is the name that you gave the service, method is a string containing the
name of the XML Web service method being called, and param1 through paramn are a
comma-separated list of any parameters that need to be sent to the XML Web service.
IRet is the return value of the callService method. This result is an identifier and not
the XML Web service method return. Handler is an optional function name that will
handle the results. The default value for Handler is the onresult property of Tag.
continues
150 Hour 9
Summary
In this hour, you learned to utilize httpPost and httpGet in order to create standard Web
forms that request XML Web service methods. You also learned how to create XML Web
service–consuming applications that run on non-.NET platforms. You ended this hour by
examining the XML Web service method and building a Web page that communicates
with an XML Web service via scripting.
Web Clients for the Four Function Calculator 151
FIGURE 9.10
The Add method of the
FourFunctionCalc
XML Web service via
the XML Web service
behavior.
Figure 9.10 shows the return values for your WebserviceBehavior Web page.
Q&A
Q Can an HTML form using simple httpPost or httpGet protocols be set up to
call different methods of a service by clicking different buttons?
A Yes, you would have to use scripting. Set the Action method of the form equal to a
function in your script and then redirect the form from there.
Q Do I have to use the Internet Transfer Control to communicate with XML
Web services via httpGet?
A No, you can use any library or component that facilitates Internet communications
in order to send your httpGet requests.
Q Is there a way to create Web applications that consume XML Web services
without using the XML Web service behavior and DHTML scripting?
A Yes, you could use ASP in conjunction with any of the other methods that we have
learned. If ASP is not available to your Web page, and you need to fully utilize
XML Web service calls within your document, the XML Web service behavior is
your best bet.
152 Hour 9
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. What is the default method for sending Form requests via HTTP?
A httpGet
2. Where is parameter data stored when requests are sent via httpPost?
A Any data sent via httpPost requests are packaged, as name-value pairs, into the
document that is sent to the contacted service.
3. What method, httpPost or httpGet, can be used to access XML Web services
directly from Internet Explorer’s address bar?
A httpGet is the default method and, thus, the one that can be used by directly
typing URLs into the address bar.
4. Can you consume multiple XML Web services in a Web page making use of the
XML Web service behavior?
A Yes, as long as you give them all unique names, you can consume multiple
services.
5. Using an XML Web service behavior, how would you call a method named
Counter for an XML Web service that you have already declared using the name
Bean? The XML Web service behavior is bound to an element called Navy and
there are no parameters to the method.
A iRet = Navy.Bean.callService(“Counter”)
Exercises
Try experimenting with the different methods of requesting XML Web services. Try writ-
ing some Web pages using httpPost and httpGet. Write some new DHTML code to uti-
lize the XML Web service behavior, such as calling any additional functions that you
created at the end of Hour 7.
A. An httpGet HTML page for the Multiply method.
1: <html>
2: <head>
3: <title>Four Function Adder httpGet Client</title>
4: </head>
Web Clients for the Four Function Calculator 153
5:
6: <body>
7: Add Method
8: <form METHOD=”GET” target=”_blank”
9: action=’http://localhost/FourFunctionCalc/Service1.asmx/Multiply’>
10: <input type=”text” size=”50” name=’iNum1’\”>
11: <input type=”text” size=”50” name=’iNum2’\”>
12: <BR>
13: <input type=submit value=”Invoke”>
14: </form> 9
15: </body>
16: </html>
Following is the code to add Squared (from the Hour 7 exercises) to your XML Web ser-
vice behavior project. Add this code in after the Divide button.
1: <button onclick=’iRetID =
2: ReturnSpace.calc.callService(“Squared”,iVal1.value);’>
3: Square</button>
PART III
Data in XML Web Services
Hour
10 Data Types in XML Web Services
11 Working with Data in XML Web Services
12 Passing DataSets from XML Web Services
13 Consuming DataSets in XML Web Services
14 XML in Web Services
HOUR 10
Data Types in XML Web
Services
In this hour, you are going to learn about many of the data types that can be
used in XML Web services. By the end of this hour you will be able to cre-
ate services that accept and return primitive data types, arrays, and even
classes.
In this hour we will discuss the following:
• Primitive data types
• Enumerations
• Arrays
• Handling classes
• Passing arguments ByVal and ByRef
158 Hour 10
The data types that you choose in your XML Web service applications will play a crucial
part in their performance. Remember, you are building an application that may be han-
dling hundreds or thousands of requests at any given time; the larger the size of the vari-
ables that you use, the more memory your application will require and the slower it will
run. Also, remember that in the operation of your service the IIS server and the client
applications will be sending data back and forth between each other, and by using the
smallest data types possible, you reduce network traffic and increase the efficiency of
your apps.
Table 10.2 shows the size of some of the more common data types available to you.
From looking at this table, and the data ranges given, you can quickly determine what
data best suits your needs. If, for example, you were building a function that returned
the number of tickets available at a particular venue and seating in the theater was
around three thousand people, you would know to avoid data types such as Decimal
and Long.
Data Types in XML Web Services 159
Listing 10.2 shows the equivalent function in C#. Again, you can use this method as a
template to return any of the data types shown in Table 6.1.
When returning an array, simply return the array name without any brackets, as shown in line
9 of both Listing 10.3 and 10.4. This will return the entire array. Client code can check for the
upper bounds of the array in order to retrieve the number of elements that the array contains. 10
When an array is returned from an XML Web service, the SOAP document contains the
type declaration and value for every value in the array (see Figure 10.1) that is contained
inside an XML tag proclaiming the contents to be type ArrayofInt.
FIGURE 10.1
Returning an array
from your XML Web
service.
each ticket sold could belong to a train, plane, or car. You could create an enumeration
called vehicle and have it contain constants for each of the vehicle types.
To create an enumeration, you declare a variable of type enum, as shown in line 1 of Listing
10.5 (10.6 for C#). You then type your constant names—in this case the colors red, blue, and
green—before you end the enum. You can now create variables of type Color in your service.
To return your Color enumeration from an XML Web service, simply declare your
method as returning type Color (see Listings 10.5 and 10.6) and return a color. The syn-
tax for retrieving a value from an enumeration is as follows:
EnumName.EnumValue
When an XML Web service returns an enumeration, it actually returns the value’s name,
not its value. In the example above, the service returns a data type Color with a value of
Red (see Figure 10.2).
Data Types in XML Web Services 163
FIGURE 10.2
Returning an enumera-
tion from an XML Web
service.
10
Returning Classes
A class is a compound data type completely defined by you, the programmer. Much like
the enumerations shown in Listings 10.5 and 10.6, a class is defined in your code, and
the variables can be declared as the type of your class.
Listing 10.7 shows a simple class declared in Visual Basic. This class includes two vari-
ables, a string type called Name and an Integer type called ID. Listing 10.8 shows the
same class declared in C#. Applications using your service would be unable to tell the
two of them apart.
Although classes can contain any data type, even enumerations and other
classes, a complete discussion of classes is beyond the scope of this book.
The examples used in this hour are very basic.
When you wish to use your class, you declare a variable as the type of your class—in
this example, Person. You then use the New keyword to actually create the object. With
the object created, you can now begin setting its properties. In Listing 10.9 (Visual
Basic) and Listing 10.10 (C#), we set the Name property of our new Person object,
oPerson, equal to "Jim Smith" and the ID property to 5.
To return your oPerson object to client applications, you declare your method to return
type Person, as seen in line 1 of Listing 10.9, and then you simply return your oPerson
object, as in Line 8 of the same listing.
When your object is returned, individual type information is not included. Instead, as
shown in Figure 10.3, the objects are typed to their variable names. In this example, the
return type is Person and contains types Name and ID.
Data Types in XML Web Services 165
FIGURE 10.3
Returning an object
of type Person.
10
Listing 10.12 shows how C# returns an array of Person objects in the same manner as
the previous Visual Basic example.
The returned SOAP document for the array of Person objects is very similar to that
shown in the previous example, only now, as shown in Figure 10.4, all three of your
Person objects are wrapped in an XML tag showing a type ArrayofPerson.
FIGURE 10.4
Returning an array of
objects of type Person.
Data Types in XML Web Services 167
Passing Arguments
Often, it is necessary to do more than simply have your methods return data to a user
request. Oftentimes, you will require some information from them in order to perform
your tasks. This is where parameters come in. Parameters define the types of information
that you are requesting from a client.
XML Web services accept all primitive data types as parameters. The syntax for declar-
ing your parameters is exactly the same as it is in function calls in non XML Web service
programming. That is to say, it takes the following form:
<Webmethod()> Public Function FuntionName (ByVal/byRef paramName as Type) as
type
Or in C#
10
Public type FunctionName(type paramName)
byVal and byRef denote the way in which incoming variables are treated.
For now, we will be using only byVal, which accepts a copy of the data and
leaves the original unchanged. In later examples, we will want to change
the original variables, and byRef will be used.
To call the above function, a client application could now use the following syntax:
SVar = Service.ParamStringReturn("HITHER", "THITHER")
In the above, sVar is a string variable for the return value and Service is the object refer-
ence to your XML Web service.
168 Hour 10
You can also accept more complicated types, such as enumerations, as parameters in
your code. Listing 10.14 shows a new enumeration in Visual Basic.
Now we can accept this enumeration in code in exactly the same way as we did the previous
primitive types. Listing 10.15 shows a method that will accept a variable of type Champion.
XML Web services allow us to accept variable sized arrays as parameters in our code. To
do so, you would simply declare parameters as such:
ByVal/byRef paramName() as Type
Listing 10.16 demonstrates the Visual Basic method of accepting an array of integers,
iName, as a parameter. This method then returns an integer—in this case the number of
elements in the array.
Listing 10.17 shows the C# method for accepting an array as a parameter. It also returns
the number of elements in the array by using the GetUpperBound method. The ability to
retrieve the number of elements in an array is crucial to working with them.
If you are using C#, you will have to build your method using the following declaration:
public int RefReturn(ref int iVal)
170 Hour 10
After you have added the refReturn method, go back and make sure that you have the
declaration for the Person class, Listing 10.7 (Listing 10.8 for C#), in your code. You
will be using this class shortly.
Now, add listing 10.19 to your service. This new method will accept a Person object as a
parameter and change its values.
For those following along in C#, declare your refClassReturn with the following line:
public void refClassReturn(ref Person oPers)
Now, save and build the project. At this point, you will begin work on a simple client
application that will call your XML Web service and display the return values.
Create a new Windows application and add a Web reference to your DataType XML Web
service. See Hour 8 if you need a reminder on how this is done.
Next, create a form that looks like the one shown in Figure 10.5. For simplicity’s sake,
leave the default names for all of the controls.
FIGURE 10.5
The form for
your byRef client
application.
Data Types in XML Web Services 171
This will create the object reference to your DataType XML Web service.
Now, add listing 10.20 to the button click event of Button1. This code will take the inte-
ger value typed into TextBox1 and store it to a variable called iVal. iVal is then passed
to the RefReturn method and the return value is displayed in TextBox2. The new value
of iVal is displayed in TextBox3.
Figure 10.6 shows the end result of clicking Button1. Notice that the value of iVal,
labeled “Old Value,” is now decremented by one.
FIGURE 10.6
Returning values from
your refReturn
method.
172 Hour 10
Listing 10.21 shows the code that you should now add to the Click event of Button2.
This code will take the values in TextBox4 and TextBox5 and store them into the Name
and Id properties of our oPerson object. oPerson is then passed, byRef, to the
refClassReturn method and the value refreshed to its respective textboxes.
Figure 10.7 shows the results of passing the Name "Danielle" and ID "6" to the
refClassReturn method.
FIGURE 10.7
Returning an array
of objects of type
Person.
Data Types in XML Web Services 173
Summary
In this hour, you learned about some of the data types in .NET and what value ranges
they can each hold. You also saw how to return variables of different types from XML
Web service applications, as well as how to accept parameters both by value and by ref-
erence. Now, with these building blocks, you can move on to creating larger and more
meaningful services.
Q&A
Q What is the purpose of having so many similar variable types, for example
integers and longs?
A The purpose to having so many variable types is to help developers, such as you,
better manage resources. You should always pick the smallest number possible of
10
variable types that can handle the needs of your application.
Q What do I do if I want to create a function that alters the parameters passed
to it, but doesn’t return a value?
A The first part of the answer is to declare your parameters as either ByRef in Visual
Basic or ref in C#. The second part of the answer, creating a function that returns
nothing, can be done in Visual Basic by using a subroutine instead of a function. In
C#, you would still use a function, but you would declare it as returning type VOID.
Q I need to create an XML Web service that will alter information about an
appliance being serviced. The information will include the owner name, the
date, and a status. I would like to return all of this information to the client
application in one method. How can I do this?
A Create a class based on your application and give it all the attributes that you need
to pass back to the client. Then, simply create your method and have it return the
class you created.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. You need to return a value between 0 and 20. What data type should return?
A Byte
174 Hour 10
2. You need to alter the variables being passed to your method. How do you declare
them?
A ByRef in Visual Basic. Ref in C#
3. What return type would you use when declaring a method that lets a client applica-
tion know if a given pH is Acid, Base, or Neutral?
A You would use an Enumeration (possibly called pH) and give it Acid, Base, and
Neutral as possible values.
4. What do you place after the return statement if you are trying to return the follow-
ing array of integers: myArray(3)?
A You would return myArray.
5. You have a class called myClient of type Client and it contains two public attributes.
What do you declare as your return type?
A Client
Exercises
Try experimenting with the different data types that you learned about in this hour. Write
methods that accept different methods as parameters as well as those that return them.
Do as many as it takes to make you feel comfortable with passing data back and forth
between your XML Web service and client applications.
#Region "Simple Data Types"
'Returning a String
<WebMethod()> Public Function StringReturn() As String
Return "This is a string"
End Function
'Return Single
<WebMethod()> Public Function SingleReturn() As Single
Return 233400000000000
End Function
10
'Return Single
<WebMethod()> Public Function DoubleReturn() As Double
Return 3444344400000000000
End Function
#End Region
'Declaring an Enum
Public Enum Color
Red = 1
Blue = 2
Green = 3
End Enum
'Returning an Enum
<WebMethod()> Public Function EnumReturn() As Color
Return Color.Red
End Function
#End Region
'Returning an Array
<WebMethod()> Public Function ArrayReturn() As Integer()
Dim a(4) As Integer
Dim i As Integer
For i = 0 To 4
176 Hour 10
a(i) = i + 1
Next
Return a
End Function
#End Region
'Declaring a Class
Public Class Person
Public Name As String
Public ID As Integer
End Class
'Returning a Class
<WebMethod()> Public Function ClassReturn() As Person
Return oPerson
End Function
Return oPerson
End Function
#End Region
#Region "Params"
'New Enum
Public Enum Champion
Corum = 1
10
Renark = 2
Urlich = 3
Hawkmoon = 4
End Enum
Return enumName
End Function
Return UBound(iName)
End Function
#End Region
#Region "ByRefParams"
iOld = iVal
iVal = iVal - 1
Return iOld
178 Hour 10
End Function
oPers.ID = oPers.ID - 1
oPers.Name = "Hi " & oPers.Name
End Sub
#End Region
HOUR 11
Working with Data in
XML Web Services
In this hour, you will see how relational data sources, such as SQL Server
and MS Access, are accessed using ADO.NET. You will also learn about the
different objects that comprise ADO.NET, such as the connection and com-
mand objects. You will also learn to use data readers to deal with connected
data sources and DataSet objects to deal with data that is disconnected from
its original source.
Throughout this hour we will discuss the following:
• Using ADO.NET to access data stores
• ADO.NET’s common objects
• Data readers for viewing data and running queries
• DataSet objects for handling disconnected data
180 Hour 11
Changes to ADO
Several years ago, Microsoft introduced ADO (ActiveX Data Objects) as a way to pro-
vide a standard method for developers to access data regardless of its type. This meant
that a developer who knew how to write code utilizing an Oracle database did not have to
learn a totally new method of data access if the next project utilized SQL Server.
In previous versions of ADO, data was modeled and transported using recordset objects.
recordset objects were a proprietary object model that allowed only a single table struc-
ture to be created and passed between components of an application that utilized ADO.
With .NET, Microsoft overhauled ADO from the ground up with an eye toward flexibil-
ity of data modeling and the ability to share data, using technologies such as XML Web
services, with applications on a variety of platforms. The single greatest change to ADO,
and the one that provided for these objectives, is the DataSet object. The DataSet object
replaces the proprietary recordset object model with an architecture that models and
transports its data in XML.
The change from the recordset object to the Dataset allows for data to be modeled in a
much more meaningful manner. Now, multiple tables can be included in a single
Dataset, and relationships between them can also be included. Modeling data in XML
also means that applications written in .NET languages can share their data with non
.NET applications by simply sending them the data’s XML representation. This is
extremely important to XML Web services and will be the focus of the next few hours.
ADO.NET Namespaces
The objects that ADO.NET is comprised of are split up over several namespaces, includ-
ing several used only for XML-based data sources. These namespaces, utilized via the
Imports keyword, allow developers to make use of ADO.NET objects in their code. The
main namespaces for dealing with relational data sources are shown in Table 11.1.
Working with Data in XML Web Services 181
System.Data.OLEDB Contains the objects used when dealing with OLE-DB data
sources. Among its main objects are OleDbConnection and
OleDbCommand objects.
These namespaces represent only a small portion of what is available to .NET develop-
ers. Other namespaces exist to allow developers to work with less common data objects
and non .NET data types that may exist for specific databases.
In order to use the code in this hour, which makes use of a Microsoft Access Database,
you will need to add the following namespaces to your code: 11
Imports System,Data.oleDB
Imports System.Data
FIGURE 11.1
Creating a New Table
in Access 2000.
Once you are in design view (shown in Figure 11.2), creating the table is relatively sim-
ple. Type a name—in this case ID—into the column marked Field Name. Now, under
Data Type, select a variable type for the field. For ID, choose AutoNumber. This will
FIGURE 11.2
Adding Fields to a
Table in Access 2000.
Working with Data in XML Web Services 183
assign a new and unique identifier to every new entry added to the database. If you wish,
you can also add some descriptive comment text to the column labeled Description.
For this table, which will store the names of authors, you will need to add two more
fields—one for the first name and another for the last. Call these fields LName and Fname,
respectively, and assign them text as their data types.
To save this table click on the save icon, the one in Figure 11.2 that looks like a
diskette. This will bring up the Save As Input box. Give this table the name tblAuthors
and click OK.
You will need to add a second table to this database before you are done. Follow the
steps that you used to create the tblAuthors table to create tblTitles. Give tblTitles
an ID field of data type AutoNumber, a Titles field of type text, and an AuthorID of type
Number. This last field will be used to point to the author of each book.
Lastly, you need to enter some data. Start with tblAuthors table as you will need the ID
field from this table to enter into the AuthorID field of tblTitles. To enter data into
tblAuthor, double click on tblAuthor in the main window of Book database window;
this will open the table for entry. Now, simply type a few names, first and last, into the
table. Notice that the ID field as autoincremented. If you type only a few entries in, 11
make a note of the ID field for each.
Now, open tblTitles and add some titles in. For the AuthorID field of each title that
you enter, type in the ID of the author from tblAuthors. You now have a simple data-
base to use for these examples.
If you wish to learn more about database programming, I highly recommend Sams’
upcoming title, Teach Yourself Database Programming with Visual Basic.Net in 21 Days.
In the code in Listing 11.1, sSource is a string variable containing the connection string
to the database. Connection strings contain information for connection to a data source,
such as server path names, database names, DSN names, and password information. A
typical connection string might look like this:
“server=(local)\\myBook;uid=sAccount;pwd=sPassword;database=Book”
Using this connection string in a connection object would open the Book database on the
local server using the account name sAccount and password sPassword.
You will see more examples of connection strings throughout this hour, so
don’t worry if you are unsure of how to write one yourself at this point in
time.
A command object contains a command string, sCommand, that is an SQL statement; the
name of a stored procedure; or the name of a table to be retrieved. The active connection,
conn, represents the connection object that you saw earlier.
You can change the command object’s command string at any time in your code using
the following syntax:
cmd.CommandText = sCommand
Likewise, it is possible to change from one connection object to another via the
Connection property:
cmd.Connection = conn
The command object also features a CommandType property that allows you to set the
type of command being utilized. The default is Text, but the type can also be set to
StoredProcedure or TableDirect. Listing 11.2 shows an example of setting the
CommandType to TableDirect.
Working with Data in XML Web Services 185
Passing Parameters
If you are using stored procedures with CommandType set to StoredProcedure, it is possi-
ble to pass in parameters to your command object. This is accomplished using the para-
meters collection.
To add parameters to a command object, you invoke the Add method of the parameters
collection:
cmd.Parameters.Add(New SQLParameter(“@Name”, sqlDbType.VarChar, “value of some
parameter”))
The previous code adds a new parameter called @Name to the command.
SQLDataType.dataType is the syntax for declaring the parameter’s data type.
SQLDataType is an enumeration that allows you to declare any of a large variety of vari-
able types including SmallDateTime, Text, VarChar, and dozens more.
11
Optionally, you can also include the size, as an integer, of the data that may be accepted;
isNullable, as a Boolean, to allow null value to be passed; and Direction, as type
ParameterDirection, to determine if the parameter represents input or return values.
After a parameter has been added, its value may be set, or changed if it was set when the
parameter was created, as in our previous example, by calling the parameters index num-
ber or name and setting its value property as follows:
cmd.Parameters(“@Name”).Value = sVal
ExecuteNonQuery
This method of the command object is used to run SQL statements that do not return
results, such as Delete and Insert queries. It can also be used to run stored procedures.
These stored procedures may or may not return data.
cmd.ExecuteNonQuery
The previous line would execute the command currently stored in the command
object, cmd. Optionally, some variable of type integer could be used to accept the
return value that contains the number of records that were affected by the command’s
execution.
ExecuteReader
This object returns a DataReader object. The DataReader, which you will see more of
later in this hour, provides a connected method through which to manipulate data on a
data source.
In order to use the ExecuteReader method of the command object, you must have a
DataReader object declared to receive the return. This can be done as follows:
You may then set the DataReader, oRead, equal to the return value of the ExecuteReader
method:
ORead = cmd.ExecuteReader
Because the data reader uses an active, “live” set of data, the connection
object that it uses is locked until the data reader releases it. The only action
that can be performed on a connection object being used by a data reader
is the Close method.
To create a DataReader object, you simply use the ExecuteReader method of the com-
mand object. Listing 11.3 shows an SQLDataReader object that contains the content of
the tblBooks table.
Working with Data in XML Web Services 187
Table 11.3 shows some of the more common properties of the data reader object.
The data reader also exposes a number of important methods, which are shown in
Table 11.4.
Now that you have seen the data reader’s properties and methods, take a look at an
example of a data reader in action. Listing 11.4 shows the data reader working its way
through a set of records returned from an Access Database.
188 Hour 11
In Listing 11.4, you can see that the data reader myReader will keep advancing through
the records and returning true, via its Read method, until it reaches the end of the data. At
this point, the Read method will return false and the While loop will end.
continues
Working with Data in XML Web Services 189
Now, take a look at a few examples that show how to use the DataAdapter to fill a
Dataset. The first example, Listing 11.5, shows how to create a DataAdapter using an
SQL query string, whereas the second example, Listing 11.6, makes use of the
DataAdapter’s SelectCommand property.
The Fill method in line 4 of Listing 11.5 creates a DataTable named Authors within
the DataSet and populates it with the return of the SQL Query string, sSQL.
The Fill method in line 3 of Listing 11.6 populates the Dataset with a DataTable called
Books that contains the contents of a database table named tblBooks.
The DataTable also contains all of the DataSet object methods for dealing with changes
(see Table 11.5). These methods allow you to roll back or accept changes at the table
level in addition to the Dataset level.
Working with Data in XML Web Services 191
The code in Listing 11.7 shows an example of DataRow objects being used to access data
in a DataSet.
11
LISTING 11.7 Using a DataRow Object to Access Data
1: Dim sSource As String
2:
3: sSource = “Provider=Microsoft.Jet.OLEDB.4.0; “ & _
4: “Data Source=C:\Book\Books.mdb;Persist Security Info=False”
5:
6: Dim conn As New OleDbConnection(sSource)
7: conn.Open()
8:
9: Dim myAdapter As New OleDbDataAdapter()
10: Dim myDataSet As New DataSet()
11: Dim cmd As New OleDbCommand()
12:
13: cmd.CommandText = “SELECT * FROM tblTitles”
14: cmd.Connection = conn
15: myAdapter.SelectCommand = cmd
16: myAdapter.Fill(myDataSet, “Books”)
17:
18: Dim myRow As DataRow
19: For Each myRow In myDataSet.Tables(“Books”).Rows
20: Debug.WriteLine(myRow(0))
21: Next
192 Hour 11
The code in Listing 11.8 iterates through the columns collection and prints the caption of
each individual column and its data type.
continues
Working with Data in XML Web Services 193
where Name is a string representing the name you wish to call the relationship, and
Column1 and Column2 are existing columns in DataTables in the DataSet.
DataRelations are held in the relations collection of the DataSet object. Listing 11.9
shows how we create a new relationship in our DataSet using the Add method of the
relations collection.
continues
194 Hour 11
Summary
In this hour, you learned how to access data stores utilizing ADO.NET. You also saw
how to populate and view data with both data readers and DataSets. Finally, you
learned how to update data sources from within ADO.NET.
Q&A
Q Why take such a long look at ADO.NET in a book on XML Web services?
A Most XML Web services that you will create will need to work with a data source,
be it uploading information to share with a client application, such as stock prices
or football scores, or tracking information, such as product orders or survey infor-
mation. Since ADO.net is the principle matter for dealing with data sources in the
.NET platform and is totally revised from older versions of ADO, it is important to
get a firm understanding of it in order to develop successful XML Web services.
Q How do I determine when to use a DataSet or a data reader in my applica-
tions?
A The data reader is a smaller, less memory-intensive object and is perfect for view-
ing data connected directly to your application. For this reason, a data reader is a
Working with Data in XML Web Services 195
great option for opening data stores that initialize data in your XML Web Service.
You can then use SQL inserts and updates to update the data store at appropriate
times in the application, such as the Application_End event.
The DataSet, on the other hand, is perfect for when you need to send data to other
applications, such as the data returned from an XML Web service. Also, because
the data set allows you to work with multiple tables, it is sometimes the most
appropriate method to handle more complex situations, such as ones that would
require multiple data readers and connection objects.
Q What is the purpose of the command object? Why not just use strings to hold
SQL statements?
A Like most programming tasks, there usually exist multiple methods to perform the
same task. Although it is possible to perform most operations without the use of
command objects, they are often the best method. The command object’s parame-
ters collection makes it perfect for dealing with stored procedures, and it also rep-
resents a method with fairly low overhead for running Update, Insert, and Delete
queries. Also, the ability to perform many different types of executions from one
object adds to the power of the command object.
Q What will my XML Web services pass to client applications? 11
A Your applications, as you will see in the next hour, will pass back Datasets under
most conditions. Because DataSet objects are heavily XML based, a property that
you will make more use of in Hour 16, they are the perfect data type to send over
http protocols.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. If your program received a DataSet from an XML Web service and you need to
programmatically extract the names of each field, what object and property would
you use?
A You would use the ColumnName property of the DataColumn object.
2. What object’s Fill method is used to populate DataSet objects?
A The DataAdapter is used to populate Dataset objects.
3. What namespace contains the SqlCommand object?
A System.Data.SqlClient
196 Hour 11
Exercises
Try using the data reader and DataSet object to manipulate a database of your choosing.
If you wish, simply use Debug.Write or Debug.WriteLine to output the data.
A. The following code opens tblAuthors from a database named book, using a DSN,
and writes all of the information in the table to the debug screen.
1: Dim sSource As String
2:
3: sSource = “Provider=Microsoft.Jet.OLEDB.4.0; “ & _
4: “Data Source=C:\Book\Books.mdb;Persist Security Info=False”
5:
6: Dim sSQL As String = “SELECT * FROM tblAuthors”
7:
8: Dim myDataSet As New DataSet()
9: Dim conn As New OleDbConnection(sSource)
10:
11: conn.Open()
12:
13: Dim cmd = New OleDbCommand(sSQL, conn)
14: Dim myAdapter As New OleDbDataAdapter()
15: myAdapter.SelectCommand = cmd
16: myAdapter.Fill(myDataSet, “Authors”)
17:
18: conn.close()
19:
20: Dim oDataRow As DataRow
21: Dim oDataCol As DataColumn
22:
23: For Each oDataRow In myDataSet.Tables(“Authors”).Rows
24: For Each oDataCol In myDataSet.Tables(“Authors”).Columns
25: Debug.WriteLine(oDataRow(oDataCol.Ordinal))
26: Next
27: Debug.WriteLine(“=======================”)
28: Next
HOUR 12
Passing DataSets from
XML Web Services
In the last hour, you saw the basic functionality of ADO.NET and how it can
be used to provide data access to a divergent array of data sources. Now, in
this hour you will learn how to create XML Web services that both expose
and consume XML-based DataSets. You will learn how to use ADO.NET to
manipulate data sources from within your services and present filtered,
meaningful results to your clients.
Throughout this hour we will discuss the following:
• Passing ADO.NET DataSources from an XML Web service
• Updating data sources from within an XML Web service
• Using the DataSource as a method argument
• Consuming DataSources in client applications
• The XML behind DataSources
198 Hour 12
If you wish to work along with this hour’s examples, create a new XML Web
service and call it exampleDataSet.
Passing DataSets from XML Web Services 199
The database used in the examples in this book contains the tables shown as Table 12.1
and Table 12.2.
With the Database in place, you now need to import your namespaces. Since you are
using an Access Database, you will need to place the following two declarations at the
top of your XML Web service:
Imports System.Data
Imports System.Data.OleDb
Returning a DataSet is fairly straightforward. First, declare a new function and set its
return type to DataSet. Then, add a new DataSet object and its supporting Connection
and DataAdapter objects, as shown in Listing 12.1. Next, build a query string and popu- 12
late your DataSet. Finally, all you need to do is return the DataSet as shown in line 12.
continues
200 Hour 12
The net result of Listing 12.1 is the creation and transmission of a data set containing the
entire contents of a table, in this case tblBands, from the Music database.
Listing 12.3 shows the actual DataSet for the Bands table. This XML representation is
what ADO.NET enabled client applications will consume as native DataSets. As you can
see from Listings 12.2 and 12.3, client applications that are built on platforms not sup-
porting ADO.NET will have an easy time working with the DataSet through the use of
XML parsers.
Passing DataSets from XML Web Services 201
continues
202 Hour 12
Listing 12.6 shows a segment of the DataSet from ReturnCatalog. Notice in the docu-
ment structure how each data grouping, ID and BandName in the case of the Bands table,
is contained in a separate Bands element. Also notice that the individual Bands elements
are not further grouped together to separate them from CDS elements. This is acceptable
because of the way XML is parsed. A parser would create a tree with Bands and CDS on
it at the same level and then drop individual elements onto the tree under each.
Passing DataSets from XML Web Services 203
continues
204 Hour 12
You have now created a DataRelation entitled BandsToCds and have set the Bands table
as the parent field. This means that you are setting rows in the CDS table as children rows
of the corresponding rows in the Bands table.
DataRelations in XML
Now look at the XSD schema fragment shown in Listing 12.8. This fragment, which is
now part of the definition of Bands, defines a unique construction entitled Constraint1
and defines it as the ID field using XPath.
In the schema definition for table CDS, the DataRelation, BandsToCds, is defined by declar-
ing a reference to Constraint1, defined in Listing 12.8. This is shown in Listing 12.9.
Note line 1 of Listings 12.8 and 12.9. The ID field of Bands is listed as unique whereas
the Band_ID field of table CDs is listed as a keyref. This is how one-to-many relations
are defined.
Passing DataSets from XML Web Services 205
It may not be the most useful method ever created, but it does demonstrate a few key
points. First, this method expects the DataSet to arrive containing a Bands table. It also
expects that the Bands table can be successfully added to by simply adding text to the
table’s second column. This is the biggest problem with handling DataSets as arguments.
Client applications have to know in advance exactly what the DataSet needs to be for-
matted as.
206 Hour 12
When this code has finished inserting the band name into the table tblBands, it creates a
new DataSet object and imports the entire contents of tblBands into it. This new DataSet
is then used as the functions return as seen in Figure 12.1. This last step is done so that
in the next Hour you can build a client application that actually tests to see that the inser-
tion takes place.
Passing DataSets from XML Web Services 207
FIGURE 12.1
Returning the
updated DataSet
with DataTable
Bands.
Next, you will create the code to enter a new CD title in the database. This is different
from entering a band name in that it requires a Band_Id value to associate the CD with a
particular band. There are several methods that you could employ to retrieve this
Band_ID value, including looking it up based on a supplied band name. In this example
however, you will simply have the client pass in the Band_ID as a parameter. This is
demonstrated in Listing 12.12.
Summary
In this hour, you learned how to create XML Web services that expose entire DataSets.
You also looked at the various portions of the outputted DataSets XML document and
how they were structured to include elements, relationships, and constraints. At the end
of the hour, you learned how to update data sources with values passed to the XML Web
service from client applications.
Q&A
Q Why return DataSets when we could move the data into objects as we saw in
Hour 11?
A There are several answers to that question. The first reason is that the tools for
working with DataSets are already in place, so why would we want to write a
bunch of custom code that we don’t have to? Another reason is that the XML
nature of DataSets makes them very easy to work with on the client side even if
ADO.NET is not present.
Q What happens if I create a DataSet with DataRelations and my XML Web
service is consumed by clients that do not use ADO.NET?
A When a DataSet is exposed by an XML Web service, it is exposed as an XML doc-
ument, complete with markup to define relationships. When these XML documents
are parsed on the client side, this relationship information may be ignored; there is
no guarantee that the parser being used can read XSD schemas or that the devel-
oper who writes the client code even cares about your relationships. Even a .NET
client is free to remove the DataRelations from the DataSet once it is within
the client’s control. Ultimately, the best you can do is to include DataRelations in
your services for those who choose not to ignore them.
Q Is there a limit to the amount of Data that I should send over in a DataSet?
A There is no hard rule on how much information is too much, but you should always
try to limit what you send across networks, especially the Internet, to only what is
absolutely necessary. Most times, you can filter down your datasets to just a few
records before sending them to clients, but there are other times when a large,
multi-table recordset is the only way to go.
Q Is it possible to organize extremely complex data into multiple DataSets and
then return them?
A Yes, it is actually possible to return an array of DataSets. This is not something that
you would normally do, as the overhead could get to be a bit large, and working
with an array of data types can be somewhat cumbersome and difficult for the
client developers. Still, it can be done.
Passing DataSets from XML Web Services 209
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future lessons.
Quiz
1. What XML subset does XML Web services use to define DataRelations?
A XPath.
2. (True or False) The sequence of columns is not preserved when DataSets are trans-
mitted.
A False, the sequence is preserved and enforced in the XSD schema.
3. What type of DataAdapter is used to connect to an MS Access database?
A OleDbDataAdapter.
4. If you need to add a row to a table, prior to returning it, what method would you
use?
A NewRow.
Exercises
Try creating and returning a DataSet built completely within the method, that is, no data
connections. Now, make the return an array of two DataSets, with at least one containing
two or more tables. Also, include at least one DataRelation. 12
The following code creates an XML Web service method that returns a DataSet array.
The array contains two DataSets, one with a DataTable containing the names of five cats
and the other containing a DataTable of fish tanks and another of fish type. The second
DataSet contains a DataRelation between the fish and the tanks.
<WebMethod()> Public Function ReturnPets() As DataSet()
Dim myDataSet(2) As DataSet
Dim myColumn As DataColumn
Dim myRow As DataRow
‘Add Tanks
myRow = myDataTable.NewRow()
myRow(“ID”) = 1
myRow(“Tank”) = “3 Gallon”
myDataTable.Rows.Add(myRow)
myRow = myDataTable.NewRow()
myRow(“ID”) = 2
myRow(“Tank”) = “10 Gallon”
myDataTable.Rows.Add(myRow)
myRow = myDataTable.NewRow()
myRow(“ID”) = 3
myRow(“Tank”) = “20 Gallon”
myDataTable.Rows.Add(myRow)
myColumn.DataType = Type.GetType(“System.Int32”)
myColumn.ColumnName = “Tank_ID”
myDataTable.Columns.Add(myColumn)
‘Add Fish
myRow = myDataTable.NewRow()
myRow(“ID”) = 1
myRow(“Fish”) = “Beta”
myRow(“Number”) = 1
myRow(“Tank_ID”) = 1
myDataTable.Rows.Add(myRow)
myRow = myDataTable.NewRow()
myRow(“ID”) = 1
myRow(“Fish”) = “Feather Fin Catfish”
myRow(“Number”) = 4
myRow(“Tank_ID”) = 3
myDataTable.Rows.Add(myRow)
‘Add Cats
myRow = myDataTable.NewRow()
myRow(“ID”) = 1
myRow(“Name”) = “Rowan”
myDataTable.Rows.Add(myRow)
myRow = myDataTable.NewRow()
myRow(“ID”) = 2
myRow(“Name”) = “Morrigan”
myDataTable.Rows.Add(myRow)
myRow = myDataTable.NewRow()
myRow(“ID”) = 3
myRow(“Name”) = “Nayarlathotep”
myDataTable.Rows.Add(myRow)
212 Hour 12
myRow = myDataTable.NewRow()
myRow(“ID”) = 1
myRow(“Name”) = “Melissa”
myDataTable.Rows.Add(myRow)
myRow = myDataTable.NewRow()
myRow(“ID”) = 1
myRow(“Name”) = “Lorindal”
myDataTable.Rows.Add(myRow)
myCol1 = myDataSet(0).Tables(“Tanks”).Columns(“ID”)
myCol2 = myDataSet(0).Tables(“Fish”).Columns(“Tank_ID”)
myDataSet(0).Relations.Add(myRelation)
Return myDataSet
End Function
HOUR 13
Consuming DataSets in
XML Web Services
In this hour you will learn how to consume a DataSet that has been passed
to your application from an XML Web service. You will see how to read
through DataSet records and even how to work through the hierarchies cre-
ated through the use of DataRelations. Finally, you will take a brief look at
the DataGrid control and how it can be used to quickly display DataSets.
Throughout this hour we will discuss the following:
• Receiving DataSets from XML Web services
• Working with DataSet Collections
• Navigating DataRelations
• DataGrid control
214 Hour 13
FIGURE 13.1
Form for the
DataSetClient
application.
Use Table 13.1 to set the properties of the various controls on your form. Don’t worry
too much about making the form user friendly as it exists only to demonstrate that the
returns from the exampleDataSet XML Web service are actually working.
Consuming DataSets in XML Web Services 215
The next thing that you need to do is prepare your application for using DataSets. In the
code view for Form1, add the following statement to import the System.Data
Namespace. This should go in the namespace section of your code, up at the very top of
the code window.
Imports System.Data
Now, create a DataSet that can be used to populate the various display controls in the
application. Let’s call this DataSet myDataSet and declare it in the general declarations
section of the Form1 class, just below the class declaration but outside of any functions.
Your declaration should look like the following:
13
Private myBands As New DataSet()
Now that you have your form set up and your project ready to use the exampleDataSet
XML Web service, it is time to add some code and start consuming DataSets. The first
code you should add displays the actual catalog and will be used to display results from
all of the other operations. This code is shown in Listing 13.1. Do not worry too much
about the specifics of it at this point in time; you won’t actually learn the details behind
this code until slightly later in the hour, but it is necessary to use it now in order to see
the results of the various operations that you will be performing.
216 Hour 13
The code in Listing 13.1 calls the ReturnCatalog method of the exampleDataSet XML
Web service and displays the entire catalog in the TreeView control. Again, you will
learn the particulars behind this shortly. In order for the TreeView to be filled when the
application starts, you need to call the LoadDataTree method when the form loads. Place
the following function call inside the Form1_Load event handler:
LoadDataTree()
At this point, save the program and run it. If you typed everything correctly, you should
see something resembling Figure 13.2. If not, go back and make sure that everything was
typed correctly and that all of the declarations are in the correct area.
Consuming DataSets in XML Web Services 217
FIGURE 13.2
The DataTree showing
the results of the
ReturnCatalog method
of the exampleDataSet
XML Web service.
In a real life situation, you would use the same Dataset that was returned
for populating the Treeview, see Listing 13.1. This additional call to the XML
Web Service, done here to reinforce the methods of consuming service,
would require the additional overhead and performance hits that develop-
ers should strive to avoid. Remember, plan you client applications carefully
to ensure that you only call a service when you have to.
13
Look at the code in Listing 13.2. In line 2, you create an object of type Service1, the
actual service used in exampleDataSet, and a DataRow object called myRow. You will use
myRow to cycle through the rows of the DataTable.
In line 5 of the code, you call the ReturnBands method and store its returned DataSet in
the myBands DataSet that you created at the beginning of this project. You can now use
the myRow DataRow object to cycle through the Rows collection of myBands.Tables(0)
and add the value of myRow(1), the second column of the row, to your ComboBox.
218 Hour 13
In this example, you used the actual integer value of each column and table’s index, or
position, in their respective collection. You could also use the actual name of each object,
as you will see in the next example.
Add the call to the LoadCombo function to the Form1_Load event handler like you did
with the LoadDataTree method above. The syntax should look like this:
LoadCombo()
Save and run the project. Figure 13.3 shows ComboBox cbBands loaded with the band
names returned from ReturnBands method of the Web Service.
FIGURE 13.3
The drop-down list
populated with the
results of ReturnBands.
Consuming DataSets in XML Web Services 219
LISTING 13.3 Adding Bands to the Bands Table Using the AddBand Method of
exampleDataSet
The code in Listing 13.3 is pretty straightforward. It simply checks to see if a value is
present in txtBand, the TextBox used to enter a new band name and, if there is, passes it
to the AddBand method of the service. After the service has been called, calls are made to
LoadCombo and LoadDataTree in order to update the form.
It would save a great deal of overhead if the calls to AddBand were elimi-
nated and the function was written to call ReturnCatalog in order to refresh 13
the myBands DataSet and use that throughout the application. The separate
calls exist here so that you can clearly see what is going on and get a little
more exposure to calling services.
220 Hour 13
At this point, it would be a good idea to save your work and run the program. Try typing a
value in the AddBand TextBox, txtBand, and click Add. Your new Band name should show
up in the ComboBox, cbBands, and the TreeView control, tvCatalog. Figure 13.4 shows
the band Nightwish being added.
FIGURE 13.4
Adding a band to
table Bands.
In order to find the ID, use the Select method of the DataTable Bands. The Select
method returns an array of sub rows that match the string criteria passed into it. In this
case, you know that only one row can be returned, so you don’t need to do any other pro-
cessing on the returned row.
At this point, you can retrieve the array by accessing the ID field of the first, and only,
row element returned. Use this ID and the band name in txtTitle as arguments for the
AddTitle Method. The final step is to simply call LoadDataTree to update the display.
When you run the application, choose a band from the drop-down list, cbBands, and type a 13
CD title into the TextBox beneath it, txtTitle. When you click the Add button, the
TreeView should be updated so that the band that you selected now has a new title listed as
a child node. Figure 13.5 shows the addition of the Oceanborn CD to the band Nightwish.
222 Hour 13
FIGURE 13.5
The OceanBorn CD
Added to the CD
Catalog.
You can now iterate through this array of rows in almost exactly the same manner as you
were navigating through the parent DataTable, Line 18 of Listing 13.1. The syntax for
doing this is:
For Each oDataRow in ArrayDataRows
To finish out your function, you simply add the child rows to the TreeView as children of
the appropriate Band node. You do this using the Add method of the Nodes object in conjunc-
tion with the Index property of the nodes collection, as shown in line 20 of Listing 13.1.
The syntax for that is the following:
oTreeView.Nodes(index).Nodes.Add(newNode)
FIGURE 13.6
The form for the
DataGrid test
application.
13
224 Hour 13
Add the code shown in Listing 13.5 to the Form_Load event and run the application. The
SetDataBinding method of the DataGrid control does all the work in pulling your
Datasets’ DataTable, in this case Bands, to the grid and displaying it.
FIGURE 13.7
The DataGrid displays
the results of the
ReturnBands method.
DataGrid.SetDataBinding(myTable, Nothing)
In C#, the declaration is almost identical except that you would use the Null keyword
instead of Visual Basic’s Nothing.
Table 13.2 shows some of the commonly used properties of the DataGrid object.
Consuming DataSets in XML Web Services 225
Summary
In this hour, you saw how to retrieve DataSets from XML Web services and use them
within your applications. You learned how to use the getChildRows property of a
DataRow to maneuver through DataRelation created table hierarchies. At the end of the
hour, you saw how to harness some of the power of the DataGrid control.
Q&A
Q Is it possible to navigate hierarchies that are more complicated than a single
relationship?
A Yes, it is quite possible to navigate down many layers of child rows, for example,
by using the GetChildRow methods on each child row.
Q Can I send and receive smaller sections of a DataSet via XML Web services?
A Actually, no. As of this writing, any attempts to use DataTables or DataRows have
met with errors. Even if you were allowed to do such a thing, however, it would
not be good form. By keeping your tables and rows together in a DataSet, you help
to ensure that all clients, even those not using .Net, know how to parse your XML
DataSet return.
Q Why do we need to create a new DataRow object just to read the rows in our
DataTable?
A In ADO.NET DataSets, a row, or DataRow to be precise, is part of a collection.
Using the for each method of iterating through a collection, although admittedly
not the only method to of doing so, is one of the more elegant ways of navigating a
collection and the one I recommend. So to answer the question, you don’t have to
create a new DataRow to navigate the collection, but it makes your code much
more readable and maintainable than if you used the collections index, for exam-
ple, to navigate.
Q Is it possible to receive DataSets from two separate XML Web services and set
up DataRelations between them?
A Yes, this can be done by merging the two DataSets, using the merge method of the
DataSet object, and then creating the DataRelations as you saw in Hour 12.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Consuming DataSets in XML Web Services 227
Quiz
1. What Row object method returns any child objects of the current row?
A GetChildRows
2. What is the syntax to get the value of the third column of a DataRow called
drRows?
A drRows(2)
3. How would you bind a table, Cheeses, from a Dataset call dsSnacks to a DataGrid
named dgData?
A DgData.SetDataBinding(dsSnacks, “Cheese”)
4. What is the syntax to retrieve the ID field from the third row of an array of
DataRows called drCalendars?
A drCalendars(2)(“ID”)
Exercises
Try altering the DataGrid project to utilize the ReturnCatalog method of
exampleDataSet to see how the grid can be used to output related tables. Also, experi-
ment with some of the methods of the DataGrid Control.
A. Here is the code to open the DataSet returned from ReturnCatalog.
1: Dim oMusic As New localhost.Service1()
2: Dim myDataSet As New DataSet()
3:
4: myDataSet = oMusic.ReturnCatalog()
5: DataGrid1.SetDataBinding(myDataSet, Nothing)
13
HOUR 14
XML in Web Services
In this hour, you will look at some of the ways that Visual Studio.NET
allows you to manipulate XML Data. You will also look at how XML Web
services can retrieve data from XML sources and pass that information on to
client applications. Finally, you will examine how to change, or transform,
the entire hierarchy of an XML document and thereby provide even greater
flexibility in the manner that your services handle data.
In this hour, we will discuss the following:
• The DataSet object’s XML handling capabilities
• XmlReader Objects
• XmlDocument Objects
• XslTransform Objects
230 Hour 14
The returned XML string is shown in Figure 14.1. If you compare this to the DataSet
returned by the example in Listing 12.1, you will notice that the new example is much
more compact because it lacks the DataSet object’s structure and the extra XSD markup.
FIGURE 14.1
The DataSet object’s
GetXml return.
14
In Listing 14.2, the GetXMLSchema is used to return only the schema of the XML data. A
practical application of this may be the sending of the schema to a client application so
that it can validate an XML document before sending the document back to the service.
Again, this would primarily be done in situations where the client application is not
using DataSet objects.
232 Hour 14
The returned schema, shown in Figure 14.2, can now be used to create valid XML docu-
ments containing information about a CD catalog.
FIGURE 14.2
The schema returned
using a DataSet
object’s GetXMLSchema
method.
Notice that the XmlTextReader provides an EOF property. This allows you to move
through the various nodes of the XML data one by one, using the Read method, until
EOF returns True. Those of you familiar with the old ADO Recordset objects will
already be familiar with this manner of navigation.
Many of the methods in Table 14.3, particularly those beginning with “Read” or “MoveTo,”
are just a representative sampling of all of the methods that the class exposes. Many other
methods exist to read in or move to various other XML document element types.
Now it is time to look at the XML reader in action. The XML document in Listing 14.3
will be used for all of the examples that follow. Notice the simple structure by which
each team gets ID, City, and TeamName elements. Feel free to add more NFL teams if
you wish or use a completely different XML document altogether.
Create a new XML Web service project and give it the name XMLReturn. Remember to
import the System.XML namespace into your project:
Imports System.Xml
You will also need to import the System.IO, System.Data, and System.Data.OleDB
namespaces into your project.
14
The first example that you will look at shows the XmlTextReader object being used to
open an XML data source, your file from Listing 14.3, and to pass it into a DataSet
object. Line 5 shows the creation of the XmlTextReader, myXmlReader. A FileStream
236 Hour 14
object is passed into the XmlTextReader and the data is read in from there. Finally, the
ReadXml method of the DataSet object, myDataSet, is used to read the XML document
from the XmlTextReader into the DataSet, as shown in Listing 14.4.
The returned DataSet for the NFL.Xml document can be seen in Figure 14.3. The struc-
ture of the original XML document has been preserved completely.
FIGURE 14.3
The DataSet return
of NFL.Xml.
XML in Web Services 237
Navigating through the XML document once it is in the XmlTextReader object is simple.
In Listing 14.5, the XML document is navigated through and its TeamName elements are
added to an array. As in the previous example, the document is read into the
XmlTextReader object (line 3). This time, however, the XML document is parsed directly
in the XmlTextReader object.
In line 9, The MoveToContent method of XmlTextReader is used to navigate to each ele-
ment tag. Line 10 checks to make sure that the current element is named “TeamName.” If
it is, the ReadElementString is used to extract the text, in this case the name of an NFL
team, from the element. This text is then added to an array.
The returned array is shown in Figure 14.4. As expected, it contains only the contents of
14
the TeamName element for each team in the XML document.
238 Hour 14
FIGURE 14.4
An array of XmlNode
elements built from
NFL.Xml.
The most common properties of the XmlNode class, and those that are commonly used
in most of the derived classes shown in Table 14.4, can be seen in Table 14.5. Again, it
should be noted that each of the derived classes adds its own properties and method,
making a full listing of the functionality available to developers beyond the scope of this
book.
XML in Web Services 239
Table 14.6 lists the common methods of the XmlNode class. Many important methods
are added to the individual classes that implement the XmlNode class. For example, the
XmlDocument object includes a number of methods, such as CreateElement and
CreateAttribute, which are used to create other objects (XmlElement and
XmlAttribute objects in this case) for use in working with their data.
The array of XmlNode objects based on the NFL.Xml file can be seen in Figure 14.5. If
you had wished, you could have iterated through and grabbed the “Teams” elements
instead of “TeamName.” This way, each of the XmlNode objects would have contained the
elements “ID,” “City,” and “TeamName.”
FIGURE 14.5
An array of XmlNodes
based on NFL.Xml.
14
242 Hour 14
The properties and methods of the XslTransform object are shown in Tables 14.7 and
14.8, respectively. As you may have noticed, there are not a lot of properties or methods
to this class. Its only real purpose is to perform transformations on XML data.
In order for the transform to accomplish its task, an XSL style sheet must be used. A
detailed discussion of the actual syntax of the transform document is a bit beyond the
scope of this book, but a quick look at the NFL.Xsl document shown in Listing 14.7 will
allow you to pick up enough to perform some simple transforms of your own.
XML in Web Services 243
1: <?xml version="1.0"?>
2: <xsl:stylesheet version="1.0"
3: xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
4:
5: <xsl:output method="xml"/>
6:
7: <xsl:template match="/">
8: <NFL>
9: <xsl:apply-templates/>
10: </NFL>
11: </xsl:template>
12:
13: <xsl:template match="Teams">
14: <Team>
15: <ID>
16: <xsl:apply-templates select="ID/text()" />
17: </ID>
18: <Name>
19: <xsl:apply-templates select="City/text()" />
20: -
21: <xsl:apply-templates select="TeamName/text()" />
22: </Name>
23: </Team>
24: </xsl:template>
25:
26: </xsl:stylesheet>
This rather simplistic XSL style sheet creates a new XML document with “<NFL>” as the
root element. Inside of the root element, the transformation will match each “<Teams>”
element and replace it with a “<Team>” element. Inside of each “<Team>” element, will
be “<ID>” and “<Name>” elements.
The last aspect worth mentioning is the use of the select statement in lines 16,19, and
21. These statements retrieve the text from the original element listed and add it to the
new document.
In order to use the XSL document, create a new method called XML_Transform, and set it
to return a DataSet. Alternately, you could return an XmlNode object.
The first thing that you must do is load the NFL.XML document. This is done in line 8 of
Listing 14.8 through the use of the XmlDocument object, myDoc. After loading the XML
document, you must load the XSL document into the XslTransform object, myTrans.
14
244 Hour 14
In line 10, we create an XmlNavigator object to use as the XML reader for our
XmlTransform object. This object is a high speed, forward-only XML reader that can be
found in the System.Xml.Xpath namespace. That means that you have to add the import
statement for this namespace into your service as well.
Imports System.Xml.Xpath
Now the Transform method of the XmlTransformation object is ready to be called. Pass
in the XpathNavigator, myNav, and the method will return a new XmlReader object with
the new XML Document. The XmlReader object is simply read into a DataSet object and
the object is returned to the service’s clients.
Your new XML can now be viewed in Figure 14.6, complete with the change from
“Teams” to “Team” and including the concatenated “City” and “TeamName” elements as
“Name.”
XML in Web Services 245
FIGURE 14.6
The transformed
NFL.Xml document.
Summary
In this hour, you learned how to retrieve and manipulate XML data in your XML Web
services. You also looked at some of the Objects and Namespaces provided by .NET to
deal with XML data. Later in the hour, you saw how to return XML-specific data from
your services. To end the Hour, you examined the XslTransform object and saw how to
use it to quickly change the entire structure of an XML document.
Q&A
Q What is the point of allowing the DataSet object to write out XML and XSL
documents?
A Well, one reason is the ability to save the DataSet object in a format that other pro-
grams could use. If you used ADO in previous versions, you may have come
across functionality that allowed you to save your record sets to disk and then,
when needed, reopen them. WriteXml and WriteXmlSchema provide that same
functionality and more. Now, other code can parse the data as straight XML or
open it into DataSet objects.
Q What is the point of returning XMLNode objects when the DataSet object is
14
in XML anyway?
A What is the point of not simply providing one large Integer type to handle all num-
bers instead of providing many, such as float and long? Sometimes, it is possible to
reduce the size of the data you are sending across the Internet by using straight
246 Hour 14
XML returns. Other times, if your data is manipulating large amounts of XML and
not really handling any relational data, it just seems more natural to remain with
the XML object model.
An additional reason is that the needs of your application may already require you
or your client applications to be using the System.XML namespace and objects but
not the System.Data and DataSet. If this is the case, why add the extra overhead
of including additional objects in your program?
Q Does the DataSet object deal with attributes?
A Yes, if you add an attribute to an XML document, say a “population” attribute to
the “City” element of the NFL.Xml document and run the XML_to_DataSet method,
you will see the “population” attribute present in the XML markup of your
DataSet.
As far as using attributes directly from the DataSet, your best bet is to perform a
transform on the original XML in order to get it into a simple, all element shape
before loading it into the DataSet. This is preferred to leaving the attributes to be
inferred as columns in a table, the default method, as this may produce tables with
a structure that is difficult to navigate.
Workshop
The Workshop is designed to help you review what you've learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. What method of the DataSet object allows XML data to be read in from files or
XmlReader objects?
A GetXml()
5. What method of XmlReader objects returns True when you have read to the end of
the document?
A EOF
Exercises
Create your own XML document and write a series of XML Web service methods to
deal with it. Try altering the functions above, as well. For example, alter Listing 14.8 to
return an XmlNodeList, or even a single XmlNode.
A. The example below alters the XML_Transform method so that it returns an array of
XmlNode objects based on the Name Node. This means that we will have an array of
XmlNodes that do not contain any child nodes.
<WebMethod()>
Public Function XML_TransformNode() As XmlNode()
myDoc.Load("C:\Book\NFL.xml")
myTrans.Load("C:\Book\NFL.xslt")
myNav = myDoc.CreateNavigator
Return myNode
End Function
14
PART IV
Web Services In-depth
Hour
15 Using ASP.NET Intrinsics
16 The XML Web Services Namespace/Web
Method
17 XML Web Service Events (Global.ASA)
18 Security and the SOAP Toolkit
19 Asynchronous Operations
20 Debugging Your XML Web Services
21 Error Handling in XML Web Services
22 Publishing an XML Web Service
HOUR 15
Using ASP.NET Intrinsics
In this hour, you will look at how to use the objects that are built into
ASP.NET to add further functionality to your XML Web services.
Throughout the hour, you will see how to add global data to your application
as well as how to maintain state for individual users. You will also learn how
to retrieve information about both your server environment and the clients
that are making requests.
In this hour we will discuss the following:
• Session object
• Application object
• Server object
• HttpContext object
• Cache object
252 Hour 15
Session Object
The Session object provides the mechanisms through which individual clients, or, more
specifically, instances of an XML Web service’s proxy objects within those clients, main-
tain state. The Session object also provides a way of gathering information about indi-
vidual clients, which is useful for delivering customized functionality.
The most common use of the Session object is the handling of Session variables.
Session variables allow data to be stored and modified throughout the life of the object
being referenced in the client application.
In order for a session to be tracked by your XML Web service, you need to add a prop-
erty setting to your WebMethod attribute tag. This property lets your service know that it
should begin saving session information. The syntax for this is
<WebMethod(EnableSession:=True)>
The data can then be retrieved by simply passing the key value back into the Session
object as follows:
<WebMethod(EnableSession:=True)> _
Public Function GetSessionText() As String
Return Session("Text")
End Function
Running a service with these two methods in it will demonstrate how sessions function.
Run the service and navigate to the SetSessionTest page, shown in Figure 15.1, and
enter some text. When you click the invoke button, the service will store this data in the
Session collection of this particular client’s Session object.
Using APS.NET Intrinsics 253
FIGURE 15.1
Setting your Session
level variable.
15
If you invoke the GetSessionTest method now, you will see your text returned to you,
as in Figure 15.2.
FIGURE 15.2
The variable stays set
throughout the session.
254 Hour 15
If you wish to verify that additional clients will operate in a separate session, simply
open addition instances of Internet Explorer and run the methods in those as well. You
should notice that every instance of Internet Explorer is generating a different return
value for the GetSessionTest function.
The Session object also provides functionality beyond just storing a collection of session
data, although that will be the function you probably use most often when dealing with
Session objects inside of an XML Web service. Table 15.1 shows some of the other
method of the Session object that you may invoke in your services.
In addition to the methods shown in Table 15.1, Table 15.2 lists some of the properties of
the Session object that can be called from within your service.
IsNewSession Gets a Boolean indicating whether the Session is new; will return True only
if a Session variable has been created
IsReadOnly Gets a Boolean determining if the HttpSessionState is read only
IsSynchronized Gets a Boolean determining if access to the cookie collects values is read only
Item Gets or Sets an item in the HttpSessionState’s collection value by key name
continues
Using APS.NET Intrinsics 255
One of the more useful methods of the Session object is the Abandon method. This
method destroys the session, and the next call to a method that uses sessions from the
client that generated the original session will be treated as a brand new session. The fol-
lowing code shows the Abandon method in use:
<WebMethod(EnableSession:=True)> _
Public Sub DestroySessionTest()
Session.Abandon()
End Sub
To test if a Session is new, you can make use of the IsNewSession method, shown next,
which returns True until the collection contains a key/value pair.
<WebMethod(EnableSession:=True)> _
Public Function SessionTest() As Boolean
Return Session.IsNewSession
End Function
Running the service and invoking the SessionTest method returns False, as seen in
Figure 15.3, after you have used the SetSessionTest to create a new item in the
Session’s collection.
FIGURE 15.3
SessionTest Returns
False after Session
level variables have
been created.
After calling the DestroySessionTest method, you can verify that the session has been
abandoned by invoking the SessionTest method again. You are now in a new session.
256 Hour 15
FIGURE 15.4
IsNewSession returns
True after a session
has been abandoned.
As an example of how a Session object can be used to return some custom data, look at
this example that uses the LCID, or local identifier, property of the Session object to
return currency type depending on the country code of the user.
First, you need to create an enumeration to be used in selecting a country code. The fol-
lowing would be appropriate:
Public Enum CountryType
Albanian = 1052
Estonian = 1061
Finnish = 1035
End Enum
The code in Figure 15.1 accepts an argument, Country, of type CountryType and uses
that to set the LCID property in line 7. Once that property has been set, functions, such
as FormatCurrency in line 9, will behave according to the standards of the users region.
LISTING 15.1 Returning Currency from the User Nation with the LCID Property
1: <WebMethod(EnableSession:=True)> _
2: Public Function ReturnCurr(ByVal Country As CountryType, _
3: ByVal iNum As Integer) As String
4:
5: Dim retNumb As String
6:
7: Session.LCID = Country
8:
9: retNumb = FormatCurrency(iNum)
10:
11: Return retNumb
12:
13: End Function
If you invoke the method and type in one of the three country names from the
CountryType enumeration, the method will return the currency to you in the denomina-
tion corresponding to the country of origin. See Figure 15.5 for an example.
Using APS.NET Intrinsics 257
FIGURE 15.5
Using the LCID to dis-
play currency in
15
Estonian Kroonies.
Application Object
Unlike the Session object, the Application object, or HttpApplicationState, contains
information that is pertinent to all clients using the application. The methods and collec-
tions of the Application object will behave the same way for all client applications that
call them. This means that name/value pairs added to the application object’s collection,
which is accessed in the same manner as the Session object’s, can be seen by all clients,
regardless of whether the session has been enabled or not.
Some of the more commonly used methods of the Application object can be seen in
Table 15.3. As you can see, they deal mainly with placing items and their keys into a
collection.
The main properties of the Application object can be seen in Table 15.4. You should be
familiar with these properties already as all of them existed in the Session object and
function identically to their counterparts.
The following method accepts a string argument and stores it in the Application’s collec-
tion under the key name “Text.” The Lock and UnLock methods are used to lock access to
the collection and prevent possible errors during additions or edits to the collection’s objects.
Methods trying to access the Application object during a lock will typically wait for access
to be re-enabled via the UnLock method or will time out if that is too long in coming.
<WebMethod()> _
Public Sub SetApplicationTest(ByVal sText As String)
Application.Lock
Application("Text") = sText
Application.UnLock
End Sub
After an item has been added to the collection, it can be retrieved in the same manner as
items from the Session object. The method below returns the "Text" item that you
added in the previous method.
Using APS.NET Intrinsics 259
<WebMethod()> _
Public Function GetApplicationTest() As String
Return Application("Text") 15
End Function
Finally, utilizing the Application object’s clear method, you can test to verify that all of
the items can be cleared from the collection.
<WebMethod()> _
Public Sub ApplicationTest()
Application.Clear()
End Sub
Run the service and add some text to the application object by invoking the
SetApplicationTest method, as seen in Figure 15.6.
FIGURE 15.6
Setting your
Application level
variable.
Now, open some additional Internet Explorer windows and navigate to the
GetApplicationTest method. This is to verify that the information saved in the
Application is available to all sessions, as seen in Figure 15.7.
When you invoke the method in each of the instances of Internet Explorer, you should
receive the same text response from every call, as seen in Figure 15.8.
Finally, if you invoke ApplicationTest, which clears the collection, and then return to
GetApplicationTest and invoke that, you will receive a null string, as illustrated in
Figure 15.9.
260 Hour 15
FIGURE 15.7
Opening multiple
sessions.
FIGURE 15.8
Every session sees
the same results.
FIGURE 15.9
All of the Application
variables have been
cleared.
Using APS.NET Intrinsics 261
Server Object
The Server object, or HttpServerUtily, provides functionality that I utilized when pro- 15
cessing Internet requests. Most of the functionality of this object is used more often in
standard ASP.NET, but some may be useful when developing an application that needs to
react to different types of requests or users.
The most commonly used method of the Server object can be seen in Table 15.5.
The Server object’s methods, many of which deal with encoding and decoding strings
for working with the actual HTTP requests, something that is abstracted away from you
when creating XML Web services, are shown in Table 15.6.
The following example shows how the Server object can be used to retrieve information
about specific requests, client applications, and the Server environment itself. In this
case, the method returns the name of the Server that is processing the request.
262 Hour 15
<WebMethod()> _
Public Function TestServer() As String
Return Server.MachineName()
End Function
Figure 15.10 shows the machine name, as a string type, returned from the previous
method.
FIGURE 15.10
Returning the Server’s
machine name.
HttpContext Object
The HttpContext object is actually the top-level object of the others that you have
encountered so far in this hour. What this means is that HttpContext actually contains all
of these other objects. It should be noted however, that access to the HttpContext object
itself is not provided in the System.Web.Services namespace but is instead provided in
the System.Web namespace.
The HttpContext object provides only one public property, Current, which is used to
get the HttpContext object for the current HTTP request. This is done as follows:
MyContext = httpContext.Current
HttpContext also provides one public method, GetAppConfig, that is used to return con-
figuration information for the current application.
Once an HttpContext object has been retrieved using the Current property, that object
exposes the properties shown in Table 15.7.
As you can see from Table 15.7, many of the properties of the HttpContext object sim-
ply provide a reference to other objects that allow for greater control over every detail of
the HttpRequest being serviced. Again, most of these objects and their properties pro-
vide information that is often more useful in a straight ASP.NET application, but they are
still provided in XML Web services in the event that you should need them.
The example below shows the Request object being used in order to retrieve the host
address of the client application that is making the method call. This information could
be useful when securing a Web service.
Imports System.Web
Return myContext.Request.UserHostAddress
End Function
The host address of the calling application can be seen in Figure 15.11.
264 Hour 15
FIGURE 15.11
Returning the Internet
protocol address of the
client application.
Cache Object
The Cache object, as the name implies, is used to cache data in much the same way as
the Application object. In fact, a look at the properties of the Cache object, Table 15.8,
shows an Item property that accepts a key value, opening up a collection of name/value
pairings that is identical to that seen in both the Application and Session objects.
Where the Cache object differs from the Application object is in the overall control that
it gives you over the behavior of the data being stored. Both provide global access to the
data that is stored, but only the Cache object provides a built-in mechanism for clearing
items out of memory based on timing or dependency relationships. The Cache object
allows items to be added to the collection with a series of constraints that determine
exactly how long they should be stored, in what order they should be cleared, and what
other items or files they depend on in order to stay current. The methods in Table 15.9,
particularly the Add method, help to provide this functionality.
At its core, the Cache object behaves exactly like the application object. In fact, the fol-
lowing code could be used to replace the earlier SetApplicationTest method:
15
<WebMethod()> Public Sub SetCache(ByVal Stuff As String)
Dim myContext As HttpContext
myContext = HttpContext.Current()
myContext.Cache("Text") = Stuff
End Sub
The following method could then be used to retrieve this cached information in place of
GetApplicationTest.
myContext = HttpContext.Current()
Return myContext.Cache("Text")
End Function
This use of the Cache object is a bit redundant, however, because the Application
already provides such functionality. As you explore the Add method of the Cache object,
you will begin to understand its full usefulness.
The Add method of the Cache object, shown next, takes the name/value pairings and adds
dependencies, expiration dates, and item priorities.
Public Function Add( _
ByVal key As String, _
ByVal value As Object, _
ByVal dependencies As CacheDependency, _
ByVal absoluteExpiration As DateTime, _
ByVal slidingExpiration As TimeSpan, _
ByVal priority As CacheItemPriority, _
ByVal priorityDecay As CacheItemPriorityDecay, _
ByVal onRemoveCallback As CacheItemRemovedCallback _
) As Object
In the method call, key and value are the name/value pair used in the cache collection.
New to this is the dependencies argument. Dependencies refer to files or cached items
upon which this cached item is dependent. If the object in question changes, then the
cache item is deleted. A CacheDependency accepts a string argument representing the file
path or cache key of the item upon which a dependency is being defined. This takes the
following format:
New CacheDependency("C:\Book\NFL.xml")
266 Hour 15
CacheItemPriority.High
Lastly, the onRemoveCallback argument allows for the cache to provide a delegate func-
tion that will be called if the item is removed from the cache.
Summary
In this hour, you learned how to use the built-in objects provided by ASP.NET to give
your XML Web services greater flexibility and control over how client requests are han-
dled. You learned how to use these objects to maintain state both globally, for all clients,
and individually, for single instances of your service being referenced from within a sin-
gle client application. You also learned how to cache data to improve your service’s per-
formance.
Q&A
Q Why use Session and Application variables when I can just use global vari-
ables and collections?
A There are several reasons for utilizing each of the objects. The Session object is
useful because, unlike a global variable or collection that would be identical for
Using APS.NET Intrinsics 267
and potentially seen by every client, the Session object provides a new instance
for every client application that accesses it. The Application object is a bit subtler
in its benefits. Globally declared variables can be used in XML Web services and
15
indeed are used in some of the examples in this book, but the Application is a
convenient collection that already exists globally and allows you to add, remove, or
alter items in any method within your service without the extra overhead of adding
additional global collections.
Q What is the benefit of using the Cache object if the only thing that it adds is
more ways to have my data disappear?
A The cache object provides some very powerful features. First of all, if you have
cache data that has been pulled from a file, such as an XML document, you can
create a dependency and have the items removed from the cache if the document is
altered. From there you have two options. The first always checks for the existence
of the data, and if it isn’t present, reloads it from the source. The second object
uses the callback feature to provide a method that automatically reinstates the item.
Also, the main purpose of the cache item is performance. You set your item in the
cache so that if the data are being requested often, they stay in memory and are not
requeried as often. If the items are not used frequently, they are dropped and valu-
able memory is reclaimed.
Q Is there any difference between the Session and Application objects that are
exposed by the HttpContext object and those directly accessible from within
the System.Web.Services namespace?
A No. The System.Web.Services namespace gives you direct access to these objects,
which are actually part of the HttpContext object, because they are frequently
used objects. If you were to add a name/value pair directly to the Application
object and then check the HttpContext’s Application object and test for the same
pair, you would see that you are working with the exact same instance of the
Application object.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. What object would you use to store information being used by multiple meth-
ods of your service that is pertinent only to a single client application?
A Session
268 Hour 15
2. How do you retrieve the data stored in an Application object under the name
"SomeText"?
A myData = Application("SomeText") or myData =
Application.Item("SomeText")
3. What method do you call if you need to start a client’s session over again?
A Session.Abandon
4. What would you need to pass into the priority argument of the Cache object’s
Add method in order to set a priority that is below normal?
A CacheItemPriority.BelowNormal
Exercises
Try building a service that utilizes Application and Session objects to handle global
data. A rather silly, but wholly applicable, example might be an application that allows a
user three guesses at a word inputed by another user.
That service might look something like this:
Public Class Game
Public Answer as String
Public Hint1 as String
Public Hint2 as String
Public Hint3 as String
End Class
Application("Game") = GameInfo
End Sub
<WebMethod()> _
Using APS.NET Intrinsics 269
Return sHint
End Function
<WebMethod(EnableSession:=True)> _
Public Function GiveAnswer(ByVal Answer As String) As String
Dim GameInfo As New Game()
Dim sResponse As String
GameInfo = Application("Game")
Return sResponse
End Function
HOUR 16
The XML Web Services
Namespace/Web Method
In this hour, you will see how the WebMethod attribute can be used to pro-
vide advanced features to your XML Web services, such as transactions and
method overloading. You will also see how this attribute can be used to
increase performance through the use of results caching and buffering.
Finally, you will look at the WebService attribute and see how it can be used
to give your services their own namespaces and descriptions.
Throughout this chapter, we will discuss the following:
• Buffering output
• Caching requests
• Changing namespaces
• Method overloading
• Transactions
272 Hour 16
WebMethod Attribute
In Hour 7, you saw how the WebMethod attribute could be added to a function declara-
tion in order to create an XML Web service method. Now you will see how the proper-
ties of the WebMethod attribute can be used to give you greater control over the behavior
of your methods and even allow you to add some fairly advanced functionality.
As of this writing, the WebMethod provides six properties that give you access to func-
tionality, including transactions, response buffering, and method overloading. The gen-
eral syntax for setting the WebMethod attribute’s properties is as follows:
<WebMethod(Property:=Value)>
If you need to set multiple properties, you simply separate them by a comma as follows:
<WebMethod(Prop1:=Val1, Prop2:=Val2)>
This descriptive text will be displayed in both the WSDL file and on the XML Web
service’s automatically generated help page. Figure 16.1 shows the description in the ser-
vice’s Internet Explorer displayed page.
The XML Web Services Namespace/Web Method 273
FIGURE 16.1
Using the Description
property of WebMethod
to describe an XML
Web service method.
16
when a request comes in whose parameters match those of a previous request, the cached
value is returned. This can be especially useful if you are creating methods that accept a
narrow scope of parameters, such as an enumeration, or that provide infrequently chang-
ing data, such as a list of files available on a server.
The CacheDuration property accepts an integer value that determines the number in sec-
onds that the service will cache the results of requests. The default value of the
CacheDuration property is 0, which disables caching altogether. The following code line
shows a function declaration for a method that returns the date, without time. The
response will be cached for a single minute.
<WebMethod(CacheDuration:=60)> Public Function TodaysDate() As Date
It should be noted that, through the use of caching, the above request loses some accu-
racy in its response. It is now possible that the current data will be incorrectly returned
for up to one minute after the data has changed.
It should also be noted that using caching in methods that have a large set of possible
return values or return large amounts of data might dramatically affect performance as
memory begins to fill with cached data.
3. At least one data type must differ. This means that you can have
Method1(Integer, double) and Method1(integer, short).
In order to use method overloading in XML Web services, it is not enough to simply
declare several methods with the same name, and, in fact, doing so will produce errors.
You need to make use of the MessageName property in order to achieve this.
The MessageName property accepts a string value that will actually be used in the SOAP
calls to the service. The proxy handles this and the developer of client software still sees
the method as being overloaded.
The code in Listing 16.1 shows the MessageName property being used to create a method
called Add that will answer to SOAP calls as Add_Shorts.
This method creates a version of the FourFuncCalc service’s Add method that works on
shorts as opposed to integers. If you want, you can now alter the original version of the
Add function in order to give it a message name as well. This is not necessary, as one of
276 Hour 16
the Add methods is allowed to operate without the MessageName property set; however, in
this case it may be good form to have a separate message name for each type being used.
<WebMethod(MessageName:=”Add_Integers”)>
Public Function Add(ByVal iNum1 As Integer, ByVal iNum2 As Integer) As Integer
Finally, you can create another version of the Add method that accepts doubles and
returns a double as well.
<WebMethod(MessageName:=”Add_Doubles”)>
Public Function Add(ByVal iNum1 As Double, ByVal iNum2 As Double) As Double
Now, when a client application makes a call to the Add method, the actual method that
runs will be determined by the type of data passed to it. Obviously, client applications
cannot mix and match argument types unless you specifically create more Add methods
to accept pairs of different data types.
Interestingly, when you run the service’s auto-generated help page in Internet Explorer,
the message names are shown instead of three separate Add methods. This is demon-
strated in Figure 16.2.
FIGURE 16.2
Overloaded methods
in the .ASMX file.
Any client application with a reference to the service could call the Add method by using
the following code, where oCalc is the object referencing the service and iNum1 and
iNum2 are arguments of type integer, short, or double:
oCalc.Add(iNum1, iNum2)
The XML Web Services Namespace/Web Method 277
To illustrate how a method can be used to accept optional parameters and perform
slightly different functions, depending on what is passed to it, the following methods
were created. Listing 16.2 shows a method named Add_Child that accepts a string as an
argument and returns a string value.
The method in Listing 16.3 accepts the original string and also accepts a byte, iAge, as a
second argument.
Now, when a client application calls the AddChild method with a string:
oService.AddChild(“Billy”)
The service returns, “Billy is in class” without the use of the method name. Likewise, if
the call is made using the additional integer argument, iAge
oService.AddChild(“Billy”, 5)
“Billy is in class and he is 5 years old” is returned. Again, the client did not, and in fact
could not, make use of the Add_ChildAge method name.
Now your text will appear at the top of the auto-generated Internet Explorer help page, as
seen in Figure 16.3.
FIGURE 16.3
The description
for the entire XML
Web service.
In addition to showing up in the service’s help page, the descriptive text shows up in the
WSDL file of the service. In Figure 16.4, you can see your description, between docu-
mentation tags, within the service’s definition.
FIGURE 16.4
The Service’s descrip-
tion in the WSDL
description file.
The XML Web Services Namespace/Web Method 279
In order to create a method that uses transactions, you need to set the
TransactionOption property to RequiresNew. This will signify that a new transaction
must be created for the method. The TransactionOption property can also be set to
Required, but since XML Web service methods can only be the root of a transaction, and
not just take part in them, this will have the exact same effect as RequiresNew.
If you wish to explicitly declare that a method not run a transaction, you can set the
TransactionOptiond property to Disabled, which is the default setting. Setting the
property to Supported or NotSupported will also have the same effect.
Listing 16.4 shows an operation that is running inside of a transaction. If any of the
SQL commands should fail, the entire operation would be rolled back and nothing on
the SQL Server would appear to have changed.
280 Hour 16
The ContextUtil also provides the SetComplete method, which allows you to explicitly
commit the current transaction.
NameSpace
When an XML Web service is being developed, it is given the default XML namespace
of “http://tempori.org/”. This namespace is fine for development situations, but once
the service is in production, it will need a better namespace to avoid possible confusion
with other XML Web services that may have the same name.
If you find it difficult to believe that services may be created using identical names, think
for a minute about how many services might be created to provide accounting services
and then think how many of them might be called “Accounting” or “Accountant.”
Changing the service’s namespace works just like adding a description:
<WebService(NameSpace:=”http://localHost/FourFunctionCalc”)>
When you add the above line of code to your XML Web service, you will notice that the
URL becomes live. You can now navigate to the URL that you designated for your name-
space and it will appear in Visual Studio .NET, as shown in Figure 16.5.
282 Hour 16
FIGURE 16.5
Using the NameSpace
to navigate to docu-
mentation.
You do not need to use an URL as your namespace—any string will do. Using
an URL that you have control over just ensures that no one else will create a
service with both the same name and namespace as yours. Also, it gives con-
sumers a place to go to find documentation if you choose to provide it.
Summary
In this hour, you saw how to use the WebMethod attribute to control caching and buffering
within your XML Web services. Further more, you learned how to add transactions to
your services in order to create more robust services. You also saw how to overload
methods in your services and how client applications and their proxies handled these
overloaded methods. Finally, you saw how to use the WebService attribute to provide
additional information about your service.
Q&A
Q What is the significance of changing the namespace of an XML Web service?
A Namespaces prevent two or more XML Web services that may share the same
name from being confused, both by developers and by their code. By giving your
service a namespace, such as an URL that you control, you ensure that no other
XML Web services can be identified exactly like yours, unless, of course, you
develop services with identical names and namespaces.
The XML Web Services Namespace/Web Method 283
Q Why have description properties for both the service and its methods? Why
not just place the entire description in one place, such as a users manual?
A When developers are looking to consume a service, whether they are in-house or
out on the Net, they will want some general information on what the service as a
whole provides. This is where the WebAttribute description comes in useful.
When it comes time to implement a specific method, users will want to know more
about the specific functionality of the method in question. This is also where it is
useful to use the WebMethod Description. 16
Q I am writing sensitive data to a database that does not support transactions,
but I really need that functionality. What can I do?
A You have two options in handling these data operations. The first is to upgrade to a
database platform that handles your needs. If this is not possible, then you are
faced with building your own support. In methods where you make these critical
calls, keep track of the data that you are writing, and, if an error should occur, have
the error handling code explicitly undo all of your changes. This could become a
very large undertaking in a complex system.
Q If I am creating an XML Web service that will be very busy, won’t it be in my
best interest to always turn Buffering off, even in the case of methods that
return very small sets of data, such as integers?
A First of all, small data return sets, such as integers, would fall below the 16KB size
that even nonbuffered data still writes to memory. This means that you won’t get
any benefit from turning buffering off. Secondly, turning buffering off for a moder-
ately sized DataSet may keep the use of memory down but will increase the num-
ber of times that your service needs to communicate across Internet connections in
order to send multiple chunks of data over to the client.
Q Why go to the trouble of overloading a method if you have to give each one a
separate message name and the proxy class that clients use actually refers to it
by that name?
A The purpose of overloading your methods is so that a group of methods that actu-
ally provide the same basic functionality can be grouped together and presented to
the client application developer in a way that is both convenient and makes sense.
It is all about making your services usable to others.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
284 Hour 16
Quiz
1. How would you change the namespace of a service to
“http\\myServer\myService\” and add the service description, “This is my
service”?
A <WebService(Description:=”This is my Service”, _
NameSpace=”http\\myServer\myService”)>
5. (True or False) It is a good idea to cache a function that accepts two doubles as its
arguments?
A False; XML Web services will cache every unique pairing of arguments, thus
creating the possibility that in high traffic your service might cache thousands or
even millions of argument pairs and their results.
Exercises
Rewrite the FourFunctionCalc to include any features, such as a new namespace, buffer-
ing, descriptions, and so on, that you feel are appropriate to add. Remember, your service
may be used by many clients at once, so caching the results of an add method may not
be a very wise idea.
A. The following code changes the default namespace to
“http:\localhost\FourFunctCalc\” and adds some description text to the service. In
addition, all four methods are now overloaded to deal with shorts and doubles as well as
integers. Finally, every method now has a description tag.
Imports System.Web.Services
MyBase.New()
End Sub
#End Region
End Function
End Class
16
HOUR 17
XML Web Service Events
(Global.ASA)
In this hour, you will learn to handle the various events that are fired
throughout the lifespan of your XML Web service. You will also deal with
the issue of data persistence and how it is handled through the life span of a
single client application versus that of multiple users sharing a common
resource.
Throughout this hour we will discuss the following:
• The Global.ASAX
• Application level events
• Session level events
• Variable scope in XML Web service applications
290 Hour 17
Application Events
To understand application events, one must understand that a single XML Web service
may be simultaneously handling requests from several, even several thousand, client
applications at any one time. Indeed, it is possible that a single client application may
create multiple references to an XML Web service and maintain them concurrently.
With this in mind, application level events exist to allow you to initialize your service for
the entire user community. It is here that you can set variables and run procedures that
will affect all of your client applications.
XML Web Service Events (Global.ASA) 291
Application_Start()
When the very first client application creates a reference to your service and triggers its
constructor, the Application_Start() event is fired. This event fires only once in the
lifetime of the service and will not fire again, no matter how many client applications
may reference and deference your service, until the server has shut the service down and
the first new client comes along and starts the process over again.
17
When IIS actually shuts your XML Web Service down is a bit tricky. When the
last client calling your service has removed its reference to your service, IIS’s
reference count decrements to zero and the service shuts down. IIS also ref-
erences clients that “timeout.” This means that IIS has decided that the
client has taken too long between calls and is no longer active.
The Application_Start() event is a great place to initialize data that will be used by
multiple routines throughout your project. Often, files or databases are opened here and
information is read into application variables. In traditional Web applications, variables
are created for counters and initialized to either zero or the count before the service last
shut down.
Because no session is associated with the application level events, you are
limited to using the ASP application and Server objects that you learned
about in Hour 12.
If you reference session variables in the application level events, your code
will compile, but runtime errors will occur.
To illustrate how the Global.ASAX works, create a new XML Web service and name it
GlobalTest. You will modify this service throughout this hour.
Listing 17.1 shows the code that you will add to Application_Start() in order to
demonstrate what can be done with the Global.ASAX file. This code simply creates a
pair of application level variables identical to those that you saw in Hour 12 and sets
them to 0. These counters, ClientCount and HitCount, will be used to count the number
of users who access our application as well as the number of times requests are made to
our service.
292 Hour 17
This line increments the HitCount variable that you created in our
Application_Start() event.
Now, add the procedure shown in Listing 17.2 to your Service class. This code exposes
our counter and allows us to watch our service’s application level events in motion.
LISTING 17.2 Exposing the Counter in Our GlobalTest XML Web Service
1: <WebMethod()> Public Function AccessCount() As Integer
2: Return CInt(Application(“HitCount”))
3: End Function
Save the program and run it. When Internet Explorer opens, scroll down the Web Method
Reference for our AccessCount method and click the invoke button. Notice that the
answer returned is 2. This is because the Application_BeginRequest() event was fired
XML Web Service Events (Global.ASA) 293
when the service first opened and again when you invoked the AccessCount button.
Click the Invoke button a few more times, as in Figure 17.1, and verify that the counter
behaves as you expect.
FIGURE 17.1
Invoking our
AccessCount method
increments the counter.
17
Application_End()
The Application_End() event is fired when the Web server shuts your service down. This
event is often used to write application level variables to files or databases before the ser-
vice is shut down. Listing 17.3 shows the code to write your HitCount to a file. This data
would then be read in during Application_Start() in order to reinitialize the data.
Now, you must add the following line to the declarations section of Global.vb in order
for the new StreamWriter object to be included in our code:
Imports System.IO
294 Hour 17
When the service shuts down, you now have a log of the number of users that hit your
service. A simple alteration to the Application_Start() event (see Listing 17.4) will
allow your service to continue to track hits across multiple start-ups.
Please note, I have not included code to check for the existence of
Counter.txt when the application first starts. The file is created in
Application_End(). In order to avoid errors, either write some code to set
the HitCounter to 0 if the file is not present or manually create the file on
your C drive and simply leave it blank.
Application_Error
One additional event that is provided by the Global.ASAX is the Application_Error()
event. This event is fired every time an error is encounter when running the XML Web
Service. This error is very useful when creating ASP applications, allowing you to redi-
rect users to other pages or provide custom error messages. In XML Web Services how-
ever, it can be used to write trace events to the trace log or provide handling for custom
error objects. You will look at how to accomplish these tasks in Hours 20 and 21.
Session Events
In order to understand what session events are, you first have to understand what a ses-
sion is. Sessions are defined by individual references to your service. When a client
application makes its first call to your XML Web service, it starts a session, and that ses-
sion lasts until the client drops reference to the service.
Every client application that uses your service will run in a separate session and fire off
its own session events. In fact, a single client may instantiate several different objects
based on your XML Web service, each running their very own session.
XML Web Service Events (Global.ASA) 295
Enabling Sessions
Sessions are turned off by default in XML Web services. In order to activate them, you
have to add a property to the WebMethod attribute when declaring a method. In Visual
basic, the new method call is
<WebMethod(EnableSession:=True)> Public Function FunctionName() as Type
In C#, you would you make your call with the following syntax:
17
[WebMethod (EnableSession=True)]
You can enable sessions in some of the method calls on your service and leave others set
to false. This will enable you to determine when your session level events will fire or
even if they will fire.
If you enable sessions in one method call, but your service contains other
methods without sessions enabled, client applications may use your service
without ever generating a session.
Session_Start()
The Session_Start() event is fired the first time that a client application makes a call
to a method with EnableSession set to true. This event is used to set session level vari-
ables that will be used by method calls throughout the lifetime of this instance of the
service.
To demonstrate sessions, let’s go back to our GlobalTest project and cut the code from
the Application_BeginRequest() event and paste it into Session_Start(). Your code
should now look like Listing 17.5.
Now, run the service. Like before, you have the AccessCount() method, only this time,
no matter how many times you invoke it, it will return only the number 1. This is because
Internet Explorer represents a single client accessing our service in a single session.
296 Hour 17
Try opening a second instance of Explorer and navigating to the URL of our service, the
same URL showing in the current IE window. When you invoke the AccessCount()
method from this window, you now receive a count of 2. You now have two clients
accessing your service in different sessions, as illustrated in Figure 17.2.
FIGURE 17.2
Multiple sessions of
our GlobalTest XML
Web service.
FIGURE 17.3
Form1 of the
TwoServices
application.
17
Now that you have created references to the service, let’s put them to use. Create click
events for both buttons, as shown in Listing 17.7
When you run the service, two separate references are created to the GlobalTest XML Web
service. When you click on button1, a new session is started and the session number is
placed in Textbox1. Further clicks to button1 will not increment the session counter at all.
298 Hour 17
By clicking on button2, you start a new session and send its session number to
Textbox2. Notice that it is one higher than the number in Textbox1 (See Figure 17.3).
Future clicks to either of the buttons, without restarting the application, will continue to
return the new, higher number, as no new sessions are created.
Now, let’s go a step further with our session example. Delete the reference that you cre-
ated in Listing 17.6 and alter our Button_Click events to include the creation of a new
reference to the XML Web service (see Listing 17.8). These new methods will create
new sessions every time a button is clicked.
LISTING 17.8 Our New Button_Click Events Create New Sessions Every Time
They Fire
1: Public Sub Button1_Click(ByVal sender As Object,_
2: ByVal e As System.EventArgs) Handles Button1.Click
3: Dim oServ1 As New localhost.Service1()
4:
5: textbox1.Text = oServ1.AccessCount.ToString
6: oServ1 = Nothing
7: End Sub
8:
9: Public Sub Button2_Click(ByVal sender As Object,_
10: ByVal e As System.EventArgs) Handles Button2.Click
11: Dim oserv2 As New localhost.Service1()
12:
13: textbox2.Text = oServ2.AccessCount.ToString
14: oServ2 = Nothing
15: End Sub
If you run the TwoServices application now, you will notice that every time you click
either button, the session ID continues to increment. You are now creating and closing a
session with every Button_Click event.
Session_End()
The last event that you will deal with is the Session_End() event. As the name implies,
this event is fired whenever a session ends. Sessions end when a client application drops
a reference to them or when the dispose method is explicitly called.
To take a look at the Session_End event, let’s reopen our GlobalTest project and add the
flowing line to our Session_Start() Event:
Application(“ClientCount”) = cInt(Application(“ClientCount”)) + 1
XML Web Service Events (Global.ASA) 299
This line of code now increments ClientCount every time a session starts. You will now
add some code to the Session_End() event to decrement this value when a session ends.
This will now make ClientCount a count of the number of open sessions. Listing 17.9
shows the new Session_End():
1:
2:
Sub Session_End(ByVal Sender As Object, ByVal e As EventArgs)
Application(“ClientCount”) = CInt(Application(“ClientCount”)) - 1
17
3: End Sub
Finally, add the method shown in Listing 17.10 to Service1 to expose our active session
count to client application.
You now have a method that reports the number of active sessions for your service.
When you are testing this method, you may notice a lag between shutting
down a client reference to the service and the actual running of
Session_End() routine. This is because IIS is retaining the session until a ses-
sion timeout occurs.
Summary
In this hour, you learned how to use the Global.ASAX in order to access XML Web ser-
vice events. You delved into the differences between application and session level events
and some methods for taking advantage of them. This hour also included an example of
creating multiple sessions from a single client and how this differs from traditional ASP
applications.
300 Hour 17
Q&A
Q I want to open a database and read in a number of e-mail addresses that will
be shared with all users of my XML Web service. How do I do this?
A In your Application_Start() event, read in your data and store it in an applica-
tion level scripting dictionary object or an array declared in a module. You can now
share this across sessions. Remember, if you allow your users to make changes to
the data, you will have to write the data back to your database in an
Application_End() event.
Q Why do XML Web services use a Global.ASAX file like ASP anyway?
A Because, as has been discussed earlier, when your project is compiled and ready
for real-world use, it is an ASP.Net application. The only thing separating it from
standard ASP code is that an XML Web service includes the framework to expose
its methods to other applications. Because ASP was designed to use the
Global.ASAX file in order to handle application and session-wide events and
because XML Web services are just specialized ASP applications, they too use the
Global.ASAX file.
Q I have been testing the session events and can never seem to get the
Session_End() to fire when my client ends a session. Why is this?
A Well, IIS really controls when sessions end and, if you don’t tell it otherwise, it
will usually hold a session open for up to 20 minutes. If you need to ensure that
sessions end more quickly, try using the timeout property of the session object to
set the length that your session will remain open and inactive or add the session’s
abandon method to your service’s dispose method. Both of these features of the
session object were discussed in Hour 12.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
XML Web Service Events (Global.ASA) 301
Quiz
1. You run your service, but your session events never seem to fire. What are you
missing?
A You have forgotten to set EnableSession = true in your <WebMethod> decla-
ration.
2. You are keeping records of how many times each of your service’s methods are
used. These values are stored in application variables. When do you need to write 17
them to a file?
A You would write them to a file during the Application_End() event.
3. You are keeping track of the number of times your service is used per hour. Where
would you place the code to record the time of each hit?
A In Application_BeginRequest().
4. You retrieve data for individual client applications when they begin using your ser-
vice. During the time that they are hitting the service, they make changes to the
data. Where do you write code to save these changes?
A In the Session_End() event.
Exercises
Try writing a simple service that exposes a name and e-mail address to client applica-
tions. For the sake of simplicity, we will hard-code the names and e-mails, six of each,
into the service. The name and corresponding e-mail address should be given out one at a
time, in order, to each client that connects to the services. This process should start over
with the first name after the sixth has been assigned.
This service could be used in a help desk application to assign a service representative
that would be assigned to the client throughout its usage of the system.
If you want to explore this problem further, read the names in from a database and allow
any number of records to exist in the table.
A. To create your name and e-mail returning program, open a new XML Web services
project and name it ReturnNames. Add a module to the project and place the following
code into that module:
Module Module1
End Sub
End Module
This code creates a class called person, which will be used to hold a name and e-mail
address. We then create an array of Person objects called oPerson and use the Initialize
subroutine to call it.
Next, add the following code to your Application_Start() and Session_Start()
events in the Global file:
Sub Application_Start(ByVal Sender As Object, ByVal e As EventArgs)
Application(“Count”) = 0
‘Initialize Names
InitializeString()
End Sub
i = CInt(Application(“Count”)) Mod 6
Session(“Name”) = oPerson(i).name
Session(“Email”) = oPerson(i).email
Application(“Count”) = CInt(Application(“Count”)) + 1
End Sub
XML Web Service Events (Global.ASA) 303
Your Application_Start() event now creates an application level variable called count
and sets it equal to 0. It also calls the Initialize() routine to set up your array of per-
son objects.
Your Session_Start() event now sets session level variables for name and email. Notice
how we use a counter, i, to hold the return of the Mod operation performed on our
counter. Because this number will always be between 0 and 5, we can use it to count
through our array of person objects.
17
Lastly, we add the following returns to Service1 in order to return the name and email
values:
Public Function <WebMethod(EnableSession:=True)> Name() As String
Return Session(“Name”)
End Function
What Is Security?
Security has many different contexts, so what do we mean by a secure XML Web ser-
vice? A secure XML Web service is one that can be accessed only by the appropriate
people. You don’t want, for example, a spy accessing your top-secret database service.
Security is very important for XML Web services. Suppose Microsoft created a
Microsoft Word XML Web service. Without security, anyone could come along and use
that service without having to pay for it—not a good thing for Microsoft.
The good news is that XML Web services can be secured just like any other Web page or
application, making things easy on you, the developer.
The SOAP Toolkit also introduces a new type of XML document, the XML
Web Services Meta Language (WSML) file. It is similar to a WSDL file but
maps service functions to existing COM objects. It is also a proprietary speci-
fication, for use only with Microsoft’s technologies, so we won’t bother with
it too much here.
The SOAP Toolkit isn’t required to implement security for your XML Web services but,
along with IIS, provides a strong mechanism for doing so. For the examples in this hour,
you’ll need to install the toolkit.
Security Basics
Before we get started securing our services, let’s take a step back and examine how secu-
rity works with IIS and Windows.
There are three parts of security in IIS: authentication, authorization, and impersonation.
Authentication is the process of verifying a user—making sure people are who they say
they are. Authorization is used to determine what resources users have access to.
Impersonation is the ability for IIS to “impersonate” its users, thereby limiting its own
18
capabilities. We’ll cover only the first part in this chapter, as that is often the only secu-
rity measure you will implement for an XML Web service. (For more information on
security and XML Web services, check out Sam’s Teach Yourself ASP.NET in 21 Days.)
Authentication
When someone knocks on your door, you’ll usually want to find out who it is before
opening the door. There are various ways to find out the person’s identity, each with its
own level of security.
For example, you could simply ask, “Who is it?” Most of the time, you’d be able to trust
the person’s response, especially if the response is “It’s your mother.” If you had some
reason to believe the person is not your mother, you could look through your peephole or
window to check. If you’re afraid that the caller may have disguised herself as your
mother, you could go one step further and ask for identification, such as a driver’s license
or even a birth certificate (a bit drastic, we know, but it sometimes helps to be paranoid).
Security in IIS and Windows works very similarly. By default, IIS lets anyone into the
Web site—it leaves the door open to anonymous users. Many times this is fine—after all,
the purpose of most Web sites is to allow anonymous visitors to come and check it out.
308 Hour 18
If you want additional security for your Web site, you can enable authentication, which
instructs IIS to require credentials before allowing a visitor in. With .NET, there are three
types of authentication.
Direct to
No
login form
User supplies
Authenticated?
credentials
No
Deny access
Windows Authentication
Finally, there is Windows authentication. With this type, when IIS sees an incoming visi-
tor, it turns control over to the operating system (OS) for authentication. Windows then
validates the user’s identity against a list of known users for that OS. In Windows 2000,
this list can be seen by clicking on Start, Settings, Control Panel, Users and Passwords.
An example list is shown in Figure 18.2.
FIGURE 18.2
A list of users
in Windows.
18
There are three subtypes of Windows authentication: basic, digest, and Integrated
Windows (or NTLM). Basic and digest mode are very similar. When a visitor comes to a
Web site with basic or digest authentication enabled, they are prompted with a box,
shown in Figure 18.3. The supplied information is then validated against the OS’s users.
FIGURE 18.3
Basic and digest
authentication modes
ask for credentials.
The difference between these two modes is that the supplied credentials are not
encrypted with basic mode, whereas they are for digest. Also, basic mode is part of the
HTTP specification, which means any platform can implement it. So, with digest mode,
you get more security but less interoperability.
310 Hour 18
NTLM, like digest mode, is specific to Microsoft’s operating systems. With this mode,
no dialog box is shown when a user visits a secure Web site. Instead, the visitor’s copy of
Windows automatically communicates with the server’s copy, sending the current user’s
identity for authentication. The user will be allowed or denied access without any inter-
vention. NTLM is the most secure of the three modes.
Create a new directory in your root Web folder, secure, and create this file as
calculator.asmx inside it.
To enable authentication, you’ll need to open IIS. Go to Start, Settings, Control Panel,
Administrative Tools, Internet Services Manager. You’ll see something similar to Figure 18.4
(click on the pluses to expand the sections).
Security and the SOAP Toolkit 311
FIGURE 18.4
Internet Services
Manager allows you to
modify and secure
your Web site.
Under Default Web Site, you should see the new secure directory you created a moment
ago. Right click the folder in the left hand pane and select properties. You have several
options in the window that pops up, but for now, all we’re interested in is the Directory
Security tab. Under this tab you’ll see Anonymous access and authentication control,
with an edit button. Click edit, and you’ll see Figure 18.5. 18
FIGURE 18.5
The authentication
control panel.
Now for the true test. Try viewing the calculator.asmx XML Web service in your
browser (http://localhost/secure/calculator.asmx). A dialog box should pop up
asking for credentials. Enter your Windows username and password for entrance. Next
we’ll examine how to use the SOAP Toolkit to gain access in another way.
You should be familiar with the basics of ASP.NET by now, so this page should be easy
to follow. Let’s take a closer look.
Security and the SOAP Toolkit 313
On line 1 you have the Page directive, which simply sets up the language we’ll be using
on the rest of the page, Visual Basic.NET. The rest of the ASP.NET code is enclosed in
the script tags on lines 3 and 15.
The only method in this page, Page_Load, is called when the page loads. This is where
we want to call the secure XML Web service. Line 5 declares the variable we’ll use for
the SOAPClient object, and line 7 instantiates it. (Note that the SOAP Toolkit is not
managed code—that is, it was built with the .NET Framework—so we have to use
Server.CreateObject to instantiate it.)
On line 9 we call the mssoapinit function, which takes as a parameter the URL (or file
location) of the WSDL service description. Here we pass it the calculator service’s URL.
Line 11 calls the Add method of the service, passing in two numbers, and displays the
results in the label on line 18.
Save this file as client.aspx in your root Web directory and view it from your browser
with http://localhost/client.aspx. You should see something similar to Figure 18.6.
FIGURE 18.6
The service is secured,
so any attempt to 18
access it will result in
an error.
If you see instead an error on line 9, you may have an issue with encoding.
See “Encoding Issues” later in this chapter.
314 Hour 18
What happened? Remember that your XML Web service is now secure. Your attempt to
connect to it failed because you didn’t supply proper credentials. Luckily, with the SOAP
Toolkit, that’s easy to fix. Add the following two lines after line 9 and before line 11 in
Listing 18.2:
objSOAP.ConnectorProperty(“AuthUser”) = “clpayne”
objSOAP.ConnectorProperty(“AuthPassword”) = “helloworld”
As noted earlier in this hour, you may encounter problems in the previous
example involving encoding. If this is the case, see “Encoding Issues” later in
this chapter.
FIGURE 18.7
The service now allows
the authenticated user
access.
Security and the SOAP Toolkit 315
Using the SOAP Toolkit, you can now access secure XML Web services! The only addi-
tional thing you have to do is supply values for the AuthUser and AuthPassword proper-
ties of the ConnectorProperty collection.
Encoding Issues
When you viewed client.aspx through your browser, you may have seen Figure 18.8
instead of 18.6. If this is the case, you are having problems with the way the XML Web
service description was encoded.
FIGURE 18.8
This error means
the file encoding
is incorrect.
18
When you view the service description with the URL http://localhost/secure/cal-
culator.asmx?WSDL, ASP.NET shows you the XML output. The first line of this XML
looks something like
<?xml version=’1.0’ encoding=’UTF-8’ ?>
The encoding here is specified as UTF-8, and when your client accesses this description,
it expects UTF-8 data. However, when viewing the URL http://localhost/secure/
calculator.asmx?WSDL, your browser may not actually output UTF-8, even though the
XML thinks it does. Your browser is not smart enough to look at the first XML line and
format the output accordingly.
316 Hour 18
The SOAPClient object is very picky, and if the XML Web service description says UTF-8,
it must have UTF-8 or you’ll receive the error shown in Figure 18.8. The solution, then, is
to tell the SOAPClient not to expect UTF-8, and this is done by modifying the service
description itself.
View http://localhost/secure/calculator.asmx?WSDL once again, and this time right-
click and select View Source. In the file that pops up, delete the first line (see Figure 18.9),
and save it in the same directory as client.aspx: c:\inetpub\wwwroot\calculator.wsdl.
FIGURE 18.9
Delete the offending
XML line from the ser-
vice description.
Next, you’ll have to modify client.aspx slightly to use this modified description instead
of the URL. Change line 9 of Listing 18.2 to read as follows:
objSOAP.mssoapinit(Server.MapPath(“calculator.wsdl”))
The first part of this statement is the same—calling the mssoapinit function. Now
instead of passing it the URL of the service, you pass in the file name of the modified
WSDL file you created in the previous step.
You cannot, however, pass the filename in by itself because the SOAPClient won’t
know where exactly to look for it. The Server.MapPath function, given a filename,
returns the full path of the file. For example, this statement would return
c:\inetpub\wwwroot\calculator.wsdl, assuming that’s where you saved the file.
Security and the SOAP Toolkit 317
Leaving everything else the same, you should now be able to access the XML Web ser-
vice and see the correct output, shown in Figure 18.7.
The SOAP Toolkit has loads of other useful tools, so be sure to check out the documen-
tation that came with the toolkit.
Summary
Security is a very complex topic and must be taken into consideration when designing
any application. This past hour you learned what is means to secure an XML Web ser-
vice and how to go about doing so.
A secure XML Web service means one that cannot be accessed by unauthorized users.
SOAP provides no security mechanisms, so without other means of protection, any visi-
tor could use any XML Web service.
Security in IIS is handled via several different steps and methods. Authentication is the
process of verifying a user’s identity, authorization is making sure a user has access to
specified resources, and impersonation allows IIS to restrict its own privileges to provide
additional security.
18
Authentication is implemented in three different forms: Forms, Passport, and Windows
modes. Forms and Passport modes redirect unauthenticated users to login forms for
them to provide credentials. With Windows mode, IIS passes the authentication chores
to the OS.
Integrated Windows mode is in turn implemented in three additional forms. Basic is the
simplest and least secure. A client user supplies credentials via a pop-up box, and the
data is transmitted as plain text across the network to the server. Digest mode works sim-
ilarly, but the credentials are encrypted. Finally, Integrated Windows (or NTLM) mode
allows the client and server machine to communicate directly without user intervention.
The two machines compare user identities, and access is allowed or denied appropriately.
You used the SOAP Toolkit to easily build an XML Web service client. Using the
SOAPClient object and the ConnectorProperty collection, you are able to supply
authentication usernames and passwords to access secure XML Web services.
In the next hour, you’ll learn about using XML Web services asynchronously. This
allows your clients to continue doing other tasks while waiting for an XML Web service
to return results.
318 Hour 18
Q&A
Q Will the SOAPClient authentication method work with Digest and Integrated
Windows authentication modes?
A It will work with Digest mode. However, due to the way credential information is
sent in Integrated Windows mode, trying to supply AuthUser and AuthPassword
values when the service is secured in this way will result in errors. With Integrated
Windows mode, the only option is to log into the computer calling the client as a
valid user of the service.
Q I can’t select digest authentication. What gives?
A Digest authentication mode is new to Windows 2000 and, as such, requires IIS 5.0
to run. It also requires that your domain controller is running Windows 2000—
check with your network administrator or the Windows 2000 help files.
Q What is the difference between using SOAP headers for security and the
method described here?
A With SOAP headers, you can pass username and password information from a
client to the service. Recall from Chapter 4 that the mustUnderstand attribute
requires the service to evaluate the headers, providing a very good means for
implementing authentication.
Each method has its own benefits. Using the methods described in this hour, you
have to write very little code and can rely on IIS and Windows to authenticate
users for you. Using SOAP headers, you’ll have to write much more code, but you
have more flexibility in authenticating users; you can validate them against a data-
base, a text file, or any other method you choose.
Additionally, using IIS authentication, the user is prevented from ever reaching the
XML Web service until he or she is authenticated. Using SOAP headers, the user
must be able to access the service in order to send the headers; in other words, visi-
tors are able to take one more step inside your application before being stopped.
The method you choose will be largely influenced by your application and the
method you feel most comfortable with. The SOAP Toolkit can handle both.
Q What about SSL? Can I use that to secure my services?
A Absolutely. The Secure Sockets Layer is another protocol that can be used to
access Web sites and services. The ConnectorProperty of the SOAPClient collec-
tion provides two properties—UseSSL and SSLClientCertificateName—that are
expressly designed to use SSL. See the SOAP Toolkit documentation for more
information.
(Note that SSL is a slower protocol than HTTP, so using it may slow down your
application.)
Security and the SOAP Toolkit 319
Q I’ve been hearing lately of a lot of security holes in IIS 5.0. Will this be a prob-
lem for my XML Web service?
A That’s a tough question to answer. Since XML Web services are part of .NET, it is
an entirely new paradigm—many existing holes and hacks don’t exist in .NET.
However, there may be other holes that no one is aware of yet. There is quite a stir
in the development community about the security of XML Web services, with
many differing opinions.
In short, existing methods may be used to hack IIS, but XML Web services aren’t
vulnerable to these attacks.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. What are the three steps of security?
A Authentication, authorization, and impersonation. 18
2. (True or False) IIS always requires users to be authenticated.
A False. By default, anonymous users are allowed entry.
3. Which is most secure: Basic, Digest, or Integrated Windows modes?
A Integrated Windows mode.
4. (True or False) The SOAP specification addresses security issues.
A False, though there are rumors of advances being made.
5. How can XML encoding cause problems? How do you get around it?
A XML often specifies an encoding type (typically UTF-8) in the first line of an
XML file. The encoding specified by this line must match the actual encoding of
the file, or you will receive an error.
To remedy the problem, simply remove the offending first line in the WSDL
description and save the modified file.
Exercises
1. Build an XML Web service that returns the reverse of a string passed into it. For
example, passing in “Web Services” would return “secivreS beW”. Secure this
service with Basic authentication.
320 Hour 18
If you are having encoding issues, view the source of the WSDL description of the
service from Exercise 1, delete the first line with the encoding, and save it as
StringReverser.wsdl in the same location as your client file. Then, change line 9
to read:
9: objSOAP.mssoapinit(Server.MapPath(“StringReverser.wsdl”))
18
HOUR 19
Asynchronous
Operations
In this hour, you will examine the various methods for calling an XML Web
service’s methods asynchronously. Throughout this hour, you will study the
Begin and End methods that are generated for your service and how they are
used to allow client applications to call your service and wait for it to
respond while still carrying out other operations.
In this hour, we will discuss the following:
• Asynchronous operations
• Callback functions
• The WaitHandle class
• The IAsyncResult interface
324 Hour 19
Add the following class to your service. This class will be used as the return type of the
rather simple service that you are creating.
Public Class TitleHolder
Public Name As String
Public Belt As String
End Class
Asynchronous Operations 325
Now you can add the method shown in Listing 19.1 to your code. This method accepts
an integer value and, based on that number, sets the TitleHolder object, oBelt, proper-
ties to contain a WWF Title Holder and the name of said title. This rather whimsical bit
of information is then returned by the method.
FIGURE 19.1
Async method
test form.
Table 19.1 shows the property settings for the controls that you just added to Form1.
Text Start
IAsyncResult Interface
IAsyncResult is an interface that is implemented by the return objects of asynchronous
operations. It, or more correctly the object implementing it, is used to determine if pro-
cessing has completed during an asynchronous operation. The properties of the
IAsyncResult interface are shown in Table 19.2.
Asynchronous Operations 327
Now, you can add the code in Listing 19.2 to the Click event of Command Button
btnStart. Line 4 of the code calls the BeginChamp method—the asynchronous way to
call the Champ method—and accepts the IasyncReturn implementing return object as
aReturn. Since we are not utilizing callback functions, the callback and asyncState 19
arguments are set to Nothing. In C#, you would set these values to Null.
With the method called, you now need ways to determine when processing is complete
and to retrieve the result of the operation. This is done by checking to see if the
IsCompleted property of Iasyncresult returns True or not.
328 Hour 19
Add the code in Listing 19.3 to the Click event of btnCheck. This code causes the
IsCompleted property to be checked and, upon receiving True, a call to be made to
EndChamp. When this call is made, line 5, the Textboxes txtChamp and txtBelt, are pop-
ulated with the results of the call.
When you run this new client application, type an integer into txtNum and click the Start
button and the Check button in quick succession. During this first call, the Server should
still be processing the request and you should receive the message in Figure 19.2.
FIGURE 19.2
The Champ method
is still running.
Asynchronous Operations 329
Eventually, the service should be ready to return, and the EndChamp method should be
called. At this time, you should receive information similar to that in Figure 19.3.
FIGURE 19.3
The Champ method
returns.
This method of calling a service can be very useful if you know that an XML Web ser-
vice method will require some time to process and you wish to run a few simple tasks.
One way to accomplish this would be to make your call and then enter a while loop that
checks for the return and continues to process other tasks until a value is returned.
callback Functions
A callback function is a function residing in the client application that is called when
the Begin method is finished processing. Typically, the callback function contains the
call to the End method. The callback method is set up by passing its address into an
object of type AsyncCallback and then passing this object to the Begin method. The syn-
tax for doing this is as follows:
Dim cb as New AsyncCallBack(AddressOf CallBackFunction) 19
Service.BeginMethod(arg1, arg2, .., cb, Service)
Alter the Click event of btnStart so that it contains the code in Listing 19.4. This code
sets the ChampCallBack function, shown in Listing 19.5, as the callback function used
in the call to BeginChamp in line 6.
continues
330 Hour 19
LISTING 19.5 Callback Function for Handling the Return of the Champ Method
WaitHandle
The WaitHandle object is used to allow client applications to make asynchronous calls to
an XML Web service and then wait for them to return. The WaitHandle allows the call-
ing application to resume processing after either one or all of the called methods have
completed processing.
The static members of the WaitHandle object are shown in Table 19.3. These are the
methods that you may use without declaring an object of type WaitHandle; for example:
WaitHandle.WaitAny(arrayofWaitHandles)
Both methods accept an array of WaitHandle objects, one for each method that is being
processed, and an optional parameter, either an integer or a timespan object, that deter-
mines how long the WaitHandle should wait before timing out.
Asynchronous Operations 331
At this point, add a new form, Form2, to your project and set it as the startup form. To
this form you will add nine textboxes and one control button, as shown in Figure 19.4.
FIGURE 19.4
New form for testing
asynchronous
method calls.
Text Start
332 Hour 19
Add the btnStart Click event, shown in Listing 19.6, to your code. This code makes
three separate calls to the BeginChamp method, in lines 11 through 13, and then creates
an array of WaitHandle objects, lines 15 through 18, with which to monitor them. This
array is passed into the WaitAll method of the WaitHandle object, line 21, and process-
ing halts there until all of the called methods return.
LISTING 19.6 Using WaitHandle to Call Asynchronous XML Web Service Methods
1: Private Sub btnStart_Click(ByVal sender As System.Object,
2: ByVal e As System.EventArgs) Handles btnStart.Click
3:
4: Dim oTitleHolder As New localhost.Service1()
5: Dim oChamp As New localhost.TitleHolder()
6:
7: Dim aResult1 As IAsyncResult
8: Dim aResult2 As IAsyncResult
9: Dim aResult3 As IAsyncResult
10:
11: aResult1 = oTitleHolder.BeginChamp(CInt(txtNum1.Text), Nothing, Nothing)
12: aResult2 = oTitleHolder.BeginChamp(CInt(txtNum2.Text), Nothing, Nothing)
13: aResult3 = oTitleHolder.BeginChamp(CInt(txtNum3.Text), Nothing, Nothing)
14:
15: Dim whResults(2) As WaitHandle
16: whResults(0) = aResult1.AsyncWaitHandle
17: whResults(1) = aResult2.AsyncWaitHandle
18: whResults(2) = aResult3.AsyncWaitHandle
19:
20:
21: WaitHandle.WaitAll(whResults)
22:
23: If aResult1.IsCompleted Then
24: oChamp = oTitleHolder.EndChamp(aResult1)
25: txtChamp1.Text = oChamp.Name
26: txtBelt1.Text = oChamp.Belt
27: End If
28:
29: If aResult2.IsCompleted Then
30: oChamp = oTitleHolder.EndChamp(aResult2)
31: txtChamp2.Text = oChamp.Name
32: txtBelt2.Text = oChamp.Belt
33: End If
34:
35: If aResult3.IsCompleted Then
36: oChamp = oTitleHolder.EndChamp(aResult3)
37: txtChamp3.Text = oChamp.Name
38: txtBelt3.Text = oChamp.Belt
39: End If
40:
41: End Sub
Asynchronous Operations 333
When you run the application this time, click the start button of Form2. The server will
make three calls to the BeginChamp method and then, once all three have completed pro-
cessing, Form2 will be updated to contain all three Title Holders, as seen in Figure 19.5.
FIGURE 19.5
All returns for Async.
Now, change the WaitAll method of the WaitHandle object, line 21 of Listing 19.6, to a
WaitAny method. This will cause processing to resume once any of the three methods has
completed. Run the server again, and you should see results like those in Figure 19.6.
FIGURE 19.6
Returning the update
DataSet with
DataTable bands.
19
Summary
In this hour, you saw how to use the Begin and End versions of an XML Web service’s
methods in order to make asynchronous calls. You also learned how to use the
IAsyncResult interface, implemented by the objects returned from Begin methods, in
order to determine when a service’s method had completed processing and was ready to
deliver a return. You also examined how callback functions are used to process return
values automatically, without the need for polling. Finally, you looked at how the
WaitHandle object is used to provide synchronous handling of asynchronous calls.
334 Hour 19
Q&A
Q What is the purpose of making asynchronous calls if you are going to use the
WaitHandle to stop processing and wait for a return?
A There are several reasons to use the WaitHandle and asynchronous calls instead of
just using the synchronous version of the calls. To give just a couple of examples,
out of many, where this might be appropriate, suppose that you are building a
client application and performance is a great issue. You find a couple of different
XML Web services that provide the functionality that you need and you use all of
them in your application. Now, if you make your calls and use the WaitAny
method, you need only to wait for the fastest one to return. This gives you speed as
well as a failsafe against a down service. Another use of the WaitHandle is to call
several methods at once, if your application relies on having all of their results
before doing anything else, and use WaitAny to halt processing. This usually pro-
vides slightly better performance than making each call and then waiting for the
return before making the next call.
Q How do callback functions help my application’s performance?
A The use of callback functions allows your application to make a call to an XML
Web service and then move on to other processing. When the original call is fin-
ished, a call to your callback function occurs, and that code is run. The main ben-
efit of this is that your client application spends less time sitting idle.
Q I have always heard the term threads used when discussing asynchronous call-
ing. What does that mean?
A When you make an asynchronous call to an XML Web service method, you are
creating a new thread. A thread is simply a segment of code that executes simulta-
neously to your application.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. What two methods would be called in an application that needed to execute an
asynchronous call to an XML Web service method named BoxScore?
A BeginBoxScore and EndBoxScore
2. What method of the WaitHandle object allows an application to resume processing
when the first of any asynchronously called method finishes processing?
A WaitAny
Asynchronous Operations 335
5. How would you call a method, BeginStockQuote, and pass it a callback function
named ProcessQuote? BeginQuote accepts one argument, a string type named
sStock. The object reference to the services proxy is called oQuotes.
Exercises
Practice writing applications that make use of asynchronous calls to the XML Web services
that you created earlier. As a starting point, try writing a simple application that accepts two
integers and calls all four methods of the FourFunctionCalc XML Web service.
A The following code accepts two integers, entered into two textboxes on a form, and
returns the results of the four methods of the FourFunctionCalc.
Dim oCalc As New localhost1.Service1()
End Sub
FIGURE 20.1
Editing the
Web.Config file.
Debugging Your XML Web Services 339
The Trace entry, shown next, provides you with the ability to customize several options
of the XML Web service runtime environment. The first is the ability to turn the applica-
tion level tracing on and off; this will have no effect on the Trace object features that you
will explore later in this hour.
<trace enabled=”false” requestLimit=”10” pageOutput=”false”_
traceMode=”SortByTime” localOnly=”true” />
First, change enabled=”false” to enabled=”true” and run the program. After Internet
Explorer opens, invoke the HelloWorld method a few times in order to get some calls
entered into the trace log. Now, in Internet Explorer, use the URL that is used to connect
to your service, substituting Service1.asmx with Trace.axd, where Service1 is the name
of your service. This will bring up the application trace file shown in Figure 20.2.
FIGURE 20.2
The Trace report after
calling some XML Web
service methods.
Notice, up near the top right of the trace file in Figure 20.2, the line “Remaining: 5.” 20
This line lets you know that the trace log will store five more requests before it starts
deleting the earliest requests. This number is controlled by the requestLimit parameter
of the trace tag in Web.config file.
Clicking View Details will bring up the details for the specific XML Web service request
made by a client, as shown in Figure 20.3. This information includes the state of server
variables, time of request, and much more. This can be very useful if you just need to
look in and check on specific usage in a low volume XML Web service or if you suspect
that something unusual is occurring on the server where the service is running.
340 Hour 20
FIGURE 20.3
Request details for
a specific call to
TraceTest.
It is also possible to add the trace reports directly to the bottom of the page that is gener-
ated for individual service calls via the use of the pageOutput property, also found in the
Web.Config file. If pageOutPut is set to true, the trace report is added directly to the bot-
tom of your page, as shown in Figure 20.4. Note that the URL for this request is still a
.asax extension.
FIGURE 20.4
The Trace report dis-
played at the bottom of
your WebService.ASAX
page.
Debugging Your XML Web Services 341
This last feature is far more useful in standard ASP.NET programs than it is in an XML
Web service, as the XML return data from the service’s method does not include any
trace information.
A further call
Debug.Write(“ and some more!”)
Notice that the second call to write added its output to the same line as the first. If you
need to advance to the next line when using Debug, you use the WriteLine method,
which is identical to the Write method with the added benefit of including a line termi-
nator at the end of the string.
Table 20.1 shows the properties commonly used when dealing with the Debug object.
The AutoFlush property and the Listeners collection deal specifically with using Debug
in conjunction with listeners and will be dealt with a little later in this hour.
20
TABLE 20.1 Common Properties of the Debug Object
Property Description
AutoFlush Indicates that output should automatically be written from the
Listener objects to the target media
IndentLevel Level of indentation on output
IndentSize Number of spaces of indentation
Listeners Listeners Collection
342 Hour 20
The most commonly used methods of the Debug object can be seen in Table 20.2. These
include various methods to write information to the output windows, or to listeners, and
a few, such as Indent, that control the formatting of output.
The methods WriteIf and WriteLineIf take the conditional as well as the message text
and write output only if the conditional is true.
Debug.WriteIf(fConditional, sMessage)
If the Indent method is called, the output will be indented forward the number of spaces
indicated by the IndentSize property, the default is five spaces. The Unindent method
can be called to move further output back the same number of spaces.
In the above, sName is an optional name for the new instance and oType can be either a
Stream object, a TextWriter object, or a file name. In order to write to the console, for
example, you would use the stream Console.Out. Listing 20.1 makes use of Stream
objects in order to output to a text file. The Stream object is a member of the System.IO
namespace and must be included by adding the following line into the namespaces area
of your code:
Imports System.IO
The code in Listing 20.1 makes use of two separate Listeners in order to show how both
the collection and the individual Listeners can be used to write output. In lines 9, 13, and
15 the Trace object writes various lines of output and the listeners collection writes them
to TestFile.txt and TestFile2.txt. The output written to TestFile.txt is shown
below.
This is Test Output
More Output to both
I’ll add my two cents
In line 11, the WriteLine method of one of the Listeners, myListener2, is used directly
to write output to TestFile2.txt, without sending the message to myListener1 as well.
You can see the additional line “I am in TestFile2” in the output to TestFile2 below.
This is Test Output
I am in TestFile2
More Output to both
I’ll add my two cents
sSource represents the name the Name of the application, sLogName is the name of the
Log being written, and sMachineName is the optional name of the computer to which the
event should be logged.
20
Also, important to the use of the EventLog object is the WriteEntry method. The write
entry method is used throughout your code to write events to the log. With the
WriteEntry method, you can write to any of the Windows standard logs, such as
Application Log, Security Log, and System Log, or create your own as you previously
saw. The most common usage of the WriteEntry method is
EventLog.WriteEntry(sSource, sMessage, oType)
346 Hour 20
In this code, sSource is a string by which the application is registered on the specific
computer, sMessage is some string message that you are writing to the log, and oType is
the type of entry using EventLogEntryType. EventLogEntryType is an enumeration con-
taining types, including Error, Information, and Warning.
The most common methods of the EventLog object can be seen in Table 20.5. Generally
speaking, you will probably delete logs and log entries from the Event Viewer and not
from code.
The properties listed in Table 20.6 are the most commonly used instance properties of
the EventLog. Calling them instance properties means that a new instance of an
EventLog object must be called in order for these properties to be called, as follows:
LogDisplayName, in particular, is useful if you wish to provide users with some informa-
tion on where to look in the Event Viewer to check on your application.
Listing 20.2 shows some code that was used to access a log called TraceTest; it creates
the log the very first time that it is called and writes an event to the log.
Compare the code in Listing 20.2 to the log pictured in Figure 20.5. Notice how the source
used in the CreateEventSource method, sSource, is displayed as the source of the event.
This is useful if you wish to have several XML Web services, or even several portions of
the same service, use a common log but display their events under different names.
FIGURE 20.5
Viewing TraceTest in
the Event Viewer.
20
348 Hour 20
Double clicking on an event will bring up the Event Properties window, shown in
Figure 20.6, for that event. This is where the message text that you entered will be
displayed.
FIGURE 20.6
The Event Properties
Window.
Then, you can create an EventLogTraceWriter object using the EventLog object, myLog,
as your target for output.
Dim myTraceLog as new EventLogTraceListener(myLog)
Finally, you can add your Listener to the Listeners Collection as follows:
Trace.Listeners.Add(myTraceLog)
As you can see, the Event Log provides you with a powerful tool to use when tracking
rare events and errors that may occur during the testing and production runs of your
XML Web service. Caution should be used in choosing exactly what and when to write
to the Event Log however, as a crowded log quickly becomes unmanageable and tracking
individual events becomes nearly impossible.
Debugging Your XML Web Services 349
Summary
In this hour, you learned how to trap and control debugging information from XML Web
services in current development through the use of the debug command. You also learned
how to output this same information to a variety of sources from a fully compiled appli-
cation via the use of the Trace object. Finally, you saw how to track important events in
the life of your application by writing them to the Event Log.
Q&A
Q Why is it advantageous to use the EventLog when you could easily just write
everything to text files?
A Well, the EventLog provides an already built and accepted standard for recording
information about events. Also, the Event Viewer provides a much easier method
for looking through this information then even the best-organized group of text
files can provide.
Q Why would you use listeners with Debug objects if you can see their messages
in the Output window of Visual Studio.NET?
A Although the Output window is a very acceptable means for capturing debug infor-
mation while working on a single function or even a small application, it is less
than perfect when dealing with large-scale development efforts. If you have lots of
data that needs to be checked, possibly by nonprogrammers, it is useful to be able
to write it all to a text file and work from there.
Q Why leave Trace objects in an application that is running in production?
A Trace statements may provide useful information to a production system by pro-
viding data such as logging user activity, tracking errors, and so on. If, when
checking through Trace logged information that output from error handlers, you
determine that your application fails to connect to a data source just as often as it
succeeds, you know that the application needs retooling. 20
Q What purpose do the conditional write methods of Debug and Trace serve
when I can simply use IF Then and other flow control objects?
A The conditional write methods, such as WriteIf, allow you to better control when
messages are written by the debugger without having to resort to the addition of
external flow control code, which in the case of the Debug object would be left
behind to support nothing when the objects were stripped by the compiler during
compilation.
350 Hour 20
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. What file do you need to edit in order to enable Application level tracing of your
XML Web service via Internet Explorer?
A Web.config
2. What types of objects can be passed in and used as the output target of the
TextWriterTraceListener Object?
4. Which property of the EventLog object determines which Event Log is written to?
A Source.
5. What happens to Debug statements that are left in an application at compile time?
A They are ignored by the compiler.
Exercises
Add some code to the Add method of the FourFunctionCalc XML Web Service that
you created in Hour 7 that writes to the Event Log every time a user passes in data
that causes an error to occur. Also, add some code that writes to a text file every time
a user causes an error in the Subtract method.
Change the return value of those functions to type Integer to make crashing
them much easier.
A The following is one way to create the Add method and write a log entry when
code fails. The Log will be titled FourFunctionCalc.
Debugging Your XML Web Services 351
Try
iRet = iNum1 / iNum2
Catch
iRet = 0
Dim sSource As String = “DivideMethod”
Dim sLogName As String = “FourFunctionCalc”
Log.WriteEntry(sMessage, EventLogEntryType.Error)
End Try
Return iRet
End Function
20
HOUR 21
Error Handling in XML
Web Services
In this hour you will learn the basic methods of error handling and how to
put them to use inside of XML Web services. You will learn how to use the
Try . . . Catch . . . Finally block in your code as well as how to throw excep-
tions. Also, you will study the Exception object and see how to inherit it in
order to create your own custom error types.
Throughout this hour we will discuss the following:
• Try . . . Catch . . . Finally
• The Exception class
• Custom errors
• Throwing errors
354 Hour 21
Error Handling
At some point in time even the most well thought out code will generate some sort of
error. It is simply impossible to take every possible occurrence into account, and even if
you could, the time involved in coding to handle these events would be significant, as
would the increased overhead on your applications. With this in mind, a wise developer
includes error-handling code for any functionality that could possibly generate an error.
This error-handling functionality ensures that applications that hit an error do not simply
crash but rather recover and either continue running or exit gracefully.
In an XML Web service, it is often the case that errors encountered in your code will
either be the result of incorrect data submitted by the client application or the failure to
retrieve data from some secondary source, such as a database or text file. In either case, it
is unlikely that your service will be able to return a meaningful result when these errors
occur. It is therefore the job of your error handler to return some useful error information
that either lets the client application know that it has passed bad data or that your service
is unable to process a request due to internal errors. By doing this, you can ensure that
client applications are properly written to handle errors and can react appropriately.
The Try . . . Catch . . . Finally block works in C# in exactly the same way as it does in
Visual Basic. The only real exception, as shown in Listing 21.2, is the inclusion of brack-
ets around the code in each block.
Now, let’s look at a very basic example of the Try and Catch blocks at work. Listing 21.3
shows a new version of the Divided method from the FourFunctionCalc XML Web ser-
vice. We have added a Try block around the actual division operation to handle errors,
such as division by zero, that might occur in our code. For now, we simply change the
return value of such errors to zero. This works as far as keeping our code running and
avoiding any crashes, but it isn’t really mathematically correct, as division by zero (or,
for that matter, division by some decimal that may cause an overflow of the integer type)
does not equal zero. We will make do with this for now.
If you run the above code and pass in zero as the second argument, you can confirm
(place a break statement at line 5 and step through the code) that the error caused in line 6
is caught in line 8 and the value 0 is returned.
Do not put Return statements in your Try . . . Catch . . . Finally blocks. Any
attempts to run code statements that break the Try . . . Catch . . . Finally state-
ment, such as exiting the subroutine, will cause additional errors to be thrown.
continues
Error Handling in XML Web Services 357
The Try . . . Catch . . . Finally block can actually occur multiple times from within any of
the other blocks and can even be nested within previously nested blocks. Also, additional
code can be placed in any of the blocks after the nested blocks, and that code will run
when processing exits the nested Try . . . Catch . . . Finally code.
With this code in place, any errors that generate an Exception object can be trapped and
handled.
The Exception class is the root class for all exceptions thrown in .NET, including those
that you will learn to create for yourself in just a little while. The Exception class offers
properties, shown in Table 21.1, that are useful both to you, as you develop your XML
Web services, and to other developers, as they attempt to consume them.
21
358 Hour 21
The Message property of the Exception class can be set when a new instance of the
exception is created. This message is often used in alert messages when building user
interfaces. It is a good idea to always provide some meaningful message when creating
your own instances of the Exception class to throw to client applications.
As was mentioned above, the Exception class is the root of all of the exception classes
used in .NET. Many more specialized exception classes exist that you may catch and
throw from within your code. Some of the more commonly occurring include:
OverFlowException, IndexOutOfRange, FileNotFoundException, ArgumentException,
SQLException, and SystemException. A listing of all of the possible exceptions and
their usage would be extremely large. Search through the documentation provided with
Visual Studio .NET for more information, or simply try printing the error out to the
screen in your Catch statement like so:
Catch e as Exception
Debug.Write(e.ToString)
Although not the most graceful solution, it is often the best way to see what types of
errors are occurring in your code so that you can deal with them.
Throwing an Exception
Sometimes, either because some criteria in your code was not met or because an excep-
tion was caught but was irresolvable, an exception needs to be raised and either moved
by processing to the Catch statement, or simply passed on to the calling code. This is
done via the Throw statement, which works like this:
Throw myException
Often, when throwing an exception, especially when the error is one that you are gener-
ating due to some conditions in your code, it is useful to create a new exception to throw.
Throw New Exception(“Some other exception occurred")
Error Handling in XML Web Services 359
The string argument provided in the previous code is the optional Message property of
the Exception class.
Another important property of the Exception class is the InnerException property. This
property is used when you catch an error in your code but cannot resolve it and decide to
throw a new exception. This property allows you to pass along the original error as well
as your new exception as follows:
Catch e as Exception
Throw New Exception("Some other exception occurred", e)
The code above will throw an OverFlowException if one of two things happen: iNum is
zero and causes a divide error or any two of the numbers multiply together to produce a
number greater than the integer type can hold. The first Catch statement, in line 10, will
handle this error, in this case by simply resetting the variables to a low-valued integer.
This is a bit frivolous, but it does demonstrate the point.
The next error handler, line 14 of Listing 21.5, handles any other errors that may occur.
This is just practice, as it is usually impossible to predict all of the types of errors that
may be thrown.
To look at the same exception being declared in C#, see Listing 21.7. Notice that C#
includes an inheritance operator (:), shown in line 2. Also, notice that this operator is
used in lieu of the MyBase keyword when implementing the base classes constructors.
Now that you have created a custom exception, it is time to use it in your code. Listing
21.8 shows portions of a method that will look up an artist’s catalog based on his or her
name. Line 12 shows the custom exception that you created being used to catch incidents
where the band name was not found.
continues
362 Hour 21
Summary
In this hour, you saw how to utilize Try blocks in your code in order to handle code that
might throw exceptions. You also learned how to catch these exceptions using the Catch
block. Then you learned how to throw errors from code whenever you needed to. Later,
you examined the Exception call and its methods and learned how to catch the various
types of exceptions that can be thrown in .NET. Finally, you learned to create and throw
custom exceptions that you create by inheriting from the Exception class.
Q&A
Q What purpose does creating custom exceptions serve in creating an XML Web
service?
A Custom exceptions serve several functions, actually. The first thing that they do is
to help you to create much more readable, structured code. By creating custom
errors and trapping them in your code, it becomes much easier to see what is hap-
pening in a given block of code. Secondly, when these errors are raised to client
code, they help the developer in building structured code that effectively deals with
the particulars of your service.
Error Handling in XML Web Services 363
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. Would the following exception-handling structure work?
Try
Try
Catch e as Exception
Catch e as OverFlowException
Finally
Finally
A No, .NET would not allow this and would simply treat the first Catch as a part
of the second Try block. Furthermore, this would produce additional problems by
placing the less restrictive exception handler at the front of the block. 21
If you were attempting to use multiple Try statements, you might write something
like this:
364 Hour 21
Try
Try
Catch e as OverFlowException
Finally
Catch e as Exception
Finally
3. How would you trap an error of type myCustomException if it was thrown in a Try
block?
A Catch e as myCustomException
Exercises
Add error handling to each of the methods in the FourFuncCalc. Remember to throw
errors back to the client application when they cannot be resolved internally.
Error Handling in XML Web Services 365
Try
iRet = iNum1 + iNum2
Catch e As OverFlowException
Throw New OverFlowException("The results of your _
addition caused an overflow error to occur.", e)
Catch
Throw New Exception("An unidentified error has occurred.")
End Try
Return iRet
End Function
Try
iRet = iNum1 - iNum2
Catch e As OverFlowException
Throw New OverFlowException("The results of your _
subtraction caused an overflow error to occur.", e)
Catch
Throw New Exception("An unidentified error has occurred.")
End Try
Return iRet
End Function
Try
iRet = iNum1 * iNum2
Catch e As OverFlowException 21
Throw New OverFlowException("The results of your _
multiplication caused an overflow error to occur.", e)
Catch
Throw New Exception("An unidentified error has occurred.")
366 Hour 21
End Try
Return iRet
End Function
Try
iRet = iNum1 / iNum2
Catch e As OverFlowException
Throw New OverFlowException("The results of your _
division caused an overflow error to occur.", e)
Catch
Throw New Exception("An unidentified error has occurred.")
End Try
Return iRet
End Function
HOUR 22
Publishing an XML Web
Service
Now that you’ve got a small arsenal of XML Web services and technology
under your belt, it’s time to show the world what you can do. Publishing an
XML Web service is the last step in developing one, so we’ll take a look at
how to do so in this hour. Publishing an XML Web service is actually a very
easy process, so you should breeze through this hour.
In this hour, we will discuss the following:
• What you need to do to deploy your XML Web service
• How to set up an Internet Information Server (IIS) application
• How to create .disco files
• How to use web.config to configure your service
368 Hour 22
As long as people can access your server, they can access your XML Web
service—that is, unless you've secured it. See Hour 18, “Security and the
SOAP Toolkit.”
4. Finally, to preserve the configuration of your service, you may also have to copy
the web.config and global.asax files. After all is said and done, your deployed
directory structure should look similar to Figure 22.1.
This loop will keep going ad infinitum, and the ASP.NET page and your Web site will
freeze up until the loop is somehow terminated.
The good news is that IIS allows you to create separate applications for each directory in
your site. This isolates processes so that a crash in one application won’t bring down
your entire site. Let’s take a look at how to set this up.
Go to Start, Settings, Control Panel, Administrative Tools, Internet Services Manager
(see Hour 18 for more information on working with the ISM). Right click Default Web
Site, click properties, and move to the Home Directory tab. You should see Figure 22.2.
Under the Application Settings subheading, you’ll see Application name, Starting point,
and so on. The home directory of your Web site should already be set up as Default
Application. You can click Configuration to modify advanced properties for your applica-
tion, such as how each type of file behaves and whether or not debugging is enabled.
The Execute Permissions drop-down box allows you to specify what kind of files visitors
can execute on your site. Scripts, the default selection, allows visitors to execute .asp
files, executables allows them to execute .exe files, and none excludes both.
370 Hour 22
FIGURE 22.2
The ISM allows you to
create IIS applications.
Finally, the Application Protection property allows you to specify how applications
should behave in relation to each other. By default, they are pooled, which means they
share resources. This and the low setting allow one crash to bring down the entire Web
site, as discussed earlier. The isolated setting prevents this from happening, but can result
in decreased performance for your site.
Let’s create a new IIS application.
1. Navigate to the secure directory (we created this in Hour 18) in the ISM and select
Properties from the right-click menu. The window that pops up is a bit different
from Figure 22.2, but the options are the same (Figure 22.3).
FIGURE 22.3
Creating a new IIS
application.
Publishing an XML Web Service 371
2. In the Directory tab, click the Create button to create a new application, and set
execute permissions and protection settings accordingly (we’ll leave ours at default
for now).
22
3. Hit the OK button, and you’re all set! The icon next to the secure folder in the
ISM should change to reflect that the folder is now an application, as shown in
Figure 22.4.
FIGURE 22.4
Applications show a
different icon from
normal directories.
That’s all there is to it. On line 1, you declare that this file is a discovery document. The
discovery element is defined in the disco namespace, which is why you have the
disco: prefix. The disco namespace is then defined. Line 1 also contains the definition
for the scl (service contract language) namespace, which is used to provide a link to
XML Web services.
Lines 4 and 5 provide the actual links. Line 4 uses the contractRef element to provide a
link to the calculator XML Web service you built earlier. Line 5 uses discoveryRef to
link to another .disco document. Clients can now use this file to find out about your
XML Web service and potentially find other .disco files that contain more XML Web
service links.
Line 5 is an optional reference and can be left off completely. If you do have
need to point to an additional Disco file, be sure to change the URL to a
valid address of an existing Disco file.
However, recall from Hour 4 that a potential client will need to know the exact URL of
the .disco file to use the disco.exe tool—often not very feasible because a user has no
way of knowing what you named your files. Let’s make it easy on the client by providing
a link to the .disco file directly from the home page.
Assuming your home page is default.htm, add the following line of HTML in between
the <HEAD> and </HEAD> tags:
<link type='text/xml' rel='alternate' href='secure/service.disco'/>
A potential client can now use the disco.exe tool to examine your XML Web service
with the command
disco http://yourhostname/
The disco.exe tool will see the link in the home page, and automatically look for the
appropriate .disco file—saving your clients a lot of headaches. They don’t even have to
visit your Web site! The disco.exe tool does everything by itself.
The disco.exe tool is very sensitive about how the .disco files are format-
ted. If it is even slightly malformed, the tool will fail. Make sure your file is
exactly the same as Listing 22.1 (with the exception, of course, of the names
of your files). This means no line breaks inside any of the XML elements.
Publishing an XML Web Service 373
Remember that enabling discovery for your XML Web service is completely optional.
You can keep your service to yourself by simply not creating a .disco file. The choice is
yours.
22
FIGURE 22.5
Registering with
UDDI.org is easy
and free.
There is no cost to register your service with the Registry, but you will need some techni-
cal information about your service, as well as contact information. Once the registration
is processed, you (or your company) will be listed and potential clients can find you via
the www.uddi.org search feature.
Chances are that you are not ready to register your services yet, but when you develop
something that you are particularly proud of, the UDDI Business Registry is a great
place to show it off.
374 Hour 22
The settings stored in web.config are known as runtime settings. They con-
trol the way ASP.NET and XML Web services operate when called. This is dif-
ferent from the settings you store directly inside your service, such as
variables or functions.
Use the web.config file for settings that affect the inner workings of XML
Web services as a whole.
web.config, as you may have guessed by now, is another XML file (XML is very popu-
lar in .NET). Let’s take a look at an example, shown in Listing 22.2.
1: <configuration>
2: <system.web>
3: <webServices>
4: 'settings go here
5: </webServices>
6: </system.web>
7: </configuration>
Publishing an XML Web Service 375
The base element in your web.config file must always be <configuration>. Under that
you have several options. On line 2 you see <system.web>, which controls settings for
Web applications, such as ASP.NET and XML Web services. You could use
22
<system.net> here to configure .NET runtime settings. For now, let’s just concentrate on
using <system.web>.
Note the way words are capitalized in the web.config file—the first one is
not capitalized, whereas all subsequent words are. For example, webServices.
This is known as camel-casing and is required in the web.config file. Don't
forget your capitalization!
Listing 22.3 shows the settings for the most common of these configuration sections and
their values.
continues
Publishing an XML Web Service 377
Most of the configuration settings point to objects in the .NET Framework (the exception
being the <sdlHelpGenerator> on line 72). Often, you’ll have no reason to change these
settings, but they are there if you need to.
If, for example, you wanted to allow clients to use only HTTP protocols to access your
service, simply change lines 55–62 to read as follows:
55: <protocolTypes>
56: <add type="System.Web.Services.
57: Protocols.HttpServerProtocol"/>
58: </protocolTypes>
Summary
In this hour, you’ve learned that deploying XML Web services is very simple. The only
thing you have to do is copy the files of the service to the appropriate directory, and your
service will be available on the Web.
You learned how to create an IIS application and about its benefits—specifically the abil-
ity to isolate your application from others, thereby preventing system-wide crashes. This
can be done through the Internet Services Manager.
.disco files are simple XML documents that provide pointers to your XML Web service
description or other .disco files. Creating a .disco file enables the discovery process,
which allows potential clients to search for your service using the disco.exe tool.
web.config is the XML configuration file for the .NET Framework, allowing you to eas-
ily customize all aspects of your application. Its <webServices> element contains set-
tings that you can alter to affect the way your XML Web service interacts with the .NET
Framework.
After just 22 short hours, you’ve learned quite a bit about XML and XML Web services,
from what a service document is to how to operate asynchronously. Now it’s time to
apply your knowledge and build a fully functional service from scratch. The next two
hours will take you through this process, on both the server side and client side. Start
your preparations!
Q&A
Q Is there a free host that allows me to deploy my XML Web service?
A www.Brinkster.com offers a free Web hosting service that supports ASP.NET and
XML Web services. You can easily register there, test your services out, and allow
others to see your work. Brinkster also offers pay services that provide you with
more features.
Publishing an XML Web Service 379
Q I don’t see any web.config files on my computer. Where are the default
settings stored?
22
A Default settings for your computer are stored in a file called machine.config, usu-
ally located in the c:\Winnt\Microsoft.NET\Framework\version\CONFIG folder.
This file contains all the default settings for ASP.NET, XML Web services, and the
.NET Framework, and it is a great way to dig into the heart of .NET.
Q Can I use web.config to secure my service?
A Absolutely. The <authentication> and <authorization> elements will allow you
to do so. But beware; when you secure your XML Web service in this way, the
SOAP Toolkit (see Hour 18) will not be able to access your service properly. See
the .NET Framework SDK documentation for more information.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Quiz
1. What are the possible types of files that need to be copied to deploy an XML Web
service?
A .asmx, .disco, .wsdl, web.config, global.asax, .dll files
2. What URLs define the disco and scl namespaces in a .disco file?
A http://schemas.xmlsoap.org/disco/scl and
http://schemas.xmlsoap.org/disco/
4. (True or False) The contractRef element is used to point to an XML Web service
description.
A True
380 Hour 22
5. If you wanted to provide a link to a .disco file from your home page, what syntax
would you use?
A
<link type='text/xml' rel='alternate' href='filename.disco'/>
Exercises
1. Fix the following .disco document. (Use disco.exe to test it out and make sure it
works.)
<disco:discovery
xmlns:scl="http://schemas.xmlsoap.com/disco/scl"
xmlns:disco="http://schemas.xmlsoap.com/disco/">
<scl:discoveryRef href="http://localhost/secure/
calculator.asmx?WSDL">
<discoveryRef href="http://localhost/secure/service.disco">
</discovery>
With the database created, open up a new ASP.NET Web service project and call it
QuoteServer. The first thing that you will need to create in your service is the object that
will contain the quotes that you send back to clients. Add a new class module to your
code, Add Class from the Project menu, and call it Quote. This class will hold the quote
and author’s name string as shown below:
Public Class Quote
Public QuoteText As String
Public Name As String
End Class
Building the Quote Server XML Service 387
Now, create a public, globally accessible DataSet to hold the quote information from the
Quote database:
This declaration should go just below the module declaration and outside of any other
routines that you will add.
continues
388 Hour 23
These will allow your service to work with the DataSet object from modGlobalDB.
Run the service now to test your code. Calling the RandomQuote method returns an object
of type Quote, exactly as shown in Figure 23.1.
390 Hour 23
FIGURE 23.1
A quote from the
random quote
generator.
One important thing to note about this new method is the use of the MessageName prop-
erty of the WebMethod attribute. This is done so that we can overload the QuoteList
method, given the MessageName “AllQuotes,” when we create the method to return a
user-selected number of quotes later on.
Building the Quote Server XML Service 391
When you run the new QuoteList method, it will appear as “AllQuotes” in the Internet
Explorer–generated help page. This is shown in Figure 23.2.
FIGURE 23.2
The AllQuotes
method.
23
Running this method will return a DataSet (see Figure 23.3) containing all of the quotes
in the Quotes database.
FIGURE 23.3
Returning all quotes
with AllQuotes
method.
392 Hour 23
1: <WebMethod(MessageName:=”NumberQuotes”, _
2: Description:=”Returns between 1 and 10 randomly selected quotes”)> _
3: Public Function QuoteList(ByVal QuoteNumber As Integer) As DataSet
4: Dim iCount As Integer
5: Dim myDataSet As New DataSet()
6: Dim myTable As New DataTable()
7:
8: If (0 >= QuoteNumber) Or (QuoteNumber > 10) Then
9: Throw New IndexOutOfRangeException( _
10: “QuoteList Requires an Integer Value between 1 and 10”)
continues
Building the Quote Server XML Service 393
11: End If
12:
13: myTable = dsQuoteDataSet.Tables(“Quotes”)
14: iCount = myTable.Rows.Count
15:
16: If iCount <= QuoteNumber Then
17: myDataSet = dsQuoteDataSet.Copy
18: Else 23
19: myDataSet = dsQuoteDataSet.Clone
20:
21: Dim i As Integer
22: Dim j As Integer
23: Dim iNum(QuoteNumber - 1) As Integer
24: Dim myRow As DataRow
25: Dim myTable2 As New DataTable()
26:
27: myTable2 = myDataSet.Tables(“Quotes”)
28:
29: For i = 0 To QuoteNumber - 1
30: AddNum(iCount, i, iNum)
31:
32: myRow = myTable2.NewRow
33:
34: myRow(“Author”) = myTable.Rows(iNum(i))(“Author”)
35: myRow(“Quote”) = myTable.Rows(iNum(i))(“Quote”)
36: myTable2.Rows.Add(myRow)
37: Next
38: End If
39:
40: Return myDataSet
41: End Function
42:
43: Private Sub AddNum(ByVal iCount As Integer, ByVal i As Integer, ByRef
iNum() As Integer)
44: Dim iTemp As Integer
45: Dim j As Integer
46:
47: iTemp = Int(iCount * Rnd())
48:
49: If i = 0 Then
50: iNum(i) = iTemp
51: Else
52: Dim fExists As Boolean
53:
54: For j = 0 To i - 1
55: If iTemp = iNum(j) Then
56: fExists = True
57: Exit For
continues
394 Hour 23
58: End If
59: Next
60:
61: If fExists = False Then
62: iNum(i) = iTemp
63: Else
64: AddNum(iCount, i, iNum)
65: End If
66: End If
67: End Sub
The code for AddNum, lines 43 through 68 of Listing 23.4, provides a workable, though
admittedly inelegant, method for generating an array of random numbers to be used in
the NumberReturn version of QuoteList. My original design required the use of a collec-
tions object and was a bit harder to follow than what is shown.
As it currently stands, AddNum generates a random number and tests it against those num-
bers that have already been called. If the number is unique it is returned, if not, AddNum
makes a recursive call to itself to generate a new number. This method should be added
to the modGlobalDB module.
The method accepts the number of Quotes being requested, iCount, to use as a seed for
its random number generator, an array, iNum, containing any numbers that were previ-
ously created by calls to AddNum, and i, which contains the current number being
requested. Finding the upper bounds of the array would work just as well. A random
number, iTemp, is generated and compared with any previous results stored in iNum. If
the number doesn’t already exist, it is added to iNum and the method exits. If, on the
other hand, the number does exist, a recursive call is made to AddNum to return a new
number. These calls will continue until a new number is generated. This method is highly
inefficient when the number of requested quotes is large.
As with the last QuoteList method, when you run your code, the method will be listed
by its MessageName, NumberQuote. The method will require a number between 1 and 10,
as shown in Figure 23.4.
Building the Quote Server XML Service 395
FIGURE 23.4
Selecting the number
of quotes to return.
23
After selecting an acceptable number of quotes and clicking the “Invoke” button, you
should be greeted with a small DataSet containing pearls of wisdom, such as the ones in
Figure 23.5 by Kierkegaard, Edison, and Clancy.
FIGURE 23.5
Returning five
random quotes.
396 Hour 23
LISTING 23.5 Returns the Same Quote for the Life of the Client Reference
1: <WebMethod(EnableSession:=True, _
2: Description:=”Returns the same quote throughout the life of the object”)> _
3: Public Function SessionQuote() As Quote
4: Dim oQuote As New Quote()
5:
6: If Session(“Quote”) Is Nothing Then
7: oQuote = RandomQuote()
8: Session(“Author”) = oQuote.Name
9: Session(“Quote”) = oQuote.QuoteText
10: Else
11: oQuote.Name = Session(“Author”)
12: oQuote.QuoteText = Session(“Quote”)
13: End If
14:
15: Return oQuote
16: End Function
In order to properly test this function, save and run your project as you normally would,
and then, when the Internet Explorer window is displayed, open a second IE window and
copy the URL from the first. This will give you two separate sessions from which to run
the QuoteServer XML Web service (see Figure 23.6).
Building the Quote Server XML Service 397
FIGURE 23.6
Multiple sessions
of myQuote.
23
From each of the two windows, press the “Invoke button” several times and verify that
each window continually returns the exact quote as shown in Figure 23.7. There is a
slight chance, dependent on the number of quotes that you have entered in the Quote
database, that both of your sessions are returning the same quote. If this happens, open a
new instance of IE and try again.
FIGURE 23.7
Returning quotes
for multiple myQuote
sessions.
398 Hour 23
1: <WebMethod(CacheDuration:=60, _
2: Description:=”Returns the Daily Quote. Quote changes at 12AM EST.”)> _
3: Public Function DailyQuote() As Quote
4:
5: Dim myQuote As New Quote()
6:
7: If Application(“Quote”) Is Nothing Then
8: myQuote = GetQuote()
9: Application(“Author”) = myQuote.Name
10: Application(“Quote”) = myQuote.QuoteText
11: Application(“Date”) = Format(Today, “mm/dd/yy”)
12: Else
continues
Building the Quote Server XML Service 399
The GetQuote function, not shown, simply queries the database for the earliest date, or
the first quote without a date if such exists, and returns it. The method then sets the
quote’s date to the current date.
Run the service and click the “Invoke” button of the DailyQuote method and you will
receive a quote, such as this insightful remark (Figure 23.8) made by IBM’s Thomas Watson.
FIGURE 23.8
Returning the quote of
the day for Monday.
400 Hour 23
Now, change the system date on your computer, right click the time in the lower
right hand side of your computer, and click the “Invoke” button a second time.
You should now see a new quote, such as the one from Frank Lloyd Wright shown in
Figure 23.9.
FIGURE 23.9
Returning the quote of
the day for Tuesday.
Now that your service’s methods are complete, it is time to complete the service
itself. Add the following XML Web service attribute to the declaration of your ser-
vice. This will set its namespace and description in order to better describe and define
your service.
<WebService(NameSpace:=”http:\\www.Superior-sdc.com”, _
Description:=”This XML Web service provides features such as a _
quote of the day, random quotes, and quote lists.”)> _
Public Class myQuote
Inherits System.Web.Services.WebService
You can view the results of these changes by running your service or by looking at
Figure 23.10.
Building the Quote Server XML Service 401
FIGURE 23.10
The description of
the myQuotes XML
Web service.
23
This method reads the Music.xml file into a FileStream object, myfStream, in line 4. The
file stream is then used to read the document into an XmlTextReader, myXMLReader, that
is in turn read into a DataSet object in line 14.
The second XML document, Sports.xml, is read directly into an XmlDocument object,
myDoc, in line 15 and then transformed into a more useful format using the Sports.xsl
file. The file is then read into a second DataSet object in line 21.
Using the Copy method of the DataSet’s DataTable object, the two tables are added
directly to dsPopQuoteDataSet. Several other methods for adding these XML data
sources may have also been appropriate, including concatenating the two documents and
transforming them into the XML representation of a two-table DataSet.
For this function to actually accomplish its goal, a call to it needs to be added to the
Global.ASAX. Place the call to LoadXML directly beneath the call to LoadData in the New
method of the Global.ASAX.
Building the Quote Server XML Service 403
A portion of the Music.xml document can be viewed in Listing 23.8. The ellipses in
line 13 represent the section of additional “Quote” nodes that were removed.
Listing 23.9 shows a segment of the Sports.xml document. As in the previous docu-
ment, line 11 should be replaced with additional “Quote” nodes. It should also be noted
that the format of Sports.xml is slightly different from that of Music.xml and will need
to be altered or “transformed” in order to create a recordset that is similar to the one cre-
ated by reading Music.xml into the dsPopQuotesDataSet object.
continues
404 Hour 23
Finally, the Sports.Xsl file shown in Listing 23.10 performs the needed transform on
the Sports.xml file.
The actual QuoteList method is actually extremely simple. The method accepts a
QuoteType enumeration, Style, and uses it to determine which of the tables from the
dsPopQuoteDataSet DataSet should be returned. The table is then copied (line 7); added
to the return DataSet, myDataSet; and returned. This is shown in Listing 23.11. 23
LISTING 23.11 Returning All the Quotes from either the Music or Sports Category
1: <WebMethod(MessageName:=”AllQuotes”, _
2: Description:=”Returns the full list of quotes”)> _
3: Public Function QuoteList(ByVal Style As QuoteType) As DataSet
4: Dim myDataSet As New DataSet()
5: Dim myTable As New DataTable()
6:
7: myTable = dsPopQuoteDataSet.Tables(Style).Copy
8: myDataSet.Tables.Add(myTable)
9:
10: Return myDataSet
11: End Function
Run the service, shown in Figure 23.11, carefully type in either Music or Sports, and
click the “Invoke” method.
FIGURE 23.11
Selecting a quote
category.
406 Hour 23
Remember that the enumerator is case sensitive and will not treat MUSIC
the same as Music.
The DataSet returns the entire contents of one of the quote categories, as shown in
Figure 23.12.
FIGURE 23.12
Returning all
music quotes.
LISTING 23.12 Returning a Random Quote from the Music or Sports Category
1: <WebMethod(Description:=”Provides a new random _
2: quote everytime that it is called.”)> _
3: Public Function RandomQuote(ByVal Style As QuoteType) As Quote
4: Dim oQuote As New Quote()
5: Dim iCount As Integer
6: Dim i As Integer
7: Dim myTable As New DataTable()
8: 23
9: myTable = dsPopQuoteDataSet.Tables(Style)
10: iCount = myTable.Rows.Count
11: i = Int(iCount * Rnd())
12:
13: oQuote.Name = myTable.Rows(i)(“Author”)
14: oQuote.QuoteText = myTable.Rows(i)(“Text”)
15: Return oQuote
16:
17: End Function
As always, save and run the service. Now, when you type in Sports and invoke the
RandomQuote method of PopQuote, you stand a very good chance of seeing one of Yogi
Berra’s many interesting quotes, such as the one in Figure 23.13.
FIGURE 23.13
A random sports quote.
408 Hour 23
Summary
In this hour, you created an entire XML Web service–based suite of quote-related tools.
Throughout this hour, you saw how to integrate all of the techniques that you learned
over the course of the last 22 hours into a fully functioning XML Web service that could
be exposed to real-world users. This service, although more frivolous than many, still
provides functionality that many developers may find valuable.
Q&A
Q Why not place the functionality of the PopQuote service into the same XML
Web service as myQuote?
A The functionality appears to be geared to a different user community and, although
related enough in functionality to warrant being placed in the same project, the
functionality offered by PopQuote is really quite different.
Q Is the QuoteServer project technically two separate XML Web services?
A Technically it is. To the developers using the service, a separate Web Reference
must be created for each XML Web service created in your project. They are related
in several key ways, however. Both share the same application space, which is to
say, they share the same Application level variables, resources, and so on. The sec-
ond major connection lies in the Disco file that is generated for the service. A Disco
file will be created by Visual Studio .NET that includes all of the services in a given
project.
Q Why, if the services are sharing the same resources, aren’t the XML docu-
ments read into the same DataSet object as the relation data was?
A If additional tables were added to the dsQuoteDataSet, changes would have had to
have been made to the original service to ensure that the additional tables were not
delivered along with operations where a full DataSet was used as the return object.
This would not have been a bad thing necessarily, but in a situation where the ser-
vice was busy it could cause additional performance hits.
Workshop
The Workshop is designed to help you review what you’ve learned in this hour and to
point you ahead to the material that will be covered in future hours.
Building the Quote Server XML Service 409
Quiz
1. How is an additional XML Web service added to an XML Web service project?
A Add New Item on the Project Menu.
2. (True or False) Public functions in a module can be used by all services in a pro-
ject.
A True.
3. (True or False) Methods in an XML Web service can call methods from the same
23
service.
A True.
4. What object needs to be used in order to handle XML data whose format prevents
them from being read into a DataSet object?
A XmlTransform
5. (True or False) It is possible to have methods with the same name in different ser-
vices within the same project. Note: overloading is not being used.
A True.
Exercises
Add two additional features to PopQuotes XML Web service. One should return between
one and ten randomly selected quotes from either the music or sports world. The second
should return a single quote of user choice of sports or music, for the lifetime of the
client application’s session.
A The following code adds two new functions to the PopQuotes XML Web service.
The first, NumberQuotes, returns between 1 and 10 quotes from either the music or sports
world. The second, SessionQuote, returns the exact same quote for the life of the ses-
sion. This quote can be from either the sports or music world.
<WebMethod(MessageName:=”NumberQuotes”, _
Description:=”Returns between 1 and 10 randomly selected quotes”)> _
Public Function QuoteList(ByVal QuoteNumber As Integer, _
ByVal Style As QuoteType) As DataSet
Dim iCount As Integer
Dim myDataSet As New DataSet()
Dim myTable As New DataTable()
myTable = dsPopQuoteDataSet.Tables(Style)
410 Hour 23
iCount = myTable.Rows.Count
Dim i As Integer
Dim j As Integer
Dim iNum(QuoteNumber - 1) As Integer
Dim myRow As DataRow
Dim myTable2 As New DataTable()
myTable2 = myDataSet.Tables(Style)
For i = 0 To QuoteNumber - 1
AddNum(iCount, i, iNum)
myRow = myTable2.NewRow
myRow(“Author”) = myTable.Rows(iNum(i))(“Author”)
myRow(“Text”) = myTable.Rows(iNum(i))(“Text”)
myTable2.Rows.Add(myRow)
Next
End If
Return myDataSet
End Function
<WebMethod(EnableSession:=True, _
Description:=”Returns the same quote throughout the life of the object”)> _
Public Function SessionQuote(ByVal Style As QuoteType) As Quote
Dim oQuote As New Quote()
Return oQuote
End Function
HOUR 24
Quote Server Clients
In this hour, you will take a look at a variety of client applications that may
make use of the Quote Server XML Web service. During this hour, you will
see desktop programs as well as ASP applications all making use of the vari-
ous methods provided by the QuoteServer application. By the end of this
hour, you should be fully motivated to go out and build your own services
and the clients to consume them.
In this hour, we will discuss the following:
• ASP clients
• Desktop clients
• Visual Basic clients
• C# clients
412 Hour 24
FIGURE 24.1
Working with HTML in
the Visual Studio .NET
Designer.
Quote Server Clients 413
continues
414 Hour 24
If you wished to keep this quote visible at the bottom of the browser at all
times, frames could have been used within the HTML to break the window
up into two distinct areas with the quote visible in the bottom pane.
Quote Server Clients 415
When you run this project, Internet Explorer should open up and greet you with a quote
similar to the one at the bottom of the page shown in Figure 24.2.
FIGURE 24.2
Returning
SessionQuotes at the
bottom of an ASP page.
24
Following the link to one of the other two pages should provide the same quote; remem-
ber that you are calling SessionQuote in the code at the bottom of the page. This is
shown in Figure 24.3.
FIGURE 24.3
Confirming
SessionQuotes at the
bottom of another ASP
page.
416 Hour 24
If you don’t want to wire the application together in this way, you can also just go to the
Solutions Explorer and make the QuoteList.aspx the project’s startup object.
Enter the designer for QuoteList.aspx and drag a PlaceHolder control from the
Toolbox onto the designer form. This will be used to allow your code a place to dynami-
cally build a Table. Alternately, you could simply create this entire page through ASP
code, but since other content may be added to the HTML section, it is probably a better
idea to use the PlaceHolder.
Now, click on the View Code button for QuoteList.aspx and enter Listing 24.3 into the
Page_Load event. The call to the QuoteList method returns a DataSet object, line 8,
which is then iterated through. Each iteration is then stored in HTMLTableCell object to
place it into the various rows of a table, lines 11 through 38, and then processing moves
on to the next record. Finally, line 40 adds the new HtmlTable object to the PlaceHolder
object for display on your page.
continues
Quote Server Clients 417
Running the application and navigating to the QuoteList page should give you the entire
contents of the QuoteList’s database, as shown in Figure 24.4.
FIGURE 24.4
Returning a
list of quotes.
418 Hour 24
TextBox Text
TextBox Text
Button Name Button1
Text Quote
Text Okay
Text Cancel
Text &File
Text &Help
Text &Inspiration
When you are done with this, your form should look like the one shown in Figure 24.5.
At this point, add a Web reference to the myQuote XML Web service and then add the
code in Listing 24.4 to your form. This code contains the GetQuote function, which actu-
ally calls the service, and the button click event that triggers the call. Line 6 of the func-
tion calls the RandomQuote method of the myQuote service and accepts the quote return.
This is then displayed to the user in a message box, line 8.
Quote Server Clients 419
FIGURE 24.5
Form1.
24
Save and run your application to confirm that a quote is returned, as in Figure 24.6.
FIGURE 24.6
Random quotes in your
Windows Desktop
Applications.
Try clicking the button a few more times to get a different quote.
420 Hour 24
FIGURE 24.7
A new quote.
Text DailyQuote
Your form should now look like the form shown in Figure 24.8.
FIGURE 24.8
frmDailyQuotes.
Quote Server Clients 421
Add the code in Listing 24.5 to the Load event of frmDailyQuote. This code calls the
DailyQuote method and loads the text into the form’s labels.
Finally, in order to actually call this frmDailyQuote from your original form, go back
and add the following code to Form1's MenuItem3 click event. This code simply displays
frmDailyQuote whenever the user clicks on the Inspiration menu item in the Help
menu of Form1.
Run the application and click the Inspiration button. Your day should be lifted by a pearl
of wisdom, such as the Frank Lloyd Wright quote shown in Figure 24.9.
Even though this is a rather simple example and not a major boon to the average business
application, it never-the-less shows how XML Web services can be integrated into a
desktop application.
422 Hour 24
FIGURE 24.9
Frank Lloyd Wright’s
Quote of the Day.
The new client will contain only one method, Greetings. Add Greetings, Listing 24.7,
to the service. The method is very straightforward. Line 10 calls the myQuote service and
retrieves a Quote object. The Quote object's Name and QuoteText properties are then set
to build the return string, sQuote, as shown in Line 12.
When you run this service, as shown in Figure 24.10, you are provided with a com-
pletely repackaged version of the RandomQuote method.
FIGURE 24.10
The repackaged
Random Quote. 24
Summary
In this hour, you saw a cross section of different application types that you can use to
take advantage of a single XML Web service. Whether you are writing your applications
in Visual Basic, C#, or some other language, and whether these apps are desktop, client
server, ASP, or even other services themselves, the XML Web service architecture pro-
vides you with a very flexible development tool. Hopefully, your interest is sparked, as
this book provides only the starting point to what can be accomplished with XML Web
services and Visual Studio .NET.
Q&A
Q What is the benefit of building an XML Web service using other XML Web
services?
A By leveraging the services of one XML Web service within a new XML Web ser-
vice, you gain all of the benefits of object-oriented design. You encapsulate it func-
tionally, reuse it in multiple applications, and, in the case of specialized
functionality, you leverage the skills of other developers who may know more
about a particular area than you do.
424 Hour 24
Workshop
The Workshop is designed to help you review what you’ve learned in this hour.
Quiz
1. What is the limit to how many levels of XML Web services consuming other XML
Web services you can have?
A There is no limit, although speed may suffer greatly from all of the network
traffic involved.
2. Can XML Web services be consumed by clients other than those written in
ASP.NET?
A Yes, there is almost no limit to the number of architectures that can leverage
XML Web services.
3. Is there a limit to the number of XML Web services that a single client application
can call?
A No, there is no restriction on the number of XML Web services that can be
called from a single client.
Exercises
Build client applications that take advantage of some of the other methods of the Quote
Server XML Web service.
A. The following calls the PopQuotes method and prints out a list of music-related
quotes. For variety’s sake, I placed the code directly into the ASP page. Only do this if
you are sure that no one else will be altering the HTML in your pages and you yourself
aren’t planning any major reworking either.
<%@ import Namespace="System.Data" %>
<%@ Page Language="vb" AutoEventWireup="false"
Quote Server Clients 425
Codebehind="WebForm2.aspx.vb" Inherits="QuoteLister.WebForm2"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
<meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0">
<meta name="CODE_LANGUAGE" content="Visual Basic 7.0">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
</head>
<body MS_POSITIONING="GridLayout">
<Form name="Quotes" action="Webform2.aspx" method="post">
<input name="Number" type="text"> <input type="submit">
</Form>
<Table border="0">
<% 24
If isNumeric(Request.Form("Number"))
Dim oQuotes As New localhost.PopQuotes()
Dim myDataSet As New DataSet()
Dim myRow As DataRow
Dim iNum As Integer
Dim uType As localhost.QuoteType
iNum = Request.Form("Number")
myDataSet = oQuotes.QuoteList(iNum, localhost.QuoteType.Music)