|
Handling state from VB.6 and VB.NET SOAP clients
Ioulia
Doumkina Software Developer, IBM Canada 01 November
2003
One of the most popular patterns for use in J2EE server
applications is the Stateful Session Facade. But how do you take
advantage of stateful session beans when SOAP doesn't support state?
This question is especially relevant to software development today where
Web Services are becoming popular for connecting Visual Basic (VB) 6 and
.NET SOAP clients to J2EE engines. The solution described in this
article involves using SOAP headers for passing controllers in
serialized form.
Web Services are becoming extremely popular not only in the software
development world, but also among customers. In this age of globalization,
sharing information has become extremely important. Large companies want
to connect their VB or .NET applications with their partner’s J2EE
engines. Web Services provide the means for software to interoperate
across different platforms and programming languages. Ironically,
interoperability has not yet become seamless due to the differences in Web
Services implementations between different vendors. Furthermore, SOAP
doesn't preserve state, which makes the task even more challenging. The
concept of state is especially relevant for J2EE server applications,
which frequently expose their business processes as stateful session
beans. Nevertheless, interoperability is achievable and state can be
preserved with the help of SOAP headers and the magic of serialization.
This article will focus on interfacing stateful session beans from VB and.
NET desktop clients.
Developing a SOAP client in VB
6.0 Developing a SOAP client in VB requires installation of
the Microsoft SOAP Type Library, which can be downloaded from the
Microsoft Web site. In the examples below, I have used the Microsoft Soap
Toolkit v3.0. The Microsoft SOAP Type Library doesn't include the header
implementation, but only an interface.
Implementing a SOAP Header with
the Microsoft SOAP Type Library 3.0 in VB 6.0 One approach
would be to create a separate DLL that would consist exclusively of the
header implementation and ship this implementation to the client as part
of the product, as shown in Listing 1. In
this example, you could call the DLL VBHeaderHandler.dll. Listing 1. Example of header implementation in VB
6.0
Implements IHeaderHandler
Option Explicit
Public HeaderValue As String
Private Function IHeaderHandler_readHeader(
ByVal par_Reader As MSSOAPLib30.ISoapReader,
ByVal par_HeaderNode As MSXML2.IXMLDOMNode,
ByVal par_Object As Object) As Boolean
IHeaderHandler_readHeader = False
End Function
Private Function IHeaderHandler_WillWriteHeaders() As Boolean
IHeaderHandler_WillWriteHeaders = True
End Function
Private Sub IHeaderHandler_writeHeaders( _
ByVal pSerializer As SoapSerializer30, _
ByVal pObject As Object)
pSerializer.StartHeaderElement "SoapHeaderHandler", "http://www.ibm.com"
pSerializer.StartElement "SoapHeaderHandler"
pSerializer.WriteString HeaderValue
pSerializer.EndElement
pSerializer.EndHeaderElement
End Sub
|
Passing serialized controller as
part of the header in VB 6.0 On the client side you can
instantiate the VBHeaderHandler class, set the HeaderValue to the base64
encoded serialized controller and, eventually, set the HeaderHandler
property of the SoapClient30 to the instance of the HeaderHandler class.
As in the code example in Listing 2, you
can first store a serialized controller in a string variable, then assign
this variable to the HeaderValue variable. Listing
2. Example of using headers to pass serialized controllers in VB
6.0
Dim objSoapClient As SoapClient30
Set objSoapClient = CreateObject("MSSOAP.SoapClient30")
objSoapClient.MSSoapInit "http://server1:9080/MyTest/TestControllerEJBService.wsdl",
"TestControllerEJBService"
Dim strSerializedTestController as String
strSerializedTestController =
objSoapClient.getSerializedTestController("John","password")
Dim objHeaderHandler as VBHeaderHandler.clsVBHeaderHandler
Set objHeaderHandler = CreateObject("VBHeaderHandler.clsVBHeaderHandler")
objHeaderHandler.HeaderValue = strSerializedTestController
'now let's try to invoke the same controller
Set objSoapClient.HeaderHandler = objHeaderHandler
Dim strUserName as String
strUserName = objSoapClient.getUserName()
MsgBox(strUserName)
|
Requirements on the server side
and interoperability tips On the server side you will need
to create a SOAP provider that will intercept the SOAP message, extract
the serialized controller from the header, and deserialize it.
Furthermore, you will need to add data type information to the deployment
descriptor (dds.xml) , since SoapClient30 doesn't include data type
information in the SOAP message
Developing a SOAP client in
VB.NET One useful .NET feature is the ability to create
proxies. You create them once, refresh when the API changes, and deliver
to the client. No more initializing WSDL files, and no need to recollect
the signature calls from the WSDL files. Furthermore, no need to use the
dds.xml files, since all data type information is now included in the SOAP
message.
Personally, I prefer to generate proxies using the WSDL.exe tool, since
it automatically adds the property "Url", that is very handy (this
property allows you to dynamically specify the location of the exposed
services). This can be convenient if you want to ship your proxies as part
of your product.
Header implementation in
VB.NET Implementing headers with .NET Web Services is very
straightforward. Writing headers is simplified to just creating a class
that inherits from SoapHeader and including a public variable HeaderValue,
which represent the header entry, as shown in Listing 3. Listing 3. Example of header implementation in
VB.NET
Imports System.Web.Services
Imports System.Web.Services.Protocols
Public Class SoapHeaderHandler
Inherits SoapHeader
Public HeaderValue As String
Public Sub New()
MyBase.New()
End Sub
End Class
|
In this example, you could save it as NetHeaderHandler.dll.
Creating and modifying Web
Services proxies. After creating NetHeaderHandler.dll, you
are ready to change your proxies that you created using WSDL.exe. The
command used to generate your proxies is shown in Listing 4 (this
command should be all on one line). Listing 4.
Command for generating proxies
wsdl /language:VB /namespace:ibm.com
http://server1:9080/MyTest/TestControllerEJBService.wsdl
|
Once you have created your proxies, you need to modify them to include
header information. Modifying a proxy involves two steps (see also
Listings 5 and 6):
- Adding a public member variable of type
NetHeaderHandler.SoapHeaderHandler
- Inserting a SOAP header attribute.
Listing 5. Example of header declaration in
VB.NET
Public headerValue As NetHeaderHandler.SoapHeaderHandler
|
Adding header
attributes Deciding how to add a header attribute is not
easy, because header attributes are not well documented by Microsoft, and
there are very few good examples available on how to use them. In most
cases, you will end up with something that looks like Listing 6. Listing 6. Example of a header attribute
System.Web.Services.Protocols.SoapHeaderAttribute("headerValue", _
Direction:=System.Web.Services.Protocols.SoapHeaderDirection.In, Required:=True), _
System.Web.Services.Protocols.SoapRpcMethodAttribute("",
RequestNamespace:=
"http://ibm.com/myarticle.myarticlecontrollers. TestControllerEJB",
ResponseNamespace:=
"http://ibm.com/myarticle.myarticlecontrollers. TestControllerEJB")
|
Build this and save it as NetProxies.dll.
Passing serialized controller as
part of the header in VB.NET One you are done with modifying
your proxies, you are ready for the final step -- invoking a J2EE server
application through a .NET client application (see Listing
7). Listing 7. Example of client side code in
VB.NET
Dim strURL as string
strURL = "http://server1:9080/TestWebServices/servlet/rpcrouter"/"
Dim oNetProxy As New NetProxies.ibm.com.TestControllerEJBService()
oNetProxy.Url = gstrURL
'invoke my controller and return it in serialized form
Dim strSerializedTestController as string
strSerializedTestController =
oNetProxy.getSerializedTestController("John","password")
Dim oNetHeaderHandler as New NetHeaderHandler.SoapHeaderHandler
oNetHeaderHandler.HeaderValue = strSerializedTestController
oNetProxy.headerValue = oNetHeaderHandler
Dim strUserName as string
strUserName = oNetProxy.getUserName()
|
Summary This article
has covered how to connect to a J2EE server application, which uses
stateful session beans as part of its architecture. To invoke the same
bean, you used headers for both a Visual Basic 6.0 Soap Client and a
VB.NET Soap Client. Also listed were some tips on how to overcome
interoperability issues which arise when using a Microsoft Soap Client and
a WebSphere Soap Server.
Resources
About the
author Ioulia Doumkina is a Software Developer in the IBM
Ottawa Lab, eRecordsManager Team. You can contact Ioulia at Ioulia_doumkina
at ca.ibm.com. |
|
|