In my previous column, I provided an overview of Microsoft's .NET Framework. We discussed .NET's language-independence and the .NET Framework class libraries. With today's column, we start a series about Web Services.
A Web service is programmable application logic that standard Web protocols can access. The application logic itself can be anything from a simple Math class that exposes Add() and Subtract() functions to a complex credit card verification service that can verify and post purchases against credit cards.
You can implement the application logic using any technology on any platform—the key is standard Web protocol access. Rather than relying on protocols such as Distributed COM (DCOM), Common Object Request Broker Architecture (CORBA), or Remote Method Invocation (RMI), a Web service uses ubiquitous protocols, such as HTTP, and encodes its data as XML. Together HTTP and XML form one of the new industry buzzwords: Simple Object Access Protocol (SOAP).
SOAP is a protocol specification that details how applications can communicate using HTTP and XML. Several respected companies, including IBM and Microsoft, submitted the SOAP specification to the World Wide Web Consortium (W3C) for standardization in May 2000. Many of the submitters have also implemented the specification. IBM, for example, is working on an Apache module, and Microsoft recently released a new version of its SOAP Toolkit. Microsoft is also making Web Services a core .NET feature.
Although still in public beta, Microsoft's .NET Framework will have deep support for SOAP and its ancillary technologies, such as Web Service Description Language (WSDL) and Universal Discovery Description and Integration (UDDI)—both of which we'll discuss in future columns. The .NET Framework supports several options for building Web Services, most notably .NET Remoting and ASP.NET.
As its name suggests, .NET Remoting is designed to facilitate calling .NET objects remotely from other .NET applications. It supports concepts such as passing objects by reference, stateful connections, and controlling the remote object lifetime. In addition to the support for.NET object management, .NET Remoting supports using various protocols, such as binary or SOAP, depending on the goal of the application. In most cases, you'll choose .NET Remoting when you need rich type fidelity and object management in an intranet environment. For Web applications, you'll most likely use ASP.NET Web Services.
ASP.NET Web Services
ASP.NET Web Services, designed for developers familiar with Active Server Pages (ASP), emphasizes loosely coupled XML document exchanges. ASP.NET Web Services supports passing any data that an XML schema can describe. In addition, ASP.NET Web Services supports state management through common ASP features, such as Session or Application.
ASP.NET makes building Web Services easy. Rather than an emphasis on understanding the protocols, the encoding, or any of the underlying plumbing (e.g., serialization), ASP.NET's emphasis is on rapid application development (RAD). That ASP.NET hides the plumbing details from you doesn't imply that they aren't accessible. Instead, ASP.NET Web Services gives you a large degree of control over the SOAP message through a lower-level feature known as extensions (we'll save the discussion of extensions for a future column).
Building a Web Service
Let's walk through an example of building a Web Service with ASP.NET. We start with some simple database access application logic and morph it into a Web Service. The following VB.NET class is a common function we might write for an application:
Imports System.Data Imports System.Data.SQL Public Class DataExample Public Function GetStoreByState(state As String) As DataSet Dim myDataSet As New DataSet Dim dsn As String Dim sqlSelect As String Dim sqlConnection As SQLCOnnection Dim sqlCommand As SQLDataSetCommand ' Set initialize values ' ****************** dsn = "server=localhost;uid=example;pwd=33sdemo;database=pubs" sqlSelect = "Select * From stores Where state='" + state + "'" ' Connect and Execute ' ****************** sqlConnection = New SQLConnection(dsn) sqlCommand = New SQLDataSetCommand(sqlSelect, sqlConnection) ' Fill DataSet and return ' ****************** sqlCommand.FillDataSet(myDataSet, "products") Return myDataSet End Function End Class
This function encapsulates access to our database and lets us retrieve the appropriate data by passing in a state value. The function then dynamically builds the SQL query, executes the query, and populates an ADO.NET DataSet. ADO.NET supports two key themes for data access: connected and disconnected. In this example, we use a DataSet, which represents a disconnected representation of the data in our database. That is, as we step through the data in the DataSet, we don't iterate over each row in a SQL table as we would with an ADO-style RecordSet. We return the populated DataSet, which contains a list of items for the chosen state, to the caller. We could use this function in an application as follows:
. . . Dim example As New DataExample() Dim storeData As DataSet storeData = example.GetStoreByState("CA")
We could then bind this data to a grid or step through each item and output its value. However, what if we decide that we want to surface the GetStoreByState() function as a Web Service—that is, we want to accept calls to this function via SOAP and respond via SOAP using ASP.NET? Easy . . . with ASP.NET installed!
First, we save the above application logic—as is—in a file with the extension .asmx. Because the Web Service needs to be accessible to the Web, we save the logic in a directory our Web server can access (e.g., assuming a default Windows 2000/Windows NT installation, c:\inetput\wwwroot\DataAccess.asmx).
We then modify our file slightly:
<%@ WebService Language="VB" Class="DataExample" %> Imports System.Data Imports System.Data.SQL Imports System.Web.Services Public Class DataExample Public Function <WebMethod()> GetDataSet(state As String) As DataSet Dim myDataSet As New DataSet Dim dsn As String Dim sqlSelect As String Dim sqlConnection As SQLCOnnection Dim sqlCommand As SQLDataSetCommand ' Set initialize values ' ****************** dsn = "server=localhost;uid=sa;pwd=00password;database=pubs" sqlSelect = "Select stor_name From stores Where state='" + state + "'" ' Connect and Execute ' ****************** sqlConnection = New SQLConnection(dsn) sqlCommand = New SQLDataSetCommand(sqlSelect, sqlConnection) ' Fill DataSet and return ' ****************** sqlCommand.FillDataSet(myDataSet, "products") Return myDataSet End Function End Class
In addition to saving the code in a .asmx file, we add a directive that instructs ASP.NET which language is used and which class contains the Web Service:
<%@ WebService Language="VB" Class="DataExample" %>
We also add a namespace that contains classes that the Web Service requires:
Finally, we add an attribute to the function—this attribute resides in the System.Web.Services namespace:
Our GetDataSet() function is now a SOAP-based Web Service. If we request it from our Web server, we receive a page that details what the service can and can't do as well as a page to make "test" calls to GetDataSet().
In my next column, we'll drill into this example in more detail and fill out some other interesting aspects of Web Services. For another look at this topic, see "At Your Service, On The Web".