Microsoft .NET Distributed Applications: Integrating XML Web Services and .NET Remoting

Microsoft .NET Distributed Applications: Integrating XML Web Services and .NET Remoting

by Matthew MacDonald

Make the jump to distributed application programming using the .NET Framework—and introduce a new level of performance, scalability, and security to your network and enterprise applications. Expert .NET developer Matthew MacDonald shares proven techniques for fully exploiting .NET Remoting, XML Web services, and other .NET technologies and integrating them


Make the jump to distributed application programming using the .NET Framework—and introduce a new level of performance, scalability, and security to your network and enterprise applications. Expert .NET developer Matthew MacDonald shares proven techniques for fully exploiting .NET Remoting, XML Web services, and other .NET technologies and integrating them into your real-world solutions. MacDonald digs into key .NET building blocks and architectural issues, explaining which features and designs will best serve your customized distributed application projects—and when to use them. Case studies with full code examples illustrate these practical techniques in action, as well as demonstrating their benefits and tradeoffs.

Learn how to:

  • Cross application boundaries with .NET Remoting, XML Web services, and Message Queuing
  • Create responsive clients and scalable servers with multithreading
  • Model your distributed application with interfaces, facades, and factories
  • Use COM+ services such as object pooling, JIT activation, and transactions
  • Craft a data transfer plan with Microsoft ADO.NET—without concurrency errors
  • Help secure your code end to end—from the transport level to the presentation tier
  • Learn ways to avert—or unclog—performance bottlenecks in your applications
  • Automate deployment using self-updating applications and XML Web services
  • Master stateless programming and other best practices for distributed applications

Product Details

Microsoft Press
Publication date:
Developer Reference Series
Product dimensions:
7.38(w) x 9.16(h) x 1.82(d)

Related Subjects

Read an Excerpt

Chapter 5.

XML Web Services (RPC the Easy Way)

  • The Role of XML Web Services in a Distributed System
  • .NET Remoting vs. XML Web Services
  • XML Web Service Plumbing
    • The Role of IIS
    • Creating a Virtual Directory
    • The XML Web Service File Format
  • Creating an XML Web Service
    • Data Serialization
  • Testing the XML Web Service
    • The WSDL Document
  • Consuming the XML Web Service
    • Examining the Proxy Class
    • Using the Proxy Class
    • Debugging Web Services
  • ASP.NET Platform Services
    • SOAP Headers and SOAP Extensions
  • Publishing an XML Web Service
  • Cross-Platform XML Web Services
    • Summary

5   XML Web Services (RPC the Easy Way)

XML Web services are, depending on your point of view, a breath of fresh air after the complexities of Microsoft .NET Remoting or a simplified approach to distributed code execution that lacks a few key features. Both arguments contain at least a grain of truth. More accurately, XML Web services represent a new approach to distributed architecture, one that favors simplicity, best design practices, and cross-platform use over raw communication speed. XML Web services provide a simple, robust, and flexible way to make a remote procedure call (RPC).

Most introductory .NET books provide a brief introduction to XML Web services and describe some of the underlying standards such as WSDL and SOAP. This chapter takes a more practical approach. We start with a quick introduction to XML Web services, examine how the technology differs from .NET Remoting, and consider where XML Web services fit into the design of an enterprise application. We also examine how you can make use of ASP.NET platform services in an XML Web service, publish the availability of an XML Web service, and consume XML Web services from other platforms.

The Role of XML Web Services in a Distributed System

XML Web services play much the same role in an application as a component exposed through .NET Remoting. If you’re new to XML Web services, you might first think of something like a Web site that enables you to look up the shipping date for a package or an investment site that enables you to get real-time price quotes. However, both of these examples are really entire Web applications. They might rely on a back-end XML Web service to actually retrieve the information, but they also include a user interface in the form of a Web page.

XML Web services, like any other type of middle-tier component, do not provide any type of user interface. They are used exclusively by other applications and are never invoked directly by end users. For example, you might create a package or a stock quote lookup XML Web service and then call this XML Web service from an ASP.NET Web application or a desktop Windows client.

.NET XML Web services are often identified as ASP.NET Web services because they represent an extension of the ASP.NET platform. In ASP.NET, every Web page acts like an individual application that runs briefly on the Web server when requested and returns an XML result over HTTP. ASP.NET is optimized for this task and uses multiple worker threads, automatic process recycling, output caching, and other enterprise-level features to ensure it can handle a large volume of clients. XML Web services work in much the same way as Web pages: They run briefly on the Web server and return a result in an XML markup (generally as a SOAP message). Much as ASP.NET Web pages create the illusion of a continuously running Web application, XML Web services can create the illusion of a stateful object. In reality, however, XML Web services are stateless components that are created and executed just-in-time when a client invokes an XML Web service method. This is one of the most dramatic departures from .NET Remoting, which provides the flexibility to allow singleton and client-activated objects that remain in memory under a set lease lifetime policy.

.NET Remoting vs. XML Web Services

XML Web services offer a simpler model for distributed applications than that provided by .NET Remoting. XML Web services are fine-tuned for Internet scenarios and cross-platform use. Although you can apply .NET Remoting in these scenarios, thanks to its SOAP formatter and HTTP channel, .NET Remoting is more suitable as a high-speed solution for binary communication between proprietary .NET components, usually over an internal network. And although XML Web services can’t match the communication speed of .NET Remoting over a binary channel, they still lend themselves to high-performance designs thanks to their stateless nature and ASP.NET’s multithreaded hosting service.

Here’s a quick overview of the major differences between the XML Web service and .NET Remoting technologies:

  • XML Web services are more restricted than objects exposed over .NET Remoting. An XML Web service works in a similar way to a SingleCall .NET Remoting object. It isn’t possible to create a singleton or a client-activated object.
  • Because of the restricted nature of XML Web services, the design issues are simplified. XML Web services are generally easier to create than remotable components (and easier to design well).
  • Communication with .NET Remoting can be faster than XML Web service communication if you use a binary formatter. XML Web services support only SOAP message formatting, which uses larger XML text messages.
  • XML Web services support open standards that target cross-platform use. For example, each .NET XML Web service has an associated WSDL document that describes how a client can interact with the service. Therefore, any client that can parse an XML message and connect over an HTTP channel can use an XML Web service, even if the client is written in Java and hosted on a UNIX computer.
  • XML Web services are designed for use between companies and organizations. They can use a dynamic discovery mechanism or a UDDI registry that "advertises" services to interested parties over the Internet.
  • XML Web services don’t require a dedicated hosting program because they are always hosted by ASP.NET. That also means that they gain access to some impressive platform services, including data caching, Web farm–ready session state management, authentication, and an application collection for global, shareable objects. These features, if required, can be extremely difficult to re-create by hand in a component exposed through .NET Remoting.
  • Because XML Web services work through Microsoft Internet Information Services (IIS) and ASP.NET, they can communicate with clients using the default HTTP channel (usually port 80). This means that consumers can use XML Web services just as easily as they can download HTML pages from the Internet. There’s no need for an administrator to open additional ports on a firewall.

The underlying technology that supports XML Web services overlaps with portions of the .NET Remoting framework. Part of the reason for this is that these technologies were developed simultaneously, before the .NET team realized the full potential of XML Web services. Chapter 11 examines the similarities a little more closely. For now, it helps to remember a broad distinction: If you are planning to provide functionality to clients over the Internet, XML Web services should be your first choice. If you need different capabilities or faster communication over a closed network, however, .NET Remoting is often a better option.

According to Microsoft architects, .NET Remoting isn’t designed to work in interop situations (for example, with Java clients) or when crossing trust boundaries (for example, exposing functionality to third-party clients or another business). These two basic rules of thumb can help you decide when to use .NET Remoting and when to use XML Web services. Incidentally, speculation abounds that XML Web services and .NET Remoting technology will be integrated in some future release of the .NET Framework, although this development isn’t on the imminent horizon—and it won’t help you plan today’s generation of distributed applications.

XML Web Service Plumbing

XML Web services are based on a cluster of open standards. Table 5-1 lists the key players.

Table 5-1 XML Web Service Technologies

Standard Description
WSDL (Web Services Description Language)An XML-based format that describes everything a client needs to interact with an XML Web service. This includes the XML Web service’s methods, the data types used for all parameters and return value, and the supported methods of communication.
HTTP (Hypertext Transfer Protocol)The communication protocol used to send XML Web service requests and responses over the Internet.
SOAP (Simple Object Access Protocol)An XML-based format used to encode the information in XML Web service messages. SOAP includes a rich, cross-platform way of representing common data types (such as integers, strings, and arrays).
DISCO (Discovery)DISCO is Microsoft’s first crack at a lightweight way to create a simple list of XML Web service links. This can allow clients to discover the XML Web services offered by a particular organization. DISCO is slated for replacement by another similar standard called WS-Inspection, which was developed jointly with IBM.
UDDI (Universal Description, Discovery, and Integration)The youngest and least evolved of the standards. UDDI is a business repository of XML Web service links designed to allow one business to find another based on the type of service, the business name, and so on. This specification is sure to go through many iterations before it becomes widely accepted.

So how do all these standards fit together? We’ll begin with the process of creating the XML Web service, which can be summarized in three steps:

  1. Create a dedicated virtual directory to host the XML Web service on your Web server, using IIS.
  2. Code the custom XML Web service class, using the <WebMethod> attribute to mark each method that should be remotely callable. At its simplest, the XML Web service class is a collection of stateless methods. .NET takes care of the communication infrastructure that allows the client to discover and call these methods.
  3. Deploy the XML Web service files to the virtual directory.

The second step is for the client to find and use your XML Web service:

  1. The client finds the XML Web service, either through a predetermined URL or by using a discovery document or the UDDI registry.
  2. The client requests the WSDL document that describes the XML Web service. .NET creates this document quickly and automatically by examining your XML Web service.
  3. The client generates a proxy class based on the WSDL document. If the client is written using .NET, this step is performed automatically.
  4. The client uses the proxy class much as it would use an XML Web service class if it were instantiated in the local process. Behind the scenes, the proxy sends a SOAP message to the XML Web service and receives a SOAP message result. The proxy class handles the Internet communication and SOAP formatting automatically (as shown in Figure 5-1).
  5. Figure 5-1 XML Web service interaction (Image unavailable)

This process is similar to .NET Remoting in several respects. First of all, the client communicates using a proxy class. The proxy class mimics the XML Web service and handles all the low-level details. Many programming platforms, including .NET, provide tools that create this proxy automatically.

The key difference is in how the proxy class is created. With .NET Remoting, the proxy object is generated dynamically. As soon as a .NET client instantiates a remote object, the runtime springs into action, creating the proxy based on the information in the assembly that describes the remote class. With XML Web services, the proxy class is created using the information found in the WSDL document. This is similar to the type of information contained in the assembly metadata, but it’s stored in a cross-platform, human-readable XML format.

Another difference is the fact that the XML Web service proxy class is created during the development cycle. If the XML Web service changes, the proxy class must be manually regenerated. This process sidesteps the headaches required with .NET Remoting, where the client always needs a reference to the assembly that describes the remote component (or a supported interface). The WSDL document also contains enough information for non-.NET clients to communicate with the XML Web service on their own, without requiring a proprietary tool. We’ll look at this issue at the end of the chapter.

The Role of IIS

With XML Web services, you don’t worry about creating a server program that listens for requests and creates the required object. Instead, ASP.NET and IIS work together to perform this service for you.

IIS is the software that allows your computer to become a Web server and allows remote clients to download HTML pages (or run ASP.NET pages). IIS is included with Microsoft Windows 2000, Windows XP, and Windows .NET Server, but it isn’t necessarily installed by default.

Here, localhost is the special "loopback" alias that always refers to the current computer. (Alternatively, you can use the specific server name or IP address.) localstart.asp is a traditional ASP file that is stored in the root directory of your computer’s Web site home directory. If you receive an error when you attempt this request, you should check to make sure you have IIS installed.

To install IIS, follow these steps:

  1. From the Start menu, choose Settings, Control Panel.
  2. Select Add Or Remove Programs, and then click Add/Remove Windows Components.
  3. Select Internet Information Services in the list, and click Next to install the appropriate files.

You must install IIS on your development computer even if the XML Web service will ultimately be hosted on a different Web server.

For those who aren’t familiar with IIS, here are the key fundamentals you need to understand before you can create XML Web services:

  • IIS provides access to the Web server through virtual directories.   If you want to provide access to the C:\MyWeb directory, for example, you might create a virtual directory. In this example, the virtual directory name (MyWeb) is the same as the physical directory name, but this isn’t required. If your computer is accessible over the Internet (or an intranet), clients can browse to a Web page in the virtual directory. For example, you can view the HTML page C:\MyWeb\index.html.
  • Virtual directories don’t have the same permissions as normal directories.   By default, remote clients aren’t allowed to browse the virtual directory, run executables, create files, or download restricted file types (such as Microsoft Visual Basic source code files). You can configure some of these settings using IIS Manager and add further restrictions such as authentication requirements.
  • IIS handles your computer’s Internet exposure.   However, it doesn’t run ASP or ASP.NET pages or XML Web services. Instead, IIS maintains a list of registered file extensions. For example, ASP.NET pages (ASPX files) and XML Web services (.asmx files) are registered to the ASP.NET worker process. If IIS receives a request for one of these file types, it hands the work off to the ASP.NET worker process, which handles the rest of the work.

Creating a Virtual Directory

Before you create an XML Web service project in Visual Studio .NET, you should create a dedicated virtual directory. Otherwise, all your code files will be automatically located in a subdirectory of C:\Inetpub\wwwroot, which is the default home directory for IIS. This can cause a great deal of confusion, particularly when it comes time to move your XML Web service project to another computer.

Luckily, creating your own virtual directory is easy. Follow these steps:

  1. Create the physical directory on your hard drive.
  2. Start IIS Manager by choosing Settings, Control Panel, Administrative Tools, Internet Services Manager from the taskbar.
  3. Start the Virtual Directory Wizard in IIS Manager by right-clicking on the Default Web Site item (under your computer in the tree) and choosing New, Virtual Directory from the shortcut menu.
  4. Click Next to get started. Specify the alias, which is the name that your virtual directory will have for Web requests. Click Next to continue.
  5. Specify the physical directory that will be exposed as the virtual directory. Click Next to continue.
  6. The final wizard window gives you the chance to adjust the virtual directory permissions. The default settings allow clients to run ASP.NET pages and XML Web services but not make any modifications or upload files. This is the recommended configuration.
  7. Click Next, and then click Finish to end the wizard. You will see the virtual directory in the IIS Manager tree display (as shown in Figure 5-2). After you have created a virtual directory, you can create a Web project in it using Visual Studio .NET.

Figure 5-2 IIS Manager (Image unavailable)

The XML Web Service File Format

As mentioned earlier, XML Web services are special files with the extension .asmx. The ASP.NET worker process is registered to handle Web requests for this type of file. When it receives a request, it loads the .asmx file, compiles the appropriate class, executes the relevant Web method, and returns the result. This process is similar to the process used for ASP.NET pages (.aspx files). However, .aspx files contain significant information about the controls used on a Web page. The .asmx file is really just a text document that tells ASP.NET where it can find the relevant XML Web service class. Technically, you can create an .asmx file that contains the code itself, but it’s almost always easier (and better in terms of organization) to place the XML Web service class in a separate file or dedicated assembly. This is also the model that Visual Studio .NET enforces.

The following sample .asmx file indicates that the XML Web service class called MyWebService can be found in a separate MyWebService.vb code file. ASP.NET is gracious enough to compile this file automatically when needed (a service that ordinary .NET components don’t provide).

<%@ WebService Language="VB" Codebehind="MyWebService.vb"
    Class="MyWebService" %>

And here’s a more typical example that indicates that the XML Web service class is named MyWebService and is already compiled into a DLL assembly called MyAssembly:

<%@ WebService Language="VB" Class="MyWebService,MyAssembly" %>

Most developers will program XML Web services with Visual Studio .NET. In this case, the .asmx file is created automatically. (In fact, Visual Studio .NET doesn’t even display the contents of .asmx files in the integrated development environment [IDE], but if you use Notepad to examine these files, you’ll see content similar to what’s shown here.) Visual Studio .NET also compiles all the XML Web service classes in the project into a single DLL assembly. Therefore, when it comes time to deploy the completed project to a production Web server, all you need to do is copy the individual .asmx files and a single DLL assembly. You can safely leave the Visual Basic source code files behind.

Every .asmx file contains a reference to one XML Web service. However, a given virtual directory can contain any number of .asmx files, and a Web server can contain any number of virtual directories. The important fact to remember is that each virtual directory acts like a separate ASP.NET application that runs in a dedicated process space and does not share any memory. This becomes important if you use the ASP.NET platform services. XML Web services in the same virtual directory use a common data cache and state collection, which XML Web services in different directories can’t access.

Creating an XML Web Service

Actually creating an XML Web service class is easy, which is one of the reasons XML Web services have gained far more exposure than .NET Remoting. All you need to do is import the System.Web.Services namespace and add a <WebMethod> attribute to each method that you want to expose in the XML Web service.

<WebMethod()> _
Public Sub AddCustomer(ByVal customer As CustomerDetails)
    ’ (Code omitted.)
End Sub

Optionally, you can set additional <WebMethod> properties to configure a text description for each Web method, which can help the client understand how your service works. You can also add a <WebService> attribute to your class declaration (although this isn’t strictly required) to set a description for the entire service and associate an XML namespace with your service.

XML Web service methods can’t be overloaded. That means you can’t create two versions of a single method that accept different parameters. Instead, you need to use distinct names (such as GetCustomerByID and GetCustomerByName). This is just one of the ways that XML Web service methods are not as fully featured as a local .NET class.

Listing 5-1 shows an example of the CustomerDB service provider component redesigned as an XML Web service. The differences are highlighted.

Imports System.Web.Services
Imports System.Data.SqlClient
Imports System.Data
‘ The XML namespace is not related to a .NET namespace.
‘ It simply associates a unique identifier that can be used 
‘ to describe your service in the WSDL document.
‘ Typically, you will use a URL that you control.
<WebService> _

    Public Sub AddCustomer(ByVal customer As CustomerDetails)
        Dim Sql As String = "INSERT INTO Customers "
        Sql &= "(FullName, EmailAddress, Password) VALUES (‘"
        Sql &= customer.Name & "‘,  ’"
        Sql &= customer.Email & "‘, ’"
        Sql &= customer.Password & "‘)"
    End Sub
    <WebMethod(Description:="Modify an existing customer record.")> _
    Public Sub UpdateCustomer(ByVal customer As CustomerDetails)

        Dim Sql As String = "INSERT INTO Customers "
        Sql &= "(FullName, EmailAddress, Password) VALUES (‘"
        Sql &= customer.Name & "‘, ’"
        Sql &= customer.Email & "‘, ’"
        Sql &= customer.Password & "‘)"
    End Sub
    <WebMethod(Description:="Modify an existing customer record.")> _
    Public Sub UpdateCustomer(ByVal customer As CustomerDetails)
        Dim  Sql As String = "UPDATE Customers SET "
        Sql &= "FullName=‘" & customer.Name
        Sql &= "‘, EmailAddress=‘" & customer.Email
        Sql &= "‘, Password=‘" & customer.Password
        Sql &= "‘ WHERE CustomerID=" & customer.ID.ToString()
    End Sub
    <WebMethod(Description:="Delete an existing customer record.")> _
    Public Sub DeleteCustomer(ByVal customerID As Integer)
        Dim Sql As String = "DELETE FROM Customers WHERE CustomerID="
        Sql &= customerID.ToString()
    End Sub
    ’ This private method is not remotely callable.
    Private Sub ExecuteNonQuery(ByVal sql As String)
        Dim con As New SqlConnection(ConnectionString)
         Dim cmd As New SqlCommand(sql, con)
        Catch Err As Exception
            Throw New ApplicationException( _
             "Exception encountered when executing command.", Err)
        End Try
    End Sub
    <WebMethod(Description:="Retrieve a single customer record.")> _
    Public Function GetCustomer(ByVal customerID As Integer) _
     As CustomerDetails
        Dim Sql As String = "SELECT * FROM Customers Where CustomerID="
        Sql &= customerID.ToString()
        Dim con As New SqlConnection(ConnectionString)
         Dim cmd As New SqlCommand(Sql, con)
        Dim reader As SqlDataReader
        Dim Customer As New CustomerDetails()
            reader = cmd.ExecuteReader(CommandBehavior.SingleRow)
            Customer.ID = reader("CustomerID")
            Customer.Name = reader("FullName")
            Customer.Email = reader("EmailAddress")
            Customer.Password = reader("Password")
        Catch Err As Exception
            Throw New ApplicationException( _
             "Exception encountered when executing command.", Err)
        End Try
        Return Customer
    End Function
    <WebMethod(Description:="Retrieve all customers in an array.")> _
    Public Function GetCustomers() As CustomerDetails()
        Dim Sql As String = "SELECT * FROM Customers"
        Dim con As New SqlConnection(ConnectionString)
        Dim cmd As New SqlCommand(Sql, con)
        Dim reader As SqlDataReader
        Dim Customers As New ArrayList()
            reader = cmd.ExecuteReader()
            Do While reader.Read()
                Dim Customer As New CustomerDetails()
                Customer.ID =  reader("CustomerID")
                Customer.Name = reader("FullName")
                Customer.Email = reader("EmailAddress")
                Customer.Password = reader("Password")
        Catch Err As Exception
            Throw New ApplicationException( _
             "Exception encountered when executing command.", Err)
        End Try
        ’ Now we convert the ArrayList to a strongly-typed array,
        ’ which is easier fo the client to deal with.
        ’ The ArrayList makes this possible  through a handy
        ’ ToArray() method.
        Return CType(Customers.ToArray(GetType(CustomerDetails)), _
    End Function
    <WebMethod(Description:="Retrieve all customers in a DataSet.")> _
    Public Function GetCustomersDS() As DataSet
        Dim Sql As String = "SELECT * FROM Customers"
        Dim con As New SqlConnection(ConnectionString)
        Dim cmd As New SqlCommand(Sql, con)
        Dim Adapter As New SqlDataAdapter(cmd)
        Dim ds As New DataSet
            Adapter.Fill(ds, "Customers")
        Catch Err As Exception
            ’ Use caller inform pattern.
             Throw New ApplicationException( _
             "Exception encountered when executing command.", Err)
        End Try
        Return ds
    End Function
End Class

Public Class CustomerDetails
    Public ID As Integer
    Public Name As String
    Public Email As String
    Public Password As String

End Class

Listing 5-1 The CustomerDB service provider as an XML Web service

Although the code in Listing 5-1 throws an ApplicationException if a problem occurs, the client will actually receive a SoapException object, which contains a text message that describes the original application class. This is an inherent limitation with how .NET handles SOAP, and it reduces the efficiency of a client to check for specific error conditions. One way around this problem is for the XML Web service to throw a SoapException directly and store extra XML information in the SoapException.Detail property.

Remember, if you aren’t designing your class with Visual Studio .NET, you also need to create the .asmx file that "advertises" the XML Web service to ASP.NET and move both files to a virtual directory. Visual Studio .NET performs these minor steps automatically.

Data Serialization

One difference you might have noticed in the XML Web service example is the downgraded CustomerDetails class. In the .NET Remoting example, the CustomerDetails class included full property procedures, several constructors, and a <Serializable> attribute. In an XML Web service, none of these is necessary. In fact, you could create property procedures and constructors, but the client wouldn’t be able to use them. Instead, the client would receive a stripped-down version of the class that only uses public member variables (like the version shown in the preceding example).

Why the discrepancy? Even though XML Web services and .NET Remoting components can both send SOAP messages, they use different formatters. Components exposed through .NET Remoting or saved to disk require the <Serializable> attribute and use the SoapFormatter class from the System.Runtime.Serialization.Formatters.Soap namespace. Web services, on the other hand, make use of the XmlSerializer class in the System.Xml.Serialization namespace. Both of these classes transform .NET objects into XML messages. The difference is that the SoapFormatter can exactly reproduce any serializable .NET object, provided it has the assembly metadata for the class. This involves some proprietary logic. The XmlSerializer, in contrast, is designed to support third-party clients who might understand little about .NET classes and assemblies. It uses predetermined rules to convert common data types. These rules, which are based on XSD and the SOAP standard, allow for the encoding of common data types, arrays, and custom structures but don’t provide any standard way to represent code (such as constructors and property procedures). Therefore, these details are ignored.

Table 5-2 lists the data types supported in XML Web services and the SOAP standard.

Table 5-2 Data Types Supported in XML Web Services

Data Type Description
Basic data typesStandard types such as integers and floating-point numbers, Boolean variables, dates and times, and strings are fully supported.
EnumerationsEnumerations types (defined by using the Enum keyword) are also fully supported.
Custom objectsYou can pass any object you create based on a custom class or structure. The only limitation is that only data members can be transmitted. If you use a class with defined methods, the copy of the object that is transmitted will have only its properties and variables.
DataSet objectsDataSet objects are natively supported. They are returned as simple structures, which .NET clients can automatically convert to full DataSet objects. DataTable objects and DataRow objects, however, are not supported.
XmlNode objectsObjects based on System.Xml.XmlNode are representations of a portion of an XML document. Under the hood, all Web service data is passed as XML. This class enables you to directly support a portion of XML information whose structure might change.
Arrays and collectionsYou can use arrays and simple collections of any supported type, including DataSet objects, XmlNode objects, and custom objects.

What Is SOAP?:
So far, we’ve been using the terms SOAP and XML almost interchangeably. Technically, SOAP is a set of tags based on XML. (You can think of XML as supplying the grammar, or ground rules, whereas SOAP defines the allowed vocabulary.) SOAP is used with Web method calls because it defines a very flexible way to encode common data types. It’s thanks to SOAP that you can create an XML Web service that returns a DataSet or a custom structure such as CustomerDetails. You could encode the same information in ordinary XML, but there are so many possible variations that a client would never know what to expect.

SOAP is a key XML Web service format, but it isn’t required. In fact, if clients don’t support SOAP messages over HTTP, you can communicate using simple name-value pairs with HTTP GET (which passes parameter information in the query string) or HTTP POST (which passes parameter information in the body of the message). However, SOAP toolkits exist for most programming languages, including Java and COM-based Microsoft programming languages such as Visual C++ and Visual Basic. You’ll almost always use SOAP encoding with your XML Web services, for the following reasons:

  • Only SOAP allows the client to pass objects as parameters. In other words, the current version of the UpdateCustomers method wouldn’t work over HTTP GET or HTTP POST because it requires a CustomerDetails object as a parameter. SOAP also provides support for ByRef parameters.
  • SOAP is more standardized. .NET defines its own rules for encoding information in an HTTP GET or HTTP POST message.
  • SOAP provides better exception support with .NET clients. If a method called over HTTP GET or if HTTP POST fails, it just returns an unhelpful HTTP error.

In this book, we won’t discuss the low-level details of SOAP formatting any more than we’ll discuss binary encoding in .NET Remoting or discuss HTTP headers. Although it never hurts to have a solid understanding of the protocols that support a given technology, these topics are peripheral to some of the real issues of application design. In fact, SOAP messages have been available to programmers, one way or another, for quite a while. However, it’s only with .NET that they’ve gained much popularity with Microsoft programmers because the .NET Framework provides a simple, extensible abstraction on top of the low-level tedium. Learning how to master that abstraction (in this case, the XML Web services model) is more important than learning how various data types are encoded unless you need to mount a major cross-platform project.

Testing the XML Web Service

ASP.NET provides a simple way to test an XML Web service after you have deployed it to a virtual directory. If you request the .asmx file in a Web browser, you’ll see an automatically generated test page that lists the available methods and the text descriptions you’ve added (as shown in Figure 5-3).

Figure 5-3 The CustomerDB test page (Image unavailable)

To test a Web method, you click one of the methods. A separate window will appear, with text boxes provided for parameters and with an Invoke button. When you click Invoke, the request message is sent, the XML Web service class is created, the Web method executes, the XML Web service class is destroyed, and the result is returned as an XML document that appears in the browser. Figure 5-4 shows the result of invoking the GetCustomers method from the test page. It returns an XML structure representing an array with five customers (two of which are collapsed in the screen shot).

Figure 5-4 The result of invoking GetCustomers (Image unavailable)

It’s important to understand that this technique does not require any special functionality from your Internet browser—it’s simply a convenience provided by ASP.NET. If you were to type the exact same request string into a Netscape or Opera browser, you would receive the same test page and the same XML document. The request string is actually a request to the XML Web service using HTTP GET. It identifies the XML Web service, Web method, and any required parameters:

Here’s the HTTP GET request required to get the list of all customers:

And here’s another HTTP GET request string; this one retrieves information for the single customer record with the CustomerID of 1:

Note that when you use the test page, the method of communication is HTTP GET (not SOAP). This means that you won’t be able to test some methods in your browser, such as UpdateCustomer.

The WSDL Document

You also can request the WSDL document for your XML Web service by requesting the .asmx file with ?WSDL appended to the end of the request string. (The test page links directly to this document; just click Service Description.) The WSDL document has the same role the IDL file does in COM programming, except it uses an XML-based syntax rather than a C-based syntax.

The WSDL document is far from compact. It’s designed to be independent of communication protocols (like HTTP) and encoding methods (like SOAP), which gives it the ability to be used with future technologies. Unfortunately, this also means that the WSDL document requires a lengthy, multipart structure. If you browse through the WSDL document for the CustomerDB XML Web service, you’ll find information about the supported methods and the custom-defined CustomerDetails class (excerpted here):

<s:complexType name="CustomerDetails">
    <s:element minOccurs="1" maxOccurs="1" name="ID" type="s:int" /> 
    <s:element minOccurs="0" maxOccurs="1" name="Name"
               type="s:string" /> 
    <s:element minOccurs="0" maxOccurs="1" name="Email"
               type="s:string" /> 
    <s:element minOccurs="0" maxOccurs="1" name="Password"
               type="s:string" /> 

Fortunately, there is little need to read the WSDL document directly. If you’re creating a .NET client, you can create a proxy class based on the WSDL document automatically. The same feat is possible with many third-party tools in non-.NET languages.

Consuming the XML Web Service

.NET enables you to create an XML Web service proxy class in two ways. If you are using Visual Studio .NET, you can generate the proxy class using the Web reference feature (as shown in Figure 5-5). Just start a normal ASP.NET, Console, or Windows client project. Then right-click on the project in Solution Explorer and choose Add Web Reference. You can then enter the WSDL document location, or you can enter a Web URL that identifies a page or discovery document that links to the XML Web service and then browse to it using the appropriate link.

Figure 5-5 Adding a Visual Studio .NET Web reference (Image unavailable)

Figure 5-5 shows the version of the Add Web Reference dialog box that you’ll see in Visual Studio .NET 2003. In earlier versions, the window is functionally equivalent but looks a little different. Visual Studio .NET 2003 also adds a few links that allow you to easily search for UDDI Web servers and browse the information they provide.

When you click Add Reference, the proxy class is generated in the language of the current project and is added to the project. By default, however, the proxy class is hidden because it shouldn’t be modified directly. If you want to examine the proxy class, choose Project, Show All Files from the Visual Studio .NET menu. By default, the proxy class file has the name Reference.vb and is grouped under the server name in the Web References section of Solution Explorer (as shown in Figure 5-6).

Figure 5-6 The Reference.vb proxy class file (Image unavailable)

Even if you aren’t using Visual Studio .NET, you can still create the proxy class using the WSDL.exe command-line utility that is included with the .NET Framework. This utility is found in the .NET Framework directory, such as C:\Program Files\Microsoft.NET\FrameworkSDK\Bin.

The syntax for WSDL.exe is shown here. Table 5-3 describes each field.

wsdl /language:language  /protocol:protocol /namespace:myNameSpace
     /out:filename /username:username /password:password
     /domain:domain <url or path>

A typical WSDL.exe command looks something like this (split over two lines):

wsdl /language:VB /namespace:localhost 
      This creates a CustomerDB.vb proxy class file. You can then add this file to a client project or compile to a DLL using the vbc.exe command-line compiler, as shown here:

vbc /t:library CustomerDB.vb

Table 5-3 WSDL.exe Command-Line Parameters

Parameter Description
LanguageThis is the language that the proxy class will use. The language really doesn’t matter because you won’t directly modify the proxy class code (because any changes are lost every time you regenerate it). The default is C#.
ProtocolUsually, you will omit this option and use the default (SOAP). However, you can also specify HTTP GET and HTTP POST for more limiting protocols.
NamespaceThis is the .NET namespace that your proxy class will use. If you omit this parameter, no namespace is used and the classes in this file are available globally. For better organization, you should choose a logical namespace. Visual Studio .NET automatically uses the server name (for example, localhost).
OutThis enables you to specify the name for the generated file. By default, this is the name of the service followed by an extension indicating the language (for example, CustomerDB.vb).
Username, password, and domainYou should specify these values if the Web server requires authentication to access the virtual directory.
URL or pathThis piece of information is always added at the end of the WSDL.exe command line. It specifies the location of the WSDL document for the Web service.

Examining the Proxy Class

It’s not necessary to examine the proxy class, but doing so provides some interesting insights into how the .NET XML Web service framework works. Essentially, the proxy class mimics the XML Web service, reproducing every Web service method. The client then creates an instance of the proxy class and calls one of its methods. Behind the scenes, the proxy class packages the information into a SOAP request message, waits for the SOAP response message, and then converts the return value into a standard .NET data type, which it then passes back to the client.

Listing 5-2 shows a shortened version of the autogenerated CustomerDB proxy class. Notice that it includes a copy of the CustomerDetails class, which allows the client to use this type natively. The proxy class also includes specialized Begin and End versions of each Web method (as in BeginGetCustomer and EndGetCustomer), which allow the Web method to be called asynchronously. These methods, which aren’t shown here, are examined in more detail in the next chapter.

Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports System.Xml.Serialization
Namespace localhost
    <WebServiceBinding, _
     XmlIncludeAttribute(GetType(System.Object()))> _
    Public Class CustomerDB
        Inherits SoapHttpClientProtocol
        Public Sub New()
            Me.Url = _
        End Sub
        <SoapDocumentMethod("AddCustomer"> _
        Public Sub AddCustomer(ByVal customer As CustomerDetails)
            Me.Invoke("AddCustomer", New Object() {customer})
        End Sub
         <SoapDocumentMethod("UpdateCustomer"> _
        Public Sub UpdateCustomer(ByVal customer As CustomerDetails)

            Me.Invoke("UpdateCustomer", New Object() {customer})
        End Sub
        <SoapDocumentMethod("DeleteCustomer"> _
        Public Sub DeleteCustomer(ByVal customerID As Integer)
            Me.Invoke("DeleteCustomer", New Object() {customerID})
        End Sub
        <SoapDocumentMethod("GetCustomer"> _
        Public Function GetCustomer(ByVal customerID As Integer) _
         As CustomerDetails
            Dim results() As Object = Me.Invoke("GetCustomer", _
              New Object() {customerID})
            Return  CType(results(0),CustomerDetails)
        End Function
            Return CType(results(0),CustomerDetails())
        End Function
            Return CType(results(0),System.Data.DataSet)
        End Function
    End Class
    <System.Xml.Serialization.XmlTypeAttribute()>  _
    Public Class CustomerDetails
        Public ID As Integer
        Public Name As String
        Public Email As String
        Public Password As String
    End Class
End Namespace

Listing 5-2 The proxy class for the CustomerDB service

The proxy class gains the ability to send SOAP messages over the Internet because it inherits from the SoapHttpClientProtocol class, which provides an Invoke method. Notice that each method receives a result as a generic object, which it then converts to the expected strongly typed class or structure.

By contrast, .NET Remoting uses its own dynamic proxy mechanism. .NET Remoting proxies are created at run time, whereas XML Web service proxies are created at design time. As a side effect, if the XML Web service changes, you must first recompile the XML Web service and then regenerate the proxy class. In Visual Studio .NET, you can accomplish this quickly by right-clicking on the Web reference in Solution Explorer and choosing Update Web Reference.

Using the Proxy Class

Using the proxy class is easy—in fact, it works just like any other object. Listing 5-3 and Figure 5-7 show a sample Windows client that gets the list of all customers and displays in a DataGrid control. This example is nearly identical to the local data component example in Chapter 3, even though the method call is invoked over the Internet. If you use Visual Studio .NET, you can even enter Break mode and single-step from the client code into the XML Web service code.

Public Class WindowsClient
    Inherits System.Windows.Forms.Form
    ’ (Designer code omitted.)
    Private Sub WindowsClient_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load
        Dim DBProxy As New localhost.CustomerDB()
        DataGrid1.DataSource = DBProxy.GetCustomerDS().Tables(0)
    End Sub
End Class

Listing 5-3 A basic Windows client

Figure 5-7 Retrieving query results through an XML Web service (Image unavailable)

And here’s an example that shows how you can interact with the CustomerDetails object defined by the XML Web service:

Public Class WindowsClient
    Inherits System.Windows.Forms.Form
    ’ (Designer code omitted.)
    Private Sub WindowsClient_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load
        Dim DBProxy As New localhost.CustomerDB()
        Dim Customer As localhost.CustomerDetails
        Customer = DBPr oxy.GetCustomer(1)
        MessageBox.Show("CustomerID 1 is: " & Customer.Name)
    End Sub
End Class

Keep in mind that this is really just a remote procedure call. The XML Web service doesn’t retain any state. Therefore, even though you retain a reference to the proxy class, the actual XML Web service instance is created at the beginning of every method invocation and is destroyed at the end. This means that you can’t set instance variables or properties and expect the values to persist between method calls.

By default, the proxy sends its SOAP message over the default HTTP port used for Web traffic: 80. You can also tweak some proxy class settings to adjust this communication if needed. If you need to connect through a computer called MyProxyServer using port 80, for example, you can use the following code before you call any proxy methods:

Dim ConnectionProxy As New WebProxy("MyProxyServer", 80)
Dim DBProxy As New localhost.CustomerDB()
DBProxy.Proxy = WebProxy

Similarly, you can adjust the amount of time the proxy waits for a SOAP response before timing out and throwing an exception, as follows:

DBProxy.Timeout = 10000  ’ 10000 milliseconds is 10 seconds.

Debugging Web Services

It’s possible to debug an XML Web service in a separate instance of Visual Studio .NET or as part of a multiproject solution. However, you’ll need to tweak the debugging settings so that your XML Web service code is compiled and loaded into the debugger. Otherwise, you won’t be able to set breakpoints, use variable watches, or rely on any of the other indispensable Visual Studio .NET debugging features.

To enable XML Web service debugging, right-click on the project in Solution Explorer and choose properties. Then under the Configuration Properties | Debugging node, choose Wait For External Process To Connect, as shown in Figure 5-8. This instructs Visual Studio .NET to load the debugging symbols when you run the XML Web service, instead of simply showing the XML Web service test page.

Figure 5-8 Configuring an XML Web service for debugging (Image unavailable)

If you’re testing a compiled client or a client in another instance of Visual Studio .NET, just be sure to start the XML Web service project first in order to debug it. If you’re creating a solution that includes both a client and an XML Web service, you can configure it to have multiple startup projects, exactly as you would with .NET Remoting. Simply right-click on the solution item in the Solution Explorer, and choose Properties. Figure 5-9 shows an example in which both an XML Web service and a client application are launched when the solution is started.

While testing an XML Web service, you might encounter the infamous "unable to start debugging on the server" error. This signals that Visual Studio .NET was able to compile the XML Web service but can’t execute it in debug mode. Unfortunately, this problem can result because of countless different reasons. One common problem occurs if you install IIS after you install the .NET Framework. In this case, you can "repair" the .NET Framework using the original setup CD or DVD. Microsoft describes this process—and a number of other possible causes for this error—in a white paper. One common cause not mentioned is failing to create the virtual directory or trying to run a program after you’ve removed or modified the virtual directory. To correct these problems, modify the virtual directory settings in IIS Manager.

Figure 5-9 Starting an XML Web service and client (Image unavailable)

Another problem that can occur in Visual Studio .NET 2003 is a failure to authenticate. Visual Studio .NET 2003 attempts to access the local Web server using integrated Windows authentication, even if you have anonymous authentication enabled for the virtual directory. Thus, your virtual directory must allow both anonymous and Windows Integrated authentication. To allow for this, follow these steps:

  1. Start IIS Manager.
  2. Right-click the virtual directory for your application, and choose Properties. (Alternatively, you can configure authentication for all directories if you right-click the Web Sites folder and choose Properties.)
  3. Select the Directory Security tab.
  4. In the Anonymous access and authentication section, click the Edit button.
  5. In the Authentication Methods dialog box, under Authenticated access, select Integrated Windows Authentication, as shown in Figure 5-10.
  6. Figure 5-10 Enabling Windows authentication for debugging (Image unavailable)

  7. Click OK to apply your changes.

ASP.NET Platform Services

The ASP.NET platform provides a rich set of services for all types of Web applications. You can harness many of these features in your XML Web services just by deriving your XML Web service class from System.Web.Service.WebService.

<WebService> _
Public Class CustomerDB
    Inherits WebService

By inheriting from WebService, your class gains four additional properties, as shown in Table 5-4. These features include a few heavyweights, such as authentication and caching, that we’ll return to in later chapters. These prebuilt features are so useful that in many situations you’ll find it easier to build a large-scale performance-optimal solution with XML Web services rather than .NET Remoting, even though .NET Remoting supports leaner binary communication.

Table 5-4 WebService Properties

Property Description
ApplicationProvides a global collection where you can store any .NET object.
ContextProvides access to some ASP.NET intrinsic objects, such as Request and Response. Most of these aren’t useful in XML Web services because you are interacting with a proxy class, not directly with the client. However, one object (Cache) is extremely useful for storing frequently used information. You’ll learn how to master this object in Chapter 12.
ServerProvides server utility methods for tasks such as encoding HTML content and URL query strings. These features generally aren’t useful in an XML Web service.
SessionProvides a collection where you can store information that’s bound to the current request. However, this capability can easily waste server memory and is disabled by default.
UserEnables you to retrieve information about the client if it has logged on through the proxy class using some form of integrated IIS authentication. You’ll learn about this option—and some more flexible alternatives—in Chapter 13.

You could also access these properties without deriving from WebService, by using the System.Web.HttpContext class.

SOAP Headers and SOAP Extensions

SOAP headers and extensions are great ways to extend the SOAP standard, and they add support for custom encryption, logging, compression, and authentication schemes. SOAP headers and extensions are also potential nightmares because they represent proprietary add-ons that you can apply to your XML Web services, potentially making them less generic and more difficult to support on other platforms. SOAP headers and extensions are also wedded to the SOAP standard, meaning you can’t easily adapt a SOAP header authentication technique or SOAP extension logging approach to a .NET Remoting component that works over a TCP/IP channel with binary messages.

This chapter won’t discuss SOAP headers and extensions. However, Chapter 13 and Chapter 18 show how you can use SOAP headers to implement security in conjunction with a custom ticket-based authentication system.

Microsoft is also developing a number of XML Web service extensions based on emerging SOAP standards, particularly those related to security and authentication. These are known collectively as the Web Service Enhancements (WSE) and are available. As these standards continue to evolve, the WSE will likely change or be incorporated into a future release of the .NET platform.

Publishing an XML Web Service

Because XML Web services aim to share functionality between organizations, there needs to be some mechanism that enables an interested party to discover which XML Web services another entity offers. The most ambitious part of this strategy is the UDDI registry, which is still in its infancy. Essentially, UDDI is a specification that defines how an XML Web service registry should be organized and how XML Web services can be registered programmatically. There are currently several test UDDI implementations, including the Microsoft Registry. You can find general information about the UDDI standard. A link in a UDDI registry can point to a WSDL document or to a discovery document listing XML Web services. This book does not cover UDDI in any detail.

Microsoft also supports a simpler discovery standard. In the current version of Visual Studio .NET, this is DISCO (which is slated for replacement by a similar standard called WS-Inspection, as mentioned earlier). A DISCO document is essentially an XML file with a list of links to one or more WSDL documents. A client using Visual Studio .NET can enter the URL for a discovery document when adding a Web reference and can easily find the required XML Web service. Essentially, a discovery document offers a simple approach to sharing XML Web service URLs in a standardized format.

A typical discovery document has the extension .disco or .vsdisco and contains one or more <contractRef> elements, each of which points to a WSDL document. It can also contain <discoveryRef> links that point to other discovery files or <schemaRef> links that point to XSD documents. Here’s an example that can allow a client to locate the CustomerDB XML Web service:

<?xml version="1.0" encoding="utf-8" ?>
<disco:discovery  xmlns:disco=""

Note that the example doesn’t use the localhost reference because the client requires the real name of the server.

Microsoft also supports a dynamic discovery format. When a client requests this file, the Web server automatically creates a list of all the XML Web services in the given virtual directory and any subdirectories. You can specifically exclude search paths (typically to save time) by using the <exclude> attribute, although this doesn’t stop the client from adding a reference to an XML Web service in one of these directories if it is not secured through IIS.

<?xml version="1.0" encoding="utf-8" ?>
  <exclude path="_vti_cnf" />
  <exclude path="_vti_pvt" />
  <exclude path="_vti_log" />
  <exclude path="_vti_script" />
  <exclude path="_vti_txt" />

Cross-Platform XML Web Services

You’ve already seen how you can invoke an XML Web service in any browser using HTTP GET and the properly formatted query string. This gives you an idea of how easy it is for a non-.NET client to access an XML Web service. It just has to send the appropriate HTTP request and parse the retrieved XML document.

To test this technique, you can use the Microsoft XML COM library, which includes an XMLHTTP object that can send XML documents over the HTTP channel. This example (shown in Listing 5-4 and illustrated in Figure 5-11) uses Visual Basic 6 and Microsoft XML version 4 (msxml4.dll), but earlier versions will also work.

Private Sub Form_Load()
    Dim Transfer As XMLHTTP
    Set Transfer = New XMLHTTP
    ’ Call the XML Web Service using HTTP GET. "GET", _

     "" & _
     GetCustomers", False
    ’ Retrieve the XML response.
    Dim Doc As DOMDocument
    Set Doc = Transfer.responseXML
    ’ Configure the MSFlexGrid control.
    MSFlexGrid1.TextMatrix(0, 0) = "ID"
    MSFlexGrid1.TextMatrix(0, 1) = "Name"
    MSFlexGrid1.TextMatrix(0, 2) = "Email"
    MSFlexGrid1.TextMatrix(0, 3) = "Password"
    ’ Parse the response.
    Dim Child As MSXML2.IXMLDOMNode
    For Each Child In Doc.documentElement.childNodes
      ’ The first node (offset 0) is the ID.
      ’ The second node (offset 1) is  the name.
      ’ The third node (offset 2) is the email.
      ’ The fourth node (offset 3) is the password.
      MSFlexGrid1.AddItem (Child.childNodes(0).Text & vbTab & _
       Child.childNodes(1).Text & vbTab & Child.childNodes(2).Text & _
       vbTab & Child.childNodes(3).Text)
End Sub

Listing 5-4 Consuming a .NET XML Web service in Visual Basic 6

Figure 5-11 A Visual Basic 6 XML Web service client (Image unavailable)

Ideally, the client will use a slightly more advanced technique and will use SOAP messages. You can send and receive SOAP messages using the XMLHTTP object, but the client will need to shoulder the burden of manually creating the request message and processing the response. If the XML Web service changes, the client must also adapt. However, most platforms include more sophisticated tools that enable you to send SOAP messages using a higher-level abstraction and even create proxy classes by analyzing WSDL documents. Some examples include the following:

  • Microsoft’s SOAP Toolkit, which works with the previous generation of Visual Studio products (such as Visual Basic and C++)
  • IBM’s Web Service Development Kit
  • Oracle’s Web Integration Development Language
  • Sun Microsystems’s Sun ONE (Open Net Environment) offering, which now supports Web services written in the Java language
  • Perl’s SOAP::Lite kit, which provides basic SOAP functionality


This chapter has provided a lightning-quick introduction to XML Web services. I’ve steered away from many conventional topics (such as an examination of the SOAP standard), which are discussed to excess in most introductory .NET texts. Instead, this chapter has honed in on some more useful XML Web service topics, including cross-platform development, serialization, and ASP.NET platform services. The coming chapters show how you can work with XML Web services in even more flexible ways, including using asynchronous requests and authentication. I haven’t introduced these topics yet because they represent techniques that can be applied with benefit to both XML Web services and .NET components exposed through .NET Remoting.

This chapter also touched on some topics that we won’t return to in any detail, including ASP.NET pages and IIS configuration. If you would like to learn more about the ASP.NET platform and how to configure a Web server, you might be interested in a dedicated ASP.NET book, such as my ASP.NET: The Complete Reference (Osborne McGraw-Hill, 2002). Of course, you’ll need to return to this book to learn many of the best practices to follow when you implement these features in an enterprise application.

Finally, if you would like to try interacting with a prebuilt XML Web service, the Internet provides many choices. You can try creating client applications for the following:

  • Microsoft’s TerraService, which provides a free gateway to TerraServer, the multiterabyte database of satellite photography. You can use TerraService to download satellite images and display them in your .NET applications.
  • Microsoft’s MapPoint, which enables you to access high-quality maps and geographical information. MapPoint isn’t free, but you can use a free trial of the XML Web service.

The basic services are on GotDotNet; they include tried-and-true favorites such as the thumbnail generator, the mail sender, and the quote of the day. Best of all, you can also see the .NET implementation code for the XML Web services.

Meet the Author

Matthew MacDonald is a developer, author, and educator in all things Visual Basic and .NET. He's worked with Visual Basic and ASP since their initial versions, and has written over a dozen books on the subject, including The Book of VB .NET (No Starch Press) and Visual Basic 2005: A Developer's Notebook (O'Reilly). He has also written a number of Missing Manual titles on Excel 2007 and Access 2007 (O’Reilly). His website is

Customer Reviews

Average Review:

Write a Review

and post it to your social network


Most Helpful Customer Reviews

See all customer reviews >