![]() |
Web Development »
ATL Server »
General
Advanced
SOAPing without a Web ServerBy Bogdan CRIVATDemonstrates how to use ATL Server to build SOAP servers/clients over various transport channels. |
VC7, Windows, .NET 1.0, Dev
|
|
Advanced Search |
|
|
|
||||||||||||||||
ATL Server is a new set of classes in ATL for creating Web Applications and Web Services. These Web Services are completely compatible with clients written in C++, C#, VB and other tools that can call a Web Service through SOAP. The Web Service support in ATL Server only supports invocation over an HTTP tranport for this version, however like the rest of ATL, ATL Server is designed to be very flexible. You may wish to create Web Services which can be called over other transport mechanisms, such as TCP/IP, and this article will help explain how you would go about changing the default transport ATL Server supports for Web Services. Two examples are included, one implementing a Web Service which can be called over TCP/IP and another sample which uses a Floppy Disk for the transport
This article shows how to separate the SOAP support offered by ATL Server from the ISAPI framework, allowing use of ATL Server to build SOAP servers and clients over virtually any communication channel.
Summary:
The ATL Server Web Service Wizard will generate the code for a Web Service exposed through HTTP. The Web Service is implemented as a class with the following declaration:
[ request_handler(name="Default", sdl="GenSimpleSoapAppServiceSDL"), soap_handler( name="SimpleSoapAppService", namespace="urn:SimpleSoapAppService", protocol="soap" ) ] class CSimpleSoapAppService : public ISimpleSoapAppService
In this code sequence, the attributes before the class declaration do most of the exposing.
The soap_handler attribute will inject the following methods : DispatchSoapCall,
ParseSoapHeaders and __AtlGetSDL. These methods are required for required for
handling SOAP messages and mapping them to internal method calls and also for wrapping the result of
internal methods invocations to SOAP responses. (The MSDN library coming with Visual Studio.NET 7.0 Beta1
contains details on the code injected by this attribute).
The request_handler attribute will make it able to handle HTTP requests. If the transport layer is not going to be HTTP, the
request_handler attribute is no longer needed, so it can be commented out.
The CSoapHandler<> class in atlsoap.h is designed to handle SOAP requests
through HTTP. The entry point for handling an HTTP SOAP request is:
HTTP_CODE HandleRequest(AtlServerRequest *, IServiceProvider *)
The request body and the SOAP related HTTP header ("SOAPAction") are retrieved from the ISAPI extension through
the pServerRequest(an ECB wrapper)member of the AtlServerRequest* parameter.
The pServerRequest object provides methods from reading the request body, reading the SOAPAction
HTTP header and writing the SOAP response back to the client. As the purpose is to replace the HTTP transport,
we need to find another way to launch the SOAP request processing and to provide it with a way of performing
the same operations.
This is solved by creating a CSoapHandler derivative, CSoapTransportHandler,
that implements the following entry point (file SoapTransportSrv.h of the downloadable code):
HTTP_CODE InvokeSoapMethod(stSoapTransportDescription *pTransInfo)
And the stSoapTransportDescription structure is defined as:
struct stSoapTransportDescription { // the stream to write the SOAP response to IWriteStream *pWriteStream; // the stream to read the SOAP request from IStream *pReadStream; // the SOAP Action CStringA strSOAPAction; // the service provider IServiceProvider *pServiceProvider; };
Perhaps the only member that needs a few details is pServiceProvider. It allows the SOAP servers to share services exactly as those in an ISAPI dll. It can be NULL in an implementation, as long as the SOAP servers will not attempt to use it.
Now, the SOAP server class generated by the wizard has to be modified to use the new CSoapTransportHandler
functionality. The new code would look like:
[ //request_handler(name="Default", sdl= "GenSimpleSoapAppWSDL"), soap_handler( name="SimpleSoapAppService", namespace="urn:SimpleSoapAppService", protocol="soap" ) ] class CSimpleSoapAppService : public CSoapTransportHandler<CSimpleSoapAppService>, public ISimpleSoapAppService ...
There is no other modification that has to be done in the wizard-generated server code.
Right now, the SOAP server can be instantiated and the SOAP methods can be invoked through
CSoapTransportHandler::InvokeSoapMethod, therefore with custom streams to read from and write to,
and it does not depend on the ATL Server HTTP support anymore.
The instantiation of the server(s) is handled by another class, CSoapDispatcher,
implemented in the soapDispatch.h file. The CSoapDispatcher class fills a
stSoapTransportDescription structure, then instantiates a SOAP server and invokes a
SOAP call like below
stSoapTransportDescription transInfo; // set the transInfo stream pointers ... CComObjectNoLock<CSimpleSoapAppService> srv; HRESULT hRet = S_OK; try { hRet = srv.InvokeSoapMethod( &transInfo ); } catch(...) ...
At this point, a server application only has to:
IStream interfaceIWriteStream to store the responseCSoapDispatcher::DispatchCallThe SOAP proxy class generated by sproxy.exe has the following prototype:
class CSimpleSoapAppService : public CSoapSocketClient ...
By inspecting the code generated by sproxy.exe, one can notice that only a few methods/members
of the CSoapSocketClient are actually used by the proxy class. These would be
HRESULT SendRequest(LPCTSTR tszAction) throw()void Cleanup() throw()m_Stream, used as an IStream interface to store the request before sendingm_ReadStream, used as an IStream interface to store the response before parsingThe method that does most of the work here is SendRequest. This method is supposed
to send the request from m_Stream to the SOAP server and to fill m_ReadStream with
the server response. By replacing (in the sproxy.exe generated file) CSoapSocketClient with
a custom class that contains all these methods and attributes, the actual channel used to send the request
to the SOAP server only depends on the implementation of the SendRequest method.
It is exactly what happens in the attached sample code. To reuse the sproxy.exe generated code for such different transport classes, the following modification would be useful:
template<TTransportClass> class CSimpleSoapAppService : public TTransportClass ...
The sample implements the following transport channels:
Each transport channel implementation contains a client application and a server application.
The server uses the SOAP server included in the Include folder (which is built as described above).
The code in the server application only takes care of the transport. The client application only
implements the transport specific class to act as a TTransportClass parameter for the modified
class generated by sproxy.exe
Please note that the modifications specified above only allow sending/receiving SOAP messages over the custom channel. They do not allow retrieving the description (SDL) for the service. Therefore, a limitation of the TCPIPTransport and FloppyTransport samples is that the SDL used in generating the proxy has to be generated outside of the sample. The one used in the applications specified above is saved as simpleSoapSrv.wsdl in the Include folder. To get the server description, one would have to create the SOAP server through the wizard, complete the interface, then save the SDL through the default HTTP way provided by ATL Server.
This folder contains an enhanced version of the TCPIPTransport server. This server
listens on a specified TCPIP port, but it accepts HTTP requests. It provides a way of responding to
.disco requests, to generate the SDL for the implemented SOAP servers and also to accept SOAP invocations.
This server can provide a very light-weight, complete, SOAP implementation, without requiring an HTTP
server to be installed on the machine. To create a client for this light server, just use the Add Web Reference
wizard from the Visual Studio.NET 7.0 Beta1 IDE, and point the wizard to the following URL:
http://<your_machine>:<ListenPort>/disco
If you build the HTTPListenerServer sample, the URL would become:
http://localhost:333/disco
The C# client provided for this server (HttpListenerCSharpClient) is generated this way
An updated version of the sample code will be included as an ATL Server sample starting with Visual Studio.NET Beta2. It will add the following :
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 17 May 2001 Editor: Chris Maunder |
Copyright 2001 by Bogdan CRIVAT Everything else Copyright © CodeProject, 1999-2009 Web12 | Advertise on the Code Project |