SOAP FAQ


The following sections contain FAQ relating to ATL Server and SOAP.

How Do I Make a SOAP Client Point to a Different URL?

Briefly, you do this by calling SetUrl on the SOAP proxy class and passing the new URL as a parameter.

The class generated by sproxy.exe has a URL hard-coded in the constructor. This is the URL contained by the input WSDL document under the soap:location field. However, the proxy class doesn t actually perform the transport and, therefore, it isn t using the URL to perform the HTTP connection. The SOAP proxy class is defined as follows :

 template <class THttpClient>  class CMyServiceT : public THttpClient 

The preceding definition allows invoking any public method of the HTTP client class on the SOAP proxy class.

It s the HttpClient template parameter class that handles the connection and uses the URL to connect to the SOAP server. So, changing the URL is actually something that has to be supported by the HTTP client class.

This transport class has to conform to the SOAP client archetype (described in MSDN under the ATL Server library reference). The definition of the archetype specifies only that this class should take a URL as a constructor parameter, to support the hard-coded URL described previously. A method allowing the changing of the URL isn t a requirement under the archetype definition in MSDN, but all three implementations of the SOAP client archetype that come with ATL Server implement the SetUrl method.

How Do I Use an HTTP Proxy in a SOAP Client?

Briefly, you do this by calling SetProxy on the SOAP proxy class and passing the proxy server and the port as parameters.

Very much like SetUrl (the function described in the previous section), SetProxy is not a SOAP client archetype requirement; rather, it s a method implemented by the CSoapSocketClientT and CSoapWininetClient classes that come with ATL Server.

It also has an implementation (albeit a nonfunctional one) in the CSoapMSXMLInetClient class. To set the HTTP proxy for the ServerXMLHTTP component, please see the MSDN article titled Using the WinHTTP Proxy Configuration Utility (http://msdn.microsoft.com/library/en-us/xmlsdk30/htm/serverxmlhttpproxy.asp).

How Do I Use SOAP over a Custom Transport Protocol?

The SOAP transport sample in MSDN covers this topic. The sample provides a low-level way of directly using the SOAP infrastructure classes in ATL Server in a stand-alone application.

An alternate mechanism for controlling the SOAP transmission is presented in Chapter 23. It s a higher-level approach that basically consists of writing a stand-alone application that encapsulates the functionality of an ISAPI DLL, meaning it loads a prebuilt SOAP application DLL and launches the SOAP request-handling code in the same way a Web server would.

How Do I Use WinINet, ServerXMLHTTP, or a Custom HTTP Stack in a SOAP Client?

The typical SOAP proxy class, generated by sproxy.exe, is defined as follows:

 template <class THttpClient>  class CMyServiceT : public THttpClient 

It is the THttpClient template parameter class that handles the connection and uses the URL to connect to the SOAP server. So, changing the URL is actually something that has to be supported by the HTTP client class.

Also, the sproxy.exe-generated header contains a specialization of the preceding template:

 typedef CMyServiceT<CSoapSocketClientT<> > CMyService; 

Most applications use CMyService as a proxy class ”that is, the specialization based on the CSoapSocketClientT HTTP client, the lightweight SOAP HTTP client that comes with ATL Server. However, you can use different HTTP stacks by passing different template parameters when instantiating the SOAP proxy. Two such alternate HTTP stacks, based on the WinINet and ServerXMLHTTP libraries, are available in ATL Server. They are CSoapWininetClient (using WinINet) and CSoapMSXMLInetClient (using ServerXMLHTTP, which comes with MSXML 3.0 or higher). To use these classes, you ll have to change the typical client code, which looks like this:

 CMyService soapProxy; 

and make it look like this:

 CMyServiceT<CSoapWininetClient> soapProxy; 

You don t have to use one of the ATL Server “provided classes for your HTTP communication. You can implement your own class or use a third-party transport class, as long as it conforms to the SOAP client archetype described in MSDN at ms-help://MS.VSCC/MS.MSDNVS/vclib/html/vclrfatlserversoapclientarchetype.htm .

How Do I Use HTTPS/SSL in a SOAP Client?

The default SOAP transport client, CSoapSocketClientT < > , doesn t support SSL. However, HTTPS URLs and secure communication are supported by the alternate transport classes that use the WinINet and the ServerXMLHTTP libraries, respectively. So, the typical client code that looks like this:

 CMySoapProxy    srv; 

should be changed to look like this:

 CMySoapProxy<CSoapWininetClient> srv; 

or this:

 CMySoapProxy<CSoapMSXMLInetClient> srv; 

Also, the SecureSOAP sample that ships as part of ATL Server shows a way to use a custom, SSL-enabled socket class for performing HTTPS communication with the lightweight CSoapSocketClientT class.

The recommended way of doing SSL is by using CSoapMSXMLInetClient , as the ServerXMLHTTP library is designed to be used both in server applications and in client applications.

How Do I Select a Specific Certificate for an SSL Connection?

Like setting the proxy and changing the SOAP server s URL, specifying the certificate to be used in a secure HTTP connection is very specific to the transport class used for SOAP communication. We demonstrate how to do so here for the CSoapMSXMLInetClient class, which is the recommended class to use when performing secure SOAP with ATL Server. The client code should look like this:

 CMyProxyClassT<CSoapMSXMLInetClient> srv;  // Invoking with the default settings.  // MSXML looks in the certificate store and  // uses the first available certificate  hRet = srv.InvokeMethod( params);  if( FAILED(hRet) )  {      CComVariant certFriendlyName;      // This way you can force the MSXMLInetClient      // to use a specific certificate      certFriendlyName.bstrVal =           ::SysAllocString(L"Some Specific Certificate's Friendly Name");      hRet = srv.m_spHttpRequest->setOption(             SXH_OPTION_SELECT_CLIENT_SSL_CERT,             certFriendlyName);  }  // Calling again, with the new client certificate  hRet = srv.InvokeMethod(params); 

Please note that, due to a design bug, you can t call SetOption before the first invocation, because the m_spHttpRequest pointer member of CSoapMSXMLInetClient is instantiated only on the first request.

By default, the CSoapMSXMLInetClient class will use the first certificate in the local store (and that one will be used to negotiate the first invocation).

How Do I Access the Client s Certificate in a SOAP Server?

We ve already presented the generic solution for this problem in the Generic ATL Server Application FAQ section of this chapter. The only SOAP server “specific part is getting the pointer to the ECB.

You learned earlier that the ECB for the current HTTP request is preserved in the AtlServerRequest structure that s passed as a parameter to the HandleRequest method. A SOAP server class inherits from the CSoapHandler class, and CSoapHandler s HandleRequest doesn t cache the AtlServerRequest parameter, so you ll have to do this.

Start by adding a new member to your SOAP server class, defined as follows:

 AtlServerRequest m_RequestInfo; 

Then override the HandleRequest method. Don t forget to call the default implementation after caching the parameter.

 HTTP_CODE HandleRequest(AtlServerRequest *pRequestInfo,                IServiceProvider * pProvider)  {          // copy the AtlServerRequest into the safe version          memcpy(&m_RequestInfo, pRequestInfo, sizeof(m_RequestInfo) );          return __super::HandleRequest(pRequestInfo, pProvider);  } 

Now m_RequestInfo contains a copy of AtlServerRequest for the current request, therefore you can obtain the ECB as m_RequestInfo.pECB .

How Do I Use Custom Encryption/Compression with SOAP?

On the client side, you can achieve this by writing a custom SOAP transport class. As we mentioned in previous sections of this chapter, a custom SOAP transport class should conform to the SOAP client archetype, as described in the MSDN documentation. What you want to do here is not necessarily replace the HTTP transport mechanism, but extend it by adding encoding capabilities (such as encryption or compression). This is why the simplest way of getting a custom SOAP transport class is to inherit from an existing one ”say, inherit from CSoapSocketClientT (if you decide to inherit from another transport class, the same functions should be overridden).

The code generated by sproxy serializes the SOAP request into the stream returned by the transport class s GetWriteStream method. So, to get a SOAP payload to be in any way encoded (encrypted and/or compressed) before sending it to the server, you ll have to override the GetWriteStream method and return your own IWriteStream derivative. This class will perform the encoding (either on-the-fly or by storing the entire payload in memory and encoding it all at once).

Now, the other method to be overridden is SendRequest . This can preserve most of the code from the base class s SendRequest . Due to optimization issues, the code that comes with ATL Server assumes that the stream returned by GetWriteStream is a CWriteStreamOnCString class and uses CWriteStreamOnCString::m_str for sending the actual request s body. You ll have to replace this with some call to a method returning the encoded (encrypted and/or compressed) body from your stream class. Optionally, your new SendRequest implementation might send some other HTTP headers to warn the server of the encoding used in the request s body.

On the server side, the easiest way of matching the client encoding is to write an ISAPI filter, which can identify the encoded requests and decode them before passing them to the actual SOAP server. The MSDN documentation contains detailed information about building an ISAPI filter, and the ISAPIFilter sample that comes with ATL Server shows how to build a filter using the ATL Server classes.

An alternate solution (which involves some extra work) is to modify the SOAP server s HandleRequest method. You would have to use almost exactly the original code from atlsoap.h ( CSoapHandler::HandleRequest , starting at line 6379). You should replace the code that instantiates a stream wrapper on top of the HTTP request with code to instantiate your custom stream class, which, besides reading from the request s body, will perform decoding. So, the following line (6412 in atlsoap.h):

 CStreamOnServerContext s(pRequestInfo->pServerContext); 

will be modified in your overridden HandleRequest with something like this:

 CDecodingStreamOnServerContext s(pRequestInfo->pServerContext); 

How Do I Develop an Asynchronous SOAP Client?

This subject is described in detail by some of the authors of this book in an article entitled Using ATL Server to Build an Asynchronous SOAP Client in Unmanaged C++ (http://msdn.microsoft.com/msdnmag/issues/02/04/SOAP/default.aspx). This article explains how to asynchronously invoke SOAP methods and then, upon completion, collect the results.

How Do I Send XML Fragments/Unescaped Strings As Part of a SOAP Message?

This question arises often from the need to send preformatted XML documents as function parameters.

In Chapter 23 in the Custom Data Types Marshaling section, you learned a way of extending the ATL Server SOAP infrastructure to support the GUID type exactly like any other built-in type. The answer to this FAQ (how to send unescaped strings as part of SOAP messages) is very similar to the method described in Chapter 23.

You ll have to define a custom type, say SOAPTYPE_RAWSTRING , by following the steps you used to define SOAPTYPE_GUID in the aforementioned section. There is a difference, though. As GUID was a completely new type, you could rely on the compiler to load the appropriate instantiation of the template function AtlGenXMLValue when serializing. The unescaped string is still a string (a BSTR, actually), so the compiler will use the existing serialization code for BSTR, which escapes XML content. The solution to this problem is to not rely on the compiler for this. You ll start by defining the following:

 inline HRESULT AtlGenRawStringXMLValue (                   IWriteStream *pStream, wchar_t **pVal) 

This function should inherit most of the code from the existing string implementation:

 inline HRESULT AtlGenXMLValue<wchar_t *>(                 IWriteStream *pStream, wchar_t **pVal) 

but it shouldn t contain the EscapeXML part, which actually performs the escaping.

Now, you should modify the serialization code for AtlSoapGenElementValue by adding the following branch:

 case SOAPTYPE_RAWSTRING:    hr = AtlGenRawXMLValue(pStream, (BSTR*)&pVal);    break; 

This doesn t cover the parsing of unescaped XML, so the deserialization for the new SOAPTYPE_RAWSTRING type will be the same as for regular strings. This is the default behavior for an unknown type that isn t an error and isn t SOAPTYPE_USERBASE . However, the correct way to do this is to add a branch to the case instruction in AtlSoapGetElementValue , as follows:

 case SOAPTYPE_RAWSTRING:    hr = AtlGetSAXValue((BSTR *)pVal, wsz, cch);    break; 

Now, once a SOAP proxy is generated, you can modify the maps from the generated code (see the instructions in the Custom Data Type Marshaling section in Chapter 23) and change SOAPTYPE_STRING to SOAPTYPE_RAWSTRING for the parameters that you don t want escaped in your SOAP payload.

How Do I Perform Custom Server-Side Parsing?

A solution for this problem is described in detail in Chapter 23 in the section Custom Parsing on the Server Side. That solution actually describes the answers for a couple of FAQ:

  • How do I parse XML sent as SOAP method parameters ( xsd:any )?

  • How do I reuse the main SAX parser?




ATL Server. High Performance C++ on. NET
Observing the User Experience: A Practitioners Guide to User Research
ISBN: B006Z372QQ
EAN: 2147483647
Year: 2002
Pages: 181

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