Web Service Architecture

Team-Fly    

 
Application Development Using Visual Basic and .NET
By Robert J. Oberg, Peter Thorsteinson, Dana L. Wyatt
Table of Contents
Chapter 15.  Web Services


Besides handling ASP.NET, Microsoft's Internet Information Server (IIS) can handle Web services, since they come in as HTTP requests. These requests are encoded in the URL or as XML. IIS then creates the required object to fulfill the Web service request. IIS then calls the object's method that is associated with the request. Any returned values are converted to XML and returned to the client, using the HTTP protocol.

Setting Up the Web Services Examples

graphics/codeexample.gif

As usual, all the example programs for this chapter are in the chapter folder, Chap15 . To run the examples, you will need to have Internet Information Services (IIS) installed on your system, as discussed in Chapter 14. Following the procedure described in Chapter 14, make \OI\NetVb\Chap15 into a virtual directory with alias Chap15 . Once a virtual directory has been created, you can access files in it by including the virtual directory in the path of the URL. In particular, you can access the file default.htm using the URL http://localhost/Chap15/ . The file default.htm contains a home page for all the Web services example programs for this chapter. See Figure 15-1.

Figure 15-1. Home page for Web services example programs.

graphics/15fig01.jpg

The Add Web Service Example

To illustrate how this works under Microsoft .NET, we will build a simple Web service to illustrate this architecture and how the associated protocols are used. Our Web service will simply add two numbers . To make things clear, we will build the Web service Add in the simplest possible way.

By writing code in a file with the suffix asmx and placing it in a subdirectory of the IIS root directory, we can have a simple Web service. [6] IIS has the concept of virtual directories so that the actual directory does not have to physically be under the IIS root directory. All our examples in this chapter will be in subdirectories of the virtual directory Chap15 created in the previous section.

[6] By default this directory is \inetpub\ wwwroot .

The file add.asmx first defines the language used to write the Web service and the class that has the definitions. That class inherits from the WebService class in the namespace System.Web.Services . Note the use of the WebService attribute to define a namespace for the service. This file is found in the AddService directory for this chapter.

A method of that class can be used as a Web service if the attribute WebMethod is applied to it. (Note the := syntax in VB.NET for assigning a value to an attribute parameter.)

 graphics/codeexample.gif <%@ WebService language="VB" class="AddService" %> Imports System Imports System.Web Imports System.Web.Services <WebService(Namespace:="http://www.oi.com/netvb")> _ Public Class AddService    Inherits System.Web.Services.WebService    <WebMethod()> Public Function Add(_     ByVal x As Long, ByVal y As Long) As Long       Return x + y    End Function End Class 

A Client Program for the Add Web Service

Internet Explorer can be used as a simple client program that uses the HTTP GET protocol's URL encoding of a Web service request. You can access the Add Web service from the home page for this chapter, or you may use the URL http://localhost/Chap15/AddService/Add.asmx as the address. Figure 15-2 shows the result.

Figure 15-2. Web service request in Internet Explorer.

graphics/15fig02.jpg

By clicking on the Add link you will get a form enabling you to submit a request to the Add service. In addition, the form describes the various HTTP protocols that can be used for submitting the request. For our purposes, two protocols are worth mentioning: HTTP GET and SOAP.

The HTTP GET protocol is worth exploring because the form that appears in IE uses it. The protocol has boldfaced placeholders for data that has to be entered:

 GET Chap15/AddService/Add.asmx/Add?  x=string  &  y=string  HTTP/1.1 ... 

The data entered into the form is added to the URL in the standard way that any HTTP GET request is made. Data is returned as

 <?xml version="1.0" encoding="utf-8" ?> <long xmlns="http://www.oi.com/netvb">  long  </long> 

Figure 15-3 shows values entered into the form. By pressing the Invoke button, you can call the Web service.

Figure 15-3. Values entered on the Internet Explorer form.

graphics/15fig03.jpg

An IE window will appear with the part of the HTTP response data generated by the Web service that contains the actual returned value:

 ... <long xmlns="http://www.oi.com/netvb">  12  </long> 

This is exactly the format that appeared in the description of the protocol with the answer (12) substituted for the placeholder. HTTP GET, however, can handle only simple types.

The more interesting protocol is SOAP. Both the SOAP HTTP POST request and response are described with placeholders for information that has to be provided in the actual call. Those placeholders are in boldface type.

First, let us look at the SOAP HTTP POST request. The first part is a set of HTTP headers. The XML for the SOAP protocol is in the data (entity-body) section of the HTTP request, which is always separated from the headers by a blank line. The content-length header is the length of the data, which is dependent on the size of the parameters in the data section.

The method header identifies the file to which the request is directed. It could also name an object that is to handle the request (endpoint). The SOAP-Action header indicates the name of the method, qualified by a namespace, to be invoked for the Web service. [7]

[7] For those with a COM background, you can think of the namespace for the method as equivalent to the GUID that identifies an interface (IID).

SOAP uses XML to specify the parameters of the method. [8] The SOAP body contains the parameters for the method call. In a real method call, the long placeholders would be replaced by the actual parameters to be passed to the Web service method.

[8] The parallel to IDL is WSDL, which we will discuss shortly. SOAP is analogous to NDR, the wire format used for DCOM calls. All these parallels to COM appear in Don Box's March 2000 MSDN article "A Young Person's Guide to the Simple Object Access Protocol."

 POST /Chap15/AddService/Add.asmx HTTP/1.1 Host: localhost Content-Type: text/xml; charset=utf-8 Content-Length:  length  SOAPAction: "http://www.oi.com/netvb/Add" <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema- instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <Add xmlns="http://www.oi.com/netvb">       <x>  long  </x>       <y>  long  </y>     </Add>   </soap:Body> </soap:Envelope> 

Next, the HTTP response is described. The long placeholder will be replaced by the actual value returned.

 HTTP/1.1 200 OK Content-Type: text/xml; charset=utf-8 Content-Length: length <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema- instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <AddResponse xmlns="http://www.oi.com/netvb">       <AddResult>  long  </AddResult>     </AddResponse>   </soap:Body> </soap:Envelope> 

WSDL

SOAP does not describe the Web service interface. While you could encode the SOAP yourself, it would be nice to be able to generate proxy classes for the client to use. Otherwise, you would have to understand all the details of the SOAP specification and how to parse the returned XML.

WSDL provides a description of the Web service interface. You can view this description from IE by clicking on the Service Description link, as illustrated in Figure 15-2. Here is the WSDL description for our AddService , which has one method, Add . We have omitted the WSDL for invocations of the Web service that do not use SOAP. The <types> section defines the types:

  • Add is used when SOAP invokes the Web service.

  • AddResponse is used when the SOAP Web service invocation returns.

Add has two elements, each occurring exactly once. Both are defined with the XSD type long, and they have the names x and y. The return parameter, whose name is AddResponse , has one element named AddResult , which occurs once, defined with the XSD type long. Note how these types were used in the SOAP definitions we looked at previously.

 ... <types> ...   <s:element name="Add">     <s:complexType>       <s:sequence>         <s:element minOccurs="1" maxOccurs="1" name="x"                                           type="s:long" />         <s:element minOccurs="1" maxOccurs="1" name="y"                                           type="s:long" />       </s:sequence>     </s:complexType>   </s:element>   <s:element name="AddResponse">     <s:complexType>       <s:sequence>         <s:element minOccurs="1" maxOccurs="1"                          name="AddResult" type="s:long" />       </s:sequence>     </s:complexType>   </s:element>   ... </types> 

The <message> section relates the types to their use as parameters.

 <message name="AddSoapIn">   <part name="parameters" element="s0:Add" /> </message> <message name="AddSoapOut">   <part name="parameters" element="s0:AddResponse" /> </message> ... 

The <portType> section relates the Web service to the individual Web methods defined by the <operation> elements. If there had been more Web methods in the Web service, there would have been more operation elements associated with the portType. [9] Each method's input and output operation is associated with the appropriate message defined previously.

[9] For those of you keeping score, this is analogous to a COM interface.

 <portType name="TestSoap">   <operation name="Add">     <input message="s0:AddSoapIn" />     <output message="s0:AddSoapOut" />   </operation> </portType> ... 

The <binding> section defines the encodings and protocols to be used for each operation.

 <binding name="TestSoap" type="s0:TestSoap">   <soap:binding           transport="http://schemas.xmlsoap.org/soap/http"           style="document" />   <operation name="Add">     <soap:operation http://www.oi.com/netvb/Add"         style="document" />     <input>       <soap:body use="literal" />     </input>     <output>       <soap:body use="literal" />     </output>   </operation> </binding> ... 

The <service> section relates the Web service to its port and how it is invoked.

 <service name="Test">   <port name="TestSoap" binding="s0:TestSoap">     <soap:address location=            "http://localhost/AddService/Add.asmx" />   </port> ... </service> ... 

Proxy Classes

The wsdl tool can be used to read the WSDL description and generate a proxy class that will make the SOAP calls for you. The following command will generate a VB.NET proxy class file with the name addproxy.vb , where the /l parameter is used to specify the language:

 wsdl /l:VB /out:addproxy.vb /protocol:SOAP http://localhost/Chap15/AddService/Add.asmx?WSDL 

The /l parameter is used here to specify the language (default is CS for C#), and the /protocol parameter is used to specify the protocol (default is SOAP).

The generated proxy defines a constructor and three methods. The constructor sets the URL that this Web service uses. One of the methods represents a synchronous, blocking call on the Web service. The other two methods correspond to the asynchronous design pattern discussed in Chapter 10. If you want to call the Web service asynchronously, you can use the BeginXXX and the EndXXX methods associated with the proxy. [10] The proxy class has the same name as the WebService class.

[10] Of course, in this particular case XXX=Add.

The Invoke method of the SoapHttpClientProtocol class will make the HTTP request and process the HTTP response associated with the transmitted and received SOAP packets. This example is found in the AddClient directory. Here is the code for the generated proxy class, in file addproxy.vb .

 graphics/codeexample.gif Public Class AddService    Inherits _    System.Web.Services.Protocols.SoapHttpClientProtocol    Public Sub New()       MyBase.New       Me.Url = _          "http://localhost/Chap15/AddService/Add.asmx"    End Sub    ...    Public Function Add(ByVal x As Long, ByVal y As Long) _     As Long       Dim results() As Object = Me.Invoke(_          "Add", New Object() {x, y})       Return CType(results(0),Long)    End Function    ...    Public Function BeginAdd(ByVal x As Long, ByVal y As _     Long, ByVal callback As System.AsyncCallback, _     ByVal asyncState As Object) As System.IAsyncResult       Return Me.BeginInvoke("Add", New Object() {x, y}, _          callback, asyncState)    End Function    ...    Public Function EndAdd(ByVal asyncResult As _     System.IAsyncResult) As Long       Dim results() As Object = Me.EndInvoke(asyncResult)       Return CType(results(0), Long)    End Function End Class 

You can then write a program to use the proxy classes to issue a Web service request.

 ' AddClient.vb Module AddClient    Sub Main()       Dim adder As New AddService()       Dim sum As Long = adder.Add(1, 2)       Console.WriteLine(sum)    End Sub End Module 

Web Service Client with Raw SOAP and HTTP

To show you what the SoapHttpClientProtocol class does, the final client program for this example uses sockets to send both the HTTP headers and the SOAP directly and to receive the response from the Web service. This example is the RawAddClient directory.

The main routine first sets up variables for talking to the HTTP server on port 80.

 graphics/codeexample.gif Dim httpServer As String = "localhost" Dim httpPort As Integer = 80 

It then reads in a file that has the SOAP headers for the service to be called. It returns the length of the content, which will have to be placed in one of the HTTP POST headers.

 Dim contentLength As Long Dim contentData As StringBuilder = _    BuildContent("SoapAdd.txt", contentLength) Dim requestHeader As StringBuilder = _    BuildHeader(contentLength) 

It then connects to the server, sends the data, and receives the response, which it writes out to the console.

 Dim endPoint As New IPEndPoint(Dns.Resolve(_    httpServer).AddressList(0), httpPort) Dim sock As New Socket(AddressFamily.InterNetwork, _    SocketType.Stream, ProtocolType.Tcp) sock.Connect(endPoint) If Not sock.Connected Then    Console.WriteLine("Unable to connect to host")    Return End If Console.WriteLine(requestHeader.ToString()) Console.WriteLine(contentData.ToString()) Dim ASCII As Encoding = Encoding.ASCII Dim header() As Byte = _    ASCII.GetBytes(requestHeader.ToString()) Dim content() As Byte = _    ASCII.GetBytes(contentData.ToString()) ' make the request sock.Send(header, header.Length, 0) sock.Send(content, content.Length, 0) ' Receive the response ASCII = Encoding.ASCII Dim bytes As Integer Dim receivedData() As Byte = New Byte(4096) {} ' receive actual response bytes = sock.Receive(receivedData, receivedData.Length, 0) Console.WriteLine(ASCII.GetString(receivedData, 0, bytes)) sock.Close() 

The routine BuildHeader just builds a standard HTTP POST request with the addition of the SOAPAction header.

 Function BuildHeader(ByVal contentLength As Long) _  As StringBuilder    Dim sb As New StringBuilder(1024)    Const QUOTE = ChrW(&H22)    sb.Append("POST /SimpleWebService/Add.asmx HTTP/1.1" _       & vbCrLf)    sb.Append("Host: localhost" & vbCrLf)    sb.Append("Content-Type: text/xml; charset=utf-8" _       & vbCrLf)    Dim line As String = "Content-Length: " & _       contentLength.ToString() & vbCrLf    sb.Append(line)    sb.Append("SOAPAction: " & QUOTE & _     "urn:uuid:10C14FCF-BF4A-477a-BFE7-41B9F2A4514E/Add" _     & QUOTE & vbCrLf)    sb.Append(vbCrLf)    Return sb End Function 

BuildContent just reads a file to a buffer and calculates the size of the buffer in bytes.

 Function BuildContent(ByVal filename As String, _  ByRef contentLength As Long) As StringBuilder    Dim sb As New StringBuilder(1024)    Dim fs As New StreamReader(File.OpenRead(filename))    contentLength = 0    Dim line As String = fs.ReadLine()    Do While line <> Nothing       sb.Append(line)       sb.Append(vbCrLf)       contentLength += line.Length + 2       line = fs.ReadLine()    Loop    fs.Close()    Return sb End Function 

Based on our previous discussion, the SOAP file, SoapAdd.txt , looks as we would expect it to. The input parameters 9 and 3 appear as the WSDL would dictate .

 <?xml version="1.0" encoding="utf-8"?> <soap:Envelope    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:xsd="http://www.w3.org/2001/XMLSchema"    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <Add xmlns=           "urn:uuid:10C14FCF-BF4A-477a-BFE7-41B9F2A4514E">       <x>9</x>       <y>3</y>     </Add>   </soap:Body> </soap:Envelope> 

The program first writes out the HTTP POST request. First come the standard HTTP headers with a special SOAPAction header, then the SOAP encoding of the request.

 POST /SimpleWebService/Add.asmx HTTP/1.1 Host: localhost Content-Type: text/xml; charset=utf-8 Content-Length: 393 SOAPAction:        "urn:uuid:10C14FCF-BF4A-477a-BFE7-41B9F2A4514E/Add" <?xml version="1.0" encoding="utf-8"?> <soap:Envelope    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:xsd="http://www.w3.org/2001/XMLSchema"    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">   <soap:Body>     <Add xmlns=           "urn:uuid:10C14FCF-BF4A-477a-BFE7-41B9F2A4514E">       <x>9</x>       <y>3</y>     </Add>   </soap:Body> </soap:Envelope> 

The program then writes out the response. [11] Again, the HTTP headers come first, then the SOAP encoding of the result, 12.

[11] If you don't get the output result the first time you run the program, try running the program a second time.

 ... HTTP/1.1 200 OK Server: Microsoft-IIS/5.0 Date: Mon, 17 Sep 2001 02:11:30 GMT Cache-Control: private, max-age=0 Content-Type: text/xml; charset=utf-8 Content-Length: 383 <?xml version="1.0" encoding="utf-8"?> <soap:Envelope     xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"     xmlns:xsd="http://www.w3.org/2001/XMLSchema">   <soap:Body>     <AddResponse xmlns=           "urn:uuid:10C14FCF-BF4A-477a-BFE7-41B9F2A4514E">       <AddResult>12</AddResult>     </AddResponse>   </soap:Body> </soap:Envelope> 

Team-Fly    
Top
 


Application Development Using Visual BasicR and .NET
Application Development Using Visual BasicR and .NET
ISBN: N/A
EAN: N/A
Year: 2002
Pages: 190

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