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.

Note

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.

Listing 5-1 The CustomerDB service provider as an XML Web service
 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(Namespace:="http://www.prosetech.com/", _  Description:="Methods to interact with the Customers table.")> _ Public Class CustomerDB     Private ConnectionString As String = _      "Data Source=localhost;Initial Catalog=Store;" & _      "Integrated Security=SSPI"     <WebMethod(Description:="Add a new customer record.")> _     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 & "')"         ExecuteNonQuery(Sql)     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 & "')"         ExecuteNonQuery(Sql)     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 CustomerdocEmphStrong"><WebMethod(Description:="Delete an existing customer record.")> _     Public Sub DeleteCustomer(ByVal customerID As Integer)         Dim Sql As String = "DELETE FROM Customers WHERE CustomerdocEmphStrong">' 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)         Try             con.Open()             cmd.ExecuteNonQuery()         Catch Err As Exception             Throw New ApplicationException( _              "Exception encountered when executing command.", Err)         Finally             con.Close()         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 CustomerCustomerID")             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)         Finally             con.Close()         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()         Try             con.Open()             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")                 Customers.Add(Customer)             Loop         Catch Err As Exception             Throw New ApplicationException( _              "Exception encountered when executing command.", Err)         Finally             con.Close()         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)), _           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         Try             con.Open()             Adapter.Fill(ds, "Customers")         Catch Err As Exception             ' Use caller inform pattern.             Throw New ApplicationException( _              "Exception encountered when executing command.", Err)         Finally             con.Close()         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 

Note

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.Run­time.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 types

Standard types such as integers and floating-point numbers, Boolean variables, dates and times, and strings are fully supported.

Enumerations

Enumerations types (defined by using the Enum keyword) are also fully supported.

Custom objects

You 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 objects

DataSet 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 objects

Objects 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 collections

You 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.



Microsoft. NET Distributed Applications(c) Integrating XML Web Services and. NET Remoting
MicrosoftВ® .NET Distributed Applications: Integrating XML Web Services and .NET Remoting (Pro-Developer)
ISBN: 0735619336
EAN: 2147483647
Year: 2005
Pages: 174

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net