Create and consume Web Services with Visual Studio .NET.
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:
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:
<WebMethod(Description:="Increment a value")> _
Public Function AddOne(ByVal inValue As Integer) As Integer
Return inValue + 1
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").
Access the Service
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).
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.
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).
Figure 3. Your project's Web References include the wsdl files for each service, organized by server.
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
intResult = ms.AddOne(4)
Catch ex As Exception
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
Out of Sync
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
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)
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
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@example.com.
Tell us what you think! Please send any comments about this article to firstname.lastname@example.org. Please include the article title and author.
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.