深蓝海域KMPRO

Generating a Strongly-Typed DataSet from a Web Service

2002-09-12 13:29

Generating a Strongly-Typed DataSet from a Web Service 


 
By: Barton Friedland

Level: Advanced

Posted Date: 3/13/2001

Tested with ASP.NET Beta 1 (v1.0.2204)

 Click for Printable Version

 Member Rating: 4.00 (Rated by 3 members)

Rate This Item 

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:

</xsd:element>

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:

</xsd:element>

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.

相关推荐