Introduction
This article reviews how to design and build a .NET Web service that consumes
another Web service whose result is not already packaged in an ADO.NET object.
I have seen a number of articles having to do with building the UI using ASP.NET
Web Forms and a number of articles on using ADO.NET to package results from
databases or remote Web services which deliver their results as ADO.NET objects.
However, I have not yet run across any examples that explain what to do when
the remote Web service consumed by the local Web service does not deliver
its result already packaged in an ADO.NET object. This seems to me to be an
operation every .NET developer should know about.
As it happens, Microsoft has a "Best
Bets" Search Web service that does not return a DataSet,
but instead returns a type System.Object.
And that is very exciting, because Object
is at the center of the .NET universe and that means we can employ a variety
of different approaches to shuttle the result set into a DataSet.
This article will not only lay out the steps involved, but it will also provide
an abundance of background information that will support any developer new to
.NET in developing a richer understanding of how .NET works.
For that reason, this article is being split across a series of multiple parts,
so that each article will cover the particular aspect of the design and implementation
of this Web service application in sufficient depth as to provide a clear basis
for understanding each area involved.
This article is Part I of a series. In this article, we will discuss the overall
design of a Web service application and how to create a strongly typed DataSet
from the information the consumed Web service provides - without writing
code.
Designing the Application
Before I decided to write this article, I was creating a sample application
to help me better understand the relationships between the various .NET object
models such as ASP.NET, ADO.NET and the whole concept of Web services. I chose
as my exercise to design a simple query application that calls upon Microsofts
"Best Bets" Search Web service.
First, I reviewed of Microsoft's service with a view to the way a user might
make use of this service. I then sat with a glass of wine to ponder on how I
might design the application to standards such that when I meet Anders
Hejlsberg at some future party, he will warmly congratulate me on
my complete grasp of .NET. I then found myself inspired to the following design:

In exploring the distinct functions within the application and mapping these
to the .NET framework, everything fell very neatly across easily defined boundaries.
I have found that the design of .NET is itself helpful in defining the application
components, which, in turn, highlight the work that needs to be accomplished
within each component.
This design defines three distinct components as the application:
- The client Web Form;
- The local Web service;
- Microsofts (remote) Web service;
The end-to-end component approach .NET supports is a very different way of
designing applications than we have had access to up until this point. Yes,
the basic pieces have been there for some time, but .NET brings elements together
in one place that have previously only been available in disparate systems,
hence its inherent ability to bring disparate systems together!
I liken the process .NET is bringing upon us to the very memorable Faberg
Organics shampoo commercial where the woman says she "...told a friend about
it and she told her friend and so on, and so on, and so on", and while
she is saying this, the single frame on the TV screen is dividing and duplicating
until I there are 64 frames of the same woman on the one screen.
Similarly, a Web service consumes another Web service, which, in turn, may
consume other Web services in an almost infinite manner. This fact has a very
broad reaching implication that is forming a powerful basis for fundamentally
changing the way we receive benefits from computer systems.
The Web Service
Here then, is a top-level diagram of the key objects & actions which can
be employed within .NET to deliver a packaged ADO.NET DataSet
to the consumer of this Web service (Note: the diagrams in this article read
right to left):

This article will focus on step one - creating the strongly typed DataSet.
Part II will present several methods to get the result set from the returned
object into the DataSet while Part III will
focus on bringing the data to the user interface in ASP.NET.
Strongly Typed DataSets
Think of a strongly typed DataSet as a database
object defined by a projects object model components themselves rather than
by the developer. While the developer makes the decision to create and use such
an object, the developer does not write the code for a strongly typed DataSet,
and allows .NET to create it instead.
By allowing this, the developer benefits from an "inner knowing"
on the part of the .NET framework that binds this object to the project much
more deeply than if the developer were to construct the DataSet
in code by hand using more traditional methods.
The DataSet can contain many tables and support
the relationships and constraints that one will normally find in a database.
The DataSet is at the heart of the disconnected
data approach ADO.NET employs - it acts as the local copy of the database -
with complete functionality.
In pre-.NET days, one would manually construct the columns of a table for a
DataSet in code, defining the field names and
datatypes for each, along with the properties of those columns.
Coding the DataSet in this manner creates the
table at run time, but does not inherently make the members of the DataSet
available to the project as a whole at design time as well. This is an implementation
of one of .NETs key goals - providing a rich development environment at both
design and run times.
Strongly typed DataSets are new for .NET and
provide a number of benefits. According to Microsoft
documentation:
"...a typed DataSet is a DataSet sub-classed from the base DataSet
class, and that has a schema file (an .XSD file) that describes the structures
of the tables that the DataSet contains.
The schema contains the table and column names, the data types of the
information in the columns, and information about constraints on the data.
An untyped DataSet, in contrast, has no corresponding schema.
You can use either type of DataSet in your applications. However, typed
DataSets make programming with the DataSet easier and less error-prone.
The typed DataSet generates an object model in which its tables
and columns become first-class objects in the object model. For
example, if you are working with a typed DataSet, you can reference a column
using syntax such as the following:
|
'Visual Basic
' This accesses the title_id column in the first row of the titles table
s = dsPubs1.titles(0).title_id
//C#
// This accesses the title_id column in the first row of the titles
table
s = dsPubs1.titles[0].title_id;
|
In contrast, if you are working with an untyped DataSet, the equivalent
syntax is:
|
'Visual Basic
s = dsPubs1.Tables("titles")(0).Columns("title_id")
//C#
s = dsPubs1.Tables["titles"][0].Columns["title_id"];
|
In addition to being easier to work with, the syntax for the typed DataSet
provides type checking, greatly reducing the possibility of errors in assigning
values to DataSet members."
This has several implications. A strongly typed DataSet:
- is a first-class player in the .NET object model and its members are fully
exposed;
- can be used more fully by VS.NETs visual tools, such as the component tray
and the DataGrid;
- can be generated from either a specific
ADOConnection, which will generate a strongly
typed DataSet and an XSD file in the process,
or can be generated from an XSD file, which will generate the strongly typed
DataSet;
This last fact provides a key insight into the design of the .NET System.Data
and System.XML classes. Heres why:
Microsoft
documentation on the DataSet object
states, "the DataSet object is central to ADO.NET."
Remembering that ADO is designed to provide universal data access, think about
where the DataSet sits relative to various data
sources. It is the central container object for all database-type data and must
therefore be accessible from all possible data sources.
From this, it can be speculated and subsequently proven that an XSD provides
both the representation of and the mechanism for creating the strongly typed
DataSet. In the same way that Web Form and Web
service files have code files attached to them, the code that creates the strongly
typed DataSet is generated by .NET and attached
to an XSD file.
When one Web service consumes another Web service, .NET uses the information
the consumed Web service provides as part of the consumption process to reconstitute
a fully working copy of its exposed object model. This is bound to the namespace
of the consumer Web service, and thus, becomes a "first-class" player.
Further, files are also copied to the Web References
folder, which provide the needed information to create a strongly
typed DataSet without writing any additional
code.
The relationship between a strongly typed DataSet, XSD
and WSDL
I am working with VS.NET Beta 1 at this time and, as a beta, it is not fully
functional. In addition, there are many standards upon which .NET relies which
are not fully agreed upon out there in the world of consortiums and standards
bodies. One of these is WSDL (in VS.NET
Beta 1 these are named .SDL) for Web Service Description
Language.
This information is used to provide a consumer of a Web service with the necessary
information on how to make use that service. It is in an XML format document.
The WSDL is actually several documents in one file - embedded within it is a
document whose standard is also not fully agreed upon, the XSD.
The XSD describes the schema the services results are returned in and this is
the document from which a strongly typed DataSet
can be generated.
It is not the easiest thing to work with something whose standards are not
fully defined and are subject to change, not to mention doing so within the
environment of a beta product. So, a bit of manual text editing is required
at this time to get the job done, but this is a good thing! Exploring the underpinnings
always provides an excellent perspective from which to view where a technology
is leading.
In the full release of VS.NET, I am sure that this process will become completely
automated, but as a pioneer, you have the benefit of understanding the system
at a more manual level.
Here is a diagram of the steps I took to create an XSD file from the supplied
WSDL:

By creating the XSD file, .NET takes care of the rest and generates the strongly
typed DataSet for use throughout the application.
The balance of this article is the step-by-step tutorial to set up the Web
service and create the strongly typed DataSet.
To Create a Web Service Project
- On the File menu, point to New, and then click Project.
- In the New Project dialog box, select either the Visual Basic
Projects or Visual C# Projects folder.
- Click the Web Service icon.
- Change the name of the project to SearchWebServiceArticle.
- If necessary, enter the address of a Web server on which you can develop
the Web Service
Note This server is referred to as your
development server. By default, the development server is the same machine
as where Visual Studio is installed. The project is developed and built on
the development server.
- Click OK to create the project.
Visual Studio automatically creates the necessary files and includes the needed
references to support a Web Service.
Consuming the upstream Web service
1. In the Solution Explorer, right click on the project icon and choose
"Add Web Reference...".

2. In the Add Web Reference dialog, type the following Web service address:
http://beta.search.microsoft.com/search/mscomsearchservice.asmx
3. When the page loads, click Add Reference.
Visual Studio then performs a discovery
of the service, which creates the following directory in your Solution Explorer:

The service is now a referenced object within the project and its classes
and members are available. Have a look in the Class View:

4. The next small piece in my code is just a personal preference. On consuming
the Web Reference, the project created a reference to the object with a default
naming structure of:
com.Microsoft.search.beta
This is a little longwinded for my taste, so I right-clicked on the name of
the web reference in the Solution Explorer and chose Rename,
renaming the reference to MS_Search. If you
refer back to the Class View after this, it should look like this:

This is much easier to reference as:
MS_Search
To Create An XSD File
In the release version of VS.NET, this step should happen with completely visual
tools and no need for manual editing. As a pioneer, you are one of the lucky
few who get to learn about what goes on under the covers to produce an XSD file
from the WSDL the consumed Web service provides.
1. Right click on the project in the solution explorer and choose "Add
New Item..." from the menu:

Select a DataSet file and name it
dsBBI.xsd.

Visual Studio will create and open the XSD document.
2. Click the XML tab at the bottom left of the window:

3. Position the cursor on line 8:

Notice that line 6 of the file defines the file as an XSD document. Since
a DataSet icon was clicked, .NET also adds
line 7 of the XML refers to that provides specific support for a DataSet.
4. Now double-click the File MSComSearchService.sdl
in the Solution Explorer. The file will open in a text editor.
Look for this line, at line #109 in my editor:
| <xsd:schema targetNamespace=http://tempuri.org/attributeFormDefault="qualified"
elementFormDefault="qualified"> |
This is the beginning of the XSD file. Select from here to the next to
the last line (224 in my editor) which reads:
Copy this text to the clipboard.
5. Close the WSDL document.
6. Paste the contents of the clipboard onto line 8 of dsBBI.xsd.
7. Save the file. It should look like this:

Now there are some important editing changes required to make this all
work. Edit with care!
8. Copy part of line 7 as pictured below:

9. Paste this at the beginning of line 5 and arrange the items so they look
like this:

10. Delete line 9 and 10.
11. Save the file.
12. Click the Schema tab at the bottom of the window:

13. The XML parser will now process the XML and in about 30 seconds, you
should see something like this on your screen:

The XSD file that represents the schema for the object returned by the remote
Web service has now been fully parsed by the built in XML-parser and displayed
a visual tool that Microsoft are calling the XML
Designer (see halfway down the page in this link).
What I discovered after this file was parsed is that there is much more information
returned in the results than the consuming Web service requires. Have a look
around the visual representation - it is very interesting.
About Attributes and Elements in an XSD Schema
The last step before we generate the strongly-type DataSet
is to isolate the schema that represents the data this Web service will package
- the BestBetItem.
In the XML designer window, note that each icon representing a table of the
schema has a small letter located at the top left corner of the rectangle. Here
are some examples:

From the Microsoft documentation:
"XML elements are divided into two categories: simple and complex.
Complex elements contain subelements and/or carry attributes, while simple
elements contain only text (strings, dates, etc.). A complex element can be
mapped to relational tables, with the simple elements defining the columns
of the table. Simple elements can also be used to add content to a complex
type."
The various letters used in an XSD XML file stand for the following:
| A |
Attribute |
| AG |
Attribute Group |
| CT |
Complex Type |
| E |
Element |
| G |
Group |
| ST |
Simple
Type
|
See the Microsoft
XML Schema (XSD) Reference for a complete description of what each
is used for.
In this schema, only the Complex Type and the Element are used.
Using the XML Designer to Edit the XSD File
What the Web service is going to package are contained in the part of the schema
that describes a BestBetsItem. So, the next step in the process is to
remove the items that are not required. That process is made infinitely easier
thanks to the XML Designer - just click on the items that are to be removed
and press the delete key - the XML Designer will edit the XML behind the scenes.
No direct XML coding required!
1. Using the mouse, select every item and delete it except the one below:

2. Save the file. Switch over to the XML view. The file should look like
this:

Alternatively, you could go through the XML file and delete every line
except what is here - the choice is yours - visual tool or text tool - whatever
you are most comfortable with.
Replace line 3 with the following two lines:
|
<xsd:element name="BestBetItem">
<xsd:complexType content="elementOnly">
|
4. Position the cursor are the end of line 12 which reads </xsd:complexType>
and paste the following on the next line:
5. One more piece - the following lines of code need to be pasted after line
13:
|
<xsd:element name="dsBBI" msdata:IsDataSet="True">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element ref="BestBetItem"/>
</xsd:choice>
</xsd:complexType>
</xsd:element>
|
This code is my gift to you - I hacked it from the code that is auto generated
from a strongly typed DataSet when the data
source is an SQL database. If you click back on the schema, it should look like
this:

Now the element dsBBI is a parent and refers
to the BestBetItem.
Go to the schema menu and choose Generate DataSet twice:

This is a beta version of VS.NET, so it is necessary to click once to clear
the existing (empty) DataSet and a second time
to generate it as per the modifications just made to the file.
Go to the Class Viewer, expand the hierarchy and you should see the following:

The DataSet which refers to the remote Web
service result object this Web service will be packaging is now a member of
the projects object model.
Conclusions
In this article, we have reviewed the steps to create a strongly typed DataSet
in VS.NET Beta 1. Undoubtedly this process will become easier in the release
version, however, it is important to see and understand the relationship between
ADO.NET and XML and this article provides some key insights into that very important
relationship.
In many ways, this article provides a very broad view of what .NET is all about.
While we are consuming a Microsoft Web service, this does not inherently make
the service .NET. The object that the service returns is generic - it could
be from any platform.
We have just spent some considerable time in getting something that is not
inherently .NET (an object returned by a Web service) to link to the .NET framework.
Building these links is what .NET is about - building bridges to other systems
and then leveraging the elegance of the .NET framework to process results.
Now the fun can really begin - using our consumed object to build a .NET application!
Coming in Part II
In the next part of this article we look closely at the various methods we
take the result set received from the upstream Web service and pass these values
to the strongly typed DataSet.