SOAPState Sample: Uses ATL Server to Implement Persistent SOAP Servers
Demonstrates how to implement a persistent SOAP server.
The SOAPState sample shows how to use the following:
IServiceProvider interface implemented by CIsapiExtension
The sample shows a method of loading the state of a SOAP server before a method invocation and of saving the state immediately after the invocation. The state of the SOAP server is preserved in memory. The code can be easily modified to store the state in a database or a file. A specific service is implemented in the CIsapiExtension-based class of the ISAPI DLL project to allow serialization of the SOAP servers.
This sample code is provided to illustrate a concept and should not be used in applications or Web sites, as it may not illustrate the safest coding practices. Microsoft assumes no liability for incidental or consequential damages should the sample code be used for purposes other than as intended.
Building and Running the Sample
To build and run this sample
Open the solution file, SoapState.sln, in the Visual Studio development environment.
Build the solution.
This will build SStateIsapi.dll, an ISAPI extension containing the ISOAPSrvStorageService, and SState.dll, an example of a persistent SOAP server using the ISOAPSrvStorageService. It will also build demoApp.exe, a small client application showing how to access a persistent SOAP server.
Run the console application demoApp.exe. You will see a series of output messages relating the communication with the server.
If you map the virtual folder under a different name or on a different computer, you will need either to regenerate the demoApp proxy file (simpleSoapApProxy.h) or add the following to the demoApp.cpp file, before executing any SOAP invocation:
srv.SetUrl( "http://< machine_name>/<folder_name>/SState.dll?Handler=Default");
How the Sample Works
Each persistent SOAP server has to implement a specific interface. This interface (IPersistSoapServer) contains two sets of methods. (Implementation of these methods should not be different from the implementation provided with the sample.)
Methods Exposed Through SOAP
The first set of methods is exposed through SOAP:
[id(1)]HRESULT initPersistSoapServer([in]BSTR bstrUser, [in]BSTR bstrPwd, [out, retval]eState* state); [id(2)]HRESULT destroyPersistSoapServer([in]BSTR bstrUser, [in]BSTR bstrPwd); [id(3)]HRESULT setPersistSoapServerTimeout([in]DWORD dwTimeoutSecs);
Only the first method, initPersistSoapServer, must be implemented and called to have persistence. If the client application does not call destroyPersistSoapServer, the persistent object will be destroyed at timeout. If the client application does not call setPersistSoapServerTimeout, a default timeout value will be assigned.
The initPersistSoapServer method generates a unique value for a SOAP header defined as:
It takes the default parameters, in="true" and out="true", that will be applied to each SOAP method, so it will be sent both ways in each method invocation. Whenever a client application will invoke a SOAP method, the m_bstrStorageKey header will be part of the invocation. If, during the lifetime of one persistent SOAP server, two client applications use the same bstrUser and bstrPwd parameters for the initPersistentSoapServer method, the two applications will be connected to the same instance of the persistent object. If the parameters are different, different instances are created on the server side. If one client application invokes the initialization method with NULL as bstrUser and bstrPwd, then the persistent object created cannot be identified by the other application. It will be accessible only for the client that created it.
Once a SOAP invocation occurs, the following should appear in any SOAP method to ensure the persistent state is loaded:
CPersistentHandler persistHandler(static_cast<IPersistSoapServer*>(this), m_spServiceProvider);
The CPersistentHandler object resides on the stack, so it will be destroyed when the method ends. On destruction, it will take care of saving the state of the server.
Methods Not Exposed Through SOAP
In the constructor/destructor of the CPersistentHandler object, the second set of methods in IPersistSoapServer, not exposed through SOAP, are used:
HRESULT getObjToken(storageKey& token); HRESULT setObjToken(storageKey& token); HRESULT persist_load(const ATLSOAP_BLOB &data); HRESULT persist_dump(ATLSOAP_BLOB &data);
getObjToken is called while attempting to restore the state of the object, and it is supposed to return the value of the m_bstrStorageKey header to act as a storage key for the state of this server.
persist_load is also called while attempting to restore the state of the object, to load the state of the server from the saved binary BLOB.
persist_dump is called while attempting to save the state of the object, to serialize the object in the provided binary BLOB.
setObjToken is called only during initPersistSoapServer, to set the value of the m_bstrStorageKey for the communication.
Internally, the CPersistentHandler object connects to ISOAPSrvStorageService (defined in the persist.h file of the sample) provided by the ISAPI extension and simply sends binary BLOBs for storage under a specific key or retrieves the BLOBs based on the same key.
Although this sample stores the BLOBs in memory by modifying the implementation of ISOAPSrvStorageService, the SOAP server state can also be preserved in a database or a file.