Web Services between .NET, Java and MS SOAP Toolkit – Part II
| This second article in this series dedicated to Web services comes as asequel to the first one in which I started to tell you how you couldbuild different kind of clients and services using MS SOAP Toolkit,Apache SOAP for Java and .NET Framework.
In the last article I mentioned something about the incompatibilitybetween a MS SOAP client and an Apache SOAP server (the infamousxsi:type). As far as I know the version 2.2 didn't solve this problem,which is Apache SOAP Server is still expecting all parameters to have atype specified. But, the good news is that there is a work around tothis problem. Many of you sent me e-mails asking how to do this. Wellit is fairly simply. Apache SOAP Server and clients Do you remember the Apache SOAP server we wrote last time? Wellanother good news is that you don't have to change anything inside theserver. You only need to change the deployment descriptor. Let me tell you more about the workaround before writinganything. The major difference between MS implementation of SOAP andApache for Java's is that the former relies on WSDL files to fullydescribe the service when the latter doesn't. This is why in theinitial implementation of the Apache SOAP for Java the type is requiredto be specified for each parameter. The server has no other mean toknow the type of the parameters unless is specified in the call. In theMS implementation the WSDL file has enough information and the servercan figure out even if the call tells nothing about this. Now, the solution to our problem is: when you deploy yourservice you can specify the type mapping of each parameter in yourmethods. The Java service uses this whenever there isn't enoughinformation in the method call. So you must add a mappings section to your deployment script. I modified the deployment descriptor for our service. |
<isd:service xmlns:isd="http://xml.apache.org/xml-soap/deployment"
id="urn:MyService ">
�
<isd:mappings>
<isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:x="" qname="x:num1"
xml2JavaClassName="org.apache.soap.encoding.soapenc.DoubleDeserializer"/>
<isd:map encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:x="" qname="x:num2" xml2JavaClassName="org.apache.soap.encoding.soapenc.DoubleDeserializer"/>
</isd:mappings>
�
</isd:service>
| That's all.Believe it or not that's all you have to change. The MS STK clientdoesn't need any change either. The same mention for the .NET client,don't change anything.
This will complete our incursion to building clients and services(simple ones) using the three major frameworks available. I mustmention here that there are other frameworks for building SOAP serversand clients so don't be shy and publish source code and information sowe can all learn about them. I remember seeing among people on SOAPBuilders discussion group another name: Glue. They were at beta versionlast time a checked their web site but I'm sure they will quickly bereleasing their product. Generic client for Web Services Ok so now we know hot to build a web service when we have enoughinformation about the service itself: we are either the developers ofthe service or good friends with the developer, so we can get the�signature� of the service at the time we write the client. Now, suppose you want to build a client that is able to call a serviceknowing only the name of the methods or something similar. My examplewill try to add two numbers searching a Math service and calling themethods. A more practical example could be a stock checker or somethingsimilar. The steps I follow are: And here is the code: |
Option Explicit
Function BuildOperation( _
ByVal WSDLFileName As String, _
ByVal WSMLFileName As String, _
sOperation As String) As CWSDLOperation
Dim Reader As WSDLReader
Dim EnumService As EnumWSDLService
Dim Service As WSDLService
Dim EnumPort As EnumWSDLPorts
Dim Port As WSDLPort
Dim EnumOperation As EnumWSDLOperations
Dim Operation As WSDLOperation
Dim EnumMapper As EnumSoapMappers
Dim Mapper As SoapMapper
Dim Fetched As Long
Dim objWSDLOperation As CWSDLOperation
Dim objOperationPart As COperationPart
Dim bAddParts As Boolean
Set objWSDLOperation = New CWSDLOperation
Set Reader = New WSDLReader
Reader.Load WSDLFileName, WSMLFileName
Reader.GetSoapServices EnumService
EnumService.Next 1, Service, Fetched
Do While Fetched = 1
Service.GetSoapPorts EnumPort
EnumPort.Next 1, Port, Fetched
Do While Fetched = 1
Port.GetSoapOperations EnumOperation
EnumOperation.Next 1, Operation, Fetched
Do While Fetched = 1
//check to see if the operation is here
bAddParts = False
If InStr(1, Operation.soapAction, "." + sOperation) > 0 Then
With objWSDLOperation
Set .m_Parts = New Collection
.m_PortAddress = Port.address
.m_SoapAction = Operation.soapAction
End With
bAddParts = True
Operation.GetOperationParts EnumMapper
EnumMapper.Next 1, Mapper, Fetched
Do While Fetched = 1
If bAddParts Then
Set objOperationPart = New COperationPart
objOperationPart.m_Name = Mapper.partName
Call objWSDLOperation.m_Parts.Add(objOperationPart)
End If
EnumMapper.Next 1, Mapper, Fetched
Loop
End If
EnumOperation.Next 1, Operation, Fetched
Loop
EnumPort.Next 1, Port, Fetched
Loop
EnumService.Next 1, Service, Fetched
Loop
Set BuildOperation = objWSDLOperation
End Function
| Function buildBuildOperation() parses the WSDL file and gathers information about theservice: name, parameters, namespaces used, etc and finally returns aCWSDLOperation object.
With this information we can move next to build the SOAP requestand invoke the web service. The service is invoked by calling Executemethod on CWSDLOperation object. In my example the Execute method willsimply print the result of the add operation. In my example the rule I applied for finding the right methodand passing the parameter is pretty simple but in a real applicationyou can implement more sophisticated mechanisms or assume there are fewpatterns for each method naming. Here is the code for the CWSDLOperation class.
|
Option Explicit
Private Const WRAPPE
R_ELEMENT_NAMESPACE = ""
Public m_PortAddress As String
Public m_SoapAction As String
Public m_Parts As Collection
Public Sub Execute()
If m_SoapAction <> vbNullString Then
On Error GoTo ErrorHandler
Dim Serializer As SoapSerializer
Dim Reader As SoapReader
Dim Connector As SoapConnector
Dim part As COperationPart
Dim sMethod As String, sNamespace As String
Set Connector = New HttpConnector
Connector.Property("EndPointURL") = m_PortAddress
Connector.Property("SoapAction") = m_SoapAction
Connector.BeginMessage
Set Serializer = New SoapSerializer
Serializer.Init Connector.InputStream
sMethod = Mid$(m_SoapAction, InStrRev(m_SoapAction, ".") + 1)
sNamespace = Left$(m_SoapAction, InStr(m_SoapAction, "/action") – 1)
Serializer.startEnvelope
Serializer.startBody
Serializer.startElement sMethod, sNamespace + "/message/", , "m"
For Each part In m_Parts
Serializer.startElement part.m_Name
Serializer.writeString "20"
Serializer.endElement
Next
Serializer.endElement
Serializer.endBody
Serializer.endEnvelope
Connector.EndMessage
Set Reader = New SoapReader
Reader.Load Connector.OutputStream
If Not Reader.Fault Is Nothing Then
MsgBox Reader.faultstring.Text, vbExclamation
Else
Debug.Print Reader.RPCResult.Text
End If
End If
Exit Sub
ErrorHandler:
MsgBox "ERROR: " & Err.Description, vbExclamation
Err.Clear
Exit Sub
End Sub
COperationPart class is very simply:
Option Explicit
Public m_Name As String
| If you want tosimplify the code you can substitute the COperationPart class with aString variable. There are more fields that can be added to theCOperationPart class but I removed them for simplicity of the code. Theother information available in the WSDL file for a OperationPart are:
- elementName To test the sample application you need to build 2 simple Web serviceswith STK MathLib1 and MathLib2. MathLib1 implements add method andMathLib2 implements addNumbers method. Both methods accept 2 parametersas double values. After you create these two web services change the namespace inone of them so something else than default, so you replicate a realsituation. Create a VB project, add the two classes, than add a form, onthe form add a button and insert the following code in his click event. |
Private Sub cmdCallServices_Click()
Call BuildOperation("C:\work\xarea\soap\MathLib\MathLib1\MathLib1.WSDL", _
"C:\work\soap\MathLib\MathLib1\MathLib1.WSML", "add").Execute
Call BuildOperation("C:\work\xarea\soap\MathLib\MathLib2\MathLib2.WSDL", _
"C:\work\soap\MathLib\MathLib2\MathLib2.WSML", "add").Execute
End Sub
Compile and you are ready to go!
I hope this article will help better understand web services and SOAP.




14. Feb, 2006 by 







No comments yet... Be the first to leave a reply!