asp:cover story
LANGUAGES: VB
TECHNOLOGIES: Web Services | Visual Studio .NET | SOAP | WSDL | UDDI
Web Service Essentials
Create and consume Web Services with Visual Studio .NET.
By Peter Vogel
For all the excitement about Web Services, the definition is surprisingly simple: A Web Service is any program that can accept a Simple Object Access Protocol (SOAP) request over the Web. This gives developers tremendous freedom to use whatever tool they prefer to create Web Services. With ASP.NET and Visual Studio .NET, Microsoft has made creating a Web Service ridiculously easy. And as you'll see from firsthand experience in this article, accessing Web Services from an ASP.NET application is not only easy but also flexible.
To create an ASP.NET Web Service using Visual Studio .NET, start a new ASP.NET Web Service project in whatever language you want to use. (Figure 1 shows the dialog for creating an ASP.NET Web Service project in Visual Basic .NET.) When you start the project, you must supply a name for it and a Web site where the service will live initially. (Later, you'll want to move the service to your production server.) In your new project, you'll find a Service1.asmx file. The asmx file is the class module where you'll place the code for your Web Service. The first thing to do is give this file a more meaningful name.
Figure 1. The New Project dialog of Visual
Studio .NET defines several different project types, including ASP.NET Web
Services. You can create Web Service projects in either VB or C#, although this
example uses VB.
Now you can begin to add code to the asmx file to create the methods that make up your service. The default asmx file contains some "Hello World" code you can delete or modify. At the top of the file, you'll find the Class declaration (I've changed the name to MathServices from the default name, Service1):
Public Class MathServices
In the world of .NET, you use properties and attributes to modify the compiled output. You should use the WebService attribute to add the Description and Namespace properties to your Class declaration:
Namespace:="http://phvis.com/MathServices/", _ Description:="Mathematical
Functionality")> _ Public Class
MathServices The Description
property's value will turn up in the wsdl file this project generates; it
provides documentation for developers using your Web Service. Understanding the
Namespace property requires looking under the hood of SOAP. Any
client that accesses your service will need to create a SOAP message containing
XML tags that refer to methods in your asmx file. If you give your methods
meaningful names, such as CreateCustomer, it's a safe bet that your
method names probably will duplicate method names for some other service
somewhere in the world. In order to prevent name collisions, you assign your
Web Service a namespace, using the Namespace property on the WebService
attribute. (By default, your Web Service is assigned a temporary namespace
by ASP.NET: tempuri.org, for temporary uri.) In the
XML world, a namespace is a much simpler thing than it is in .NET. An XML
namespace is simply an arbitrary set of characters associated with a tag name
to make the tag name unique. The key characteristic of your namespace should be
that no one else should ever want to use it. A good candidate for your
namespace is the URL for your Web Service because it's unlikely that anyone
else would ever use that URL as his or her namespace. Now you
can start writing the methods that make up your service. These methods are
standard Visual Basic code (well, Visual Basic .NET code). Here's a method that
adds 1 to whatever number is passed to it: Public Function
AddOne(ByVal inValue As Integer) As Integer Return inValue + 1 End Function As with the
Class declaration, you can add a Description property to your Function
declarations to document your methods. Now you've created a Web Service that
clients can access. As part
of creating your service, Visual Studio .NET generates a discovery file (with
the extension vsdisco in a Visual Basic project, and disco in a C# project). A
Web Service client can use the information in the discovery file to retrieve
the Web Services Description Language (WSDL) description of your service (see
the sidebar, "Web Service
Technologies: SOAP, WSDL, and UDDI"). Accessing
a Web Service from a Visual Studio .NET application is as easy as creating one.
In your client project, right-click on the project and select Add Web Reference to display the Add Web Reference
dialog. Enter the URL for the Web Service's discovery file in the text box and
click on the arrow to the left of the box. Using the information in the
discovery file (or the asmx file itself if there is no discovery file), Visual
Studio .NET retrieves the WSDL document for your Web Service and displays it in
the left-hand pane. The right-hand pane contains links to more information
about the Web Service (see Figure 2). Here's a
tip: The easiest way to get the URL for your discovery file is to drag the file
from the Solution Explorer window to any code module in your Web Service
project. This adds the URL for the file to the module, where you can cut and
paste it into the Add Web Reference dialog in your client application. You also
must have at least one method defined in each asmx file before you can add a
reference to it in any application. When you
click on the Add
Reference button, your
client project is updated with the Web Service's wsdl file. In the Web Service
client project, you'll see a Web References folder and, underneath it, an entry
for the server on which the Web Service lives. Within the server folder, you'll
see an entry for each asmx file in your Web Service (see Figure 3). Visual
Studio also generates a proxy class module for each of the services to which
you have set references. Rather than dealing with the ugly realities of
generating and processing SOAP documents yourself, these proxy classes take
care of the dirty work for you. You simply instantiate the classes and call
their methods. The proxy classes include methods that duplicate those in your
asmx file, as well as other methods that allow you to manage calling the
service. The
names of these proxy classes are formed from the URL for your service and the
name of the asmx file. Instantiating the MathServices class for a Web
Service running on my local computer looks like this: Dim ms As
localhost.MathServices ms = New
localhost.MathServices() Calling
any method on the service is similar to calling a method on any other object,
thanks to the proxy classes. You can even use Try...Catch error handling
with the code that accesses the Web Service: Dim intResult
As Integer Try intResult = ms.AddOne(4) Catch ex As
Exception Response.Write(ex.ToString) End Try Because of the existence of the proxy
classes, if you make any change to the definitions of your Web Service's
functions, you'll need to update your client project to rebuild the proxy
classes. If you make a change to your Web Service project, select the Build option on the Build menu to
regenerate the application. Then, in the client application, right-click on the
name of the host in Solution Explorer and select Update Web Reference to regenerate the application's
proxy classes. The
proxy classes normally call your Web Service synchronously, which means your
client waits patiently for the service to return its result before continuing
to the next line of code. If you're concerned that you might wait too long, you
can set a timeout value (in milliseconds) using the proxy class's Timeout
property. This code, for instance, tells the proxy class to wait half a second
before giving up on the service: ms.Timeout =
500 You can
have the proxy call your Web Service asynchronously, as well. This allows you
to call the service and then go on to do something else in your program while
you wait for the service to return its result. For
every method in your service, the proxy class generates a Begin method and
an End method to support asynchronous access to that method. For my AddOne
method, this means the proxy contains a BeginAddOne method and an EndAddOne
method. The Begin
method accepts any parameters your method requires as well as two more
parameters to hold objects the proxy class needs: an AsyncCallback
object and an object of undetermined type that you can use to pass data to the
method. You don't have to pass these objects, and in my sample code I simply
pass Nothing for these parameters for now. But you do need to declare an
IAsyncResult object to catch the result the Begin method returns: Dim Ias As
IAsyncResult Now you
can instantiate the service and call it: Ias =
ms.BeginAddOne(4, Nothing, Nothing) You can
determine if the method has completed by checking the IsCompleted
property of the IAsyncResult object. When IsCompleted is True,
you can retrieve the service's return value by calling the EndAddOne
routine, passing the IAsyncResult object returned by the BeginAddOne
method: Do While Not
Ias.IsCompleted ...processing... Loop intResult =
ms.EndAddOne(Ias) Alternately,
if you've completed whatever else you had to do, you simply can call the End
method without waiting for the IsCompleted flag to be set to True.
Calling the End method before the service is complete causes your
program to wait for the service to complete and then returns the service's
result: Ias =
ms.BeginAddOne(4, nothing, nothing) ...processing... intResult =
ms.EndAddOne(Ias) You also
can create a callback method for your asynchronous call. With a callback
method, you don't have to write any code to wait for the result after calling
the Web Service. Your callback routine is called automatically when the Web
Service is done. To call
a Web Service method with a callback routine, you still use the Begin
version of the method. In the second parameter, pass the name of a routine you
wish the proxy to call when the method has completed (such as the callback
routine), with the AddressOf operator. This code calls the AddOne
method asynchronously and identifies AsyncAddOne as the callback
routine: Ias =
ms.BeginAddOne(4, AddressOf AsyncAddOne, Nothing) Of
course, you must write the callback routine. The routine must accept a single
parameter, which is an IASyncResult object. Once again, you retrieve
your result by calling the End version of the method, passing it the IASyncResult
object. The callback routine to work with my previous code would look like
this: Private Sub
AsyncAddOne(ByVal ar as IASyncResult) intResult = ms.EndAddOne(ar) ms = Nothing End Sub Callbacks,
however, are not well-suited for the ASP.NET environment. Once the routine that
calls the Web Service is finished running, there might be nothing to hold the
page at the server until the Web Service is done. By the time the callback is
ready to be executed, your ASP.NET page might have sent its output to the user
and been removed from memory. Creating
and calling Web Services in the ASP.NET environment in Visual Studio .NET is
simple and flexible. As you create your own Web Services, you provide yourself
with a toolbox from which you can assemble your own applications. The files referenced in this article are available for
download. Peter Vogel
is a principal in PH&V Information Services. He has designed, built, and
installed intranet and component-based systems for Bayer AG, Exxon, Christie
Digital, and the Canadian Imperial Bank of Commerce. He is editor of the Smart Access
and XML Developer newsletters and author of The Visual Basic
Object and Component Handbook
(Prentice Hall), which is being revised for .NET, and he presents information
at conferences around the world. E-mail Peter at mailto:[email protected]. Tell us what you think! Please send any comments about this
article to [email protected].
Please include the article title and author. Web Service Technologies: SOAP, WSDL, and UDDI If you've
been building applications with ASP classic or Visual Basic 6.0, you've been
using COM and DCOM to access components. In both ASP classic and Visual Basic,
you didn't have to know much about COM or DCOM to use them; the tools took care
of it for you. The combination of Simple Object Access Protocol (SOAP), Web
Services Description Language (WSDL), and Universal Description, Discovery, and
Integration (UDDI) provide the same kind of support in the world of Web
Services. The
essential technology behind Web Services is SOAP, which describes the format of
an XML document that allows you to send a request to run a method on some other
computer. SOAP also describes how to pass parameters in that document and how
to format the result of the method to send it back to the requesting program. A
Web Service must be able to read a SOAP document. Closely
affiliated with the SOAP specification is WSDL. A WSDL document uses a set of
XML-compliant tags to describe a Web Service. Included in a WSDL document is a
description of the company providing the Web Service, contact phone numbers,
and descriptions of the services the company provides. The key part of the WSDL
document for the developer is a tModel_spec, which describes the SOAP
message required by a particular Web Service. Web Service-aware development
tools can use the information in the wsdl file to format SOAP messages, which
saves the developer from having to create them. WSDL is
a result of the work done by the UDDI consortium. UDDI also describes a
peer-to-peer repository system for holding WSDL documents. (Microsoft and IBM
have established UDDI repositories already at http://www-3.ibm.com/services/uddi
and http://uddi.microsoft.com.)
When building an application that will access a Web Service, your development
tool will be able to pull the WSDL document for the service from some
convenient UDDI repository and use the information in the document to generate
your SOAP messages. Access the
Service
Figure 2. The Add Web Reference dialog
allows you to add a Web reference to your program or browse a Universal
Description, Discovery, and Integration (UDDI) repository.
Figure 3. Your project's Web References include
the wsdl files for each service, organized by server. Out of Sync