ATL Server Interoperability Limitations


In the previous section we covered generic interoperability issues that can and should be treated by any SOAP implementation. In this section we describe known limitations in the ATL Server implementation and ways to work around some of these limitations, when necessary.

Standard Basic Data Types Not Supported by ATL Server

Problems with the support of data types are usually best addressed from the client side, as a server will normally specify (via the WSDL) only types that are fully supported, and the client will have to comply with this specification. The solution presented here, however, will work equally well on the server and the client with the addition of just a few extra steps (discussed at the end of the section).

The ATL Server basic type support mainly focuses on those types that correspond directly with types in the C++ language. Some of the basic types included in the XML Schema Datatypes specification aren t directly supported, as they don t have a natural correspondent in C++ (e.g., xsd:dateTime ), whereas others are supported by including them into a superset that can be represented in C++ (e.g., xsd:nonPositiveInteger is represented as __int64 ). The MSDN documentation contains an article with a list of all the basic types supported by ATL Server: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/vcconatlserverwebservicetypemapping.asp.

One of the nice things about developing with ATL Server is that developers can use unsupported types. Therefore, if a developer finds the base implementation restrictive , he or she can write code to improve type support.

Also, for those types that are mapped to supersets (such as nonPositiveInteger , which will be represented as __int64 ), the developer can, if necessary, add appropriate restrictions and checks before executing the SOAP request. For example, a function like this:

 <message name="echoNonPositiveIntegerIn">    <part name="paramIn" type="s: nonPositiveInteger "/>  </message>  <message name="echoNonPositiveIntegerOut">    <part name="return" type="s:nonPositiveInteger"/>  </message> 

will generate (via sproxy.exe) the following code:

 HRESULT echoNonPositiveInteger(__int64 paramIn, __int64* return); 

And it can be easily wrapped in a different function that performs a check:

 HRESULT echoSafeNonPositiveInteger(__int64 in, __int64 *out)  {    if(in > 0)      return E_PARAM;    return echoNonPositiveInteger(in, out);  } 

Those types that aren t directly supported by ATL Server are treated as strings. Thus, you can use the same technique to wrap the function with some code that converts between the internal chosen representation format for the type and the string to be passed as a parameter. So for a type such as xsd:dateTime , the sproxy-generated code would look like this:

 HRESULT echoDateTime(BSTR bstrIn, BSTR* bstrOut), 

which you could wrap in something like this:

 HRESULT echoSafeDateTime(COleDateTime& dtIn, COleDateTime& dtOut)  {    CString strDateTime = dtIn.Format(   );    CComBSTR bstrIn;    BSTR bstrOut;    bstrIn.Append(strDateTime);    HRESULT hRet = echoDateTime(bstrIn, &bstrOut);    if(SUCCEEDED(hRet))    {      CW2A szNewTime(bstrOut);      dtOut.Parse(szNewTime   );    }    return hRet;  } 
Caution  

In most cases, there s a good reason why ATL Server doesn t try to map an xsd type onto a similar type in C++ (e.g., DateTime ). When you do these mappings yourself, be careful of sometimes subtle semantic differences between the types that make them less compatible than you might otherwise realize.

To create an ATL Server “based SOAP server that exposes a method using xsd:dateTime (or any other unsupported type), you could apply the same wrapping technique (i.e., writing a wrapper method that performs any required type checking). Take a method echoing an xsd:dateTime parameter, which internally will look like this:

 HRESULT echoDateTime(BSTR bstrIn, BSTR* pbstrOut); 

Now, the WSDL for this method will look like this:

 <message name="echoDateTimeIn">  <part name="paramIn" type="s: string"/>  </message>  <message name="echoDateTimeOut">  <part name="return" type="s:string"/>  </message> 

You can now save the WSDL as a file and manually make a few modifications. For example, you could change all the references to s:string to s:dateTime before publishing the WSDL. As a result, any client using the published WSDL would send a dateTime parameter. The server application would receive the dateTime parameter as a string and then be able to convert it into an internal time representation, process it, and convert it back into a string to marshal it back to the client.

Note  

At first glance, it may seem that all this marshaling to and from strings is going to be inefficient, but remember that SOAP is based on XML, which is a text protocol. Thus, this marshaling to and from strings has to happen regardless of whether the conversion happens in the ATL Server code or your own.

For a more detailed discussion on ATL Server SOAP marshaling, how to hook into the marshaler , and how you can use this to extend the type support, please see the section Custom Data Type Marshaling in Chapter 23.

WSDL Problems

This section covers workarounds for a few problems you may encounter when using WSDL documents that weren t generated by an ATL Server Web service. The problems we cover here are as follows :

  • Missing the soap:location section of the WSDL

  • Import / include directives in the WSDL document

The specification for WSDL documents mentions a special entry to describe the endpoint of the Web service. This endpoint is the URL to which the SOAP messages should be sent. This entry has the qualified name soap:address , soap being the prefix associated with the http://schemas.xmlsoap.org/wsdl/soap/ namespace. Here s an example:

 <port name="SomeServiceSoap" binding="s0: SomeServiceSoap">  <soap:address     location="http://localhost/SomeServer/SomeServer.dll?Handler=Default"/>  </port> 

This section of the WSDL document is required by the client generator tool (sproxy.exe) in order to generate the proxy class.

An example of a missing soap:location entry may be a WSDL designed to be used at multiple endpoints. For example, multiple Web servers may provide the same service, the central authority that coordinates the implementations will publish the common WSDL, and each server has to specify its own endpoint. In this situation, sproxy.exe will fail in generating the proxy class.

To work around this problem, the client developer will have to save the WSDL as a file, manually and add the following section (maybe including dummy data), then run sproxy.exe over the modified file:

 <definitions   >    <service name="TestServerService">      <port name="TestServerServiceSoap" binding="s0:TestServerServiceSoap">  <soap:address location="http://localhost/ "/>  </port>    </service>  </definitions> 

For now, it doesn t have to identify a valid URL; it s just a syntax element of the WSDL that s required for the WSDL to be accepted as valid. Of course, http://localhost/ will usually be an invalid Web service endpoint. Once the proxy class is generated, you can programmatically specify the URL, even at runtime, by calling into the SetUrl method of the generated class.

Quoting from the WSDL specification: WSDL allows associating a namespace with a document location using an import statement.

 <definitions   >    <import namespace= " uri "  location= " uri " />  </definitions> 

Such a mechanism allows, for example, separating the schema part of the WSDL (the types definitions) from the binding part (the messages and the endpoint description). For instance, if multiple services reuse the same type definitions, these can be isolated in a separate schema document and imported for each of the Web services.

The version of ATL Server that comes with Visual Studio .NET doesn t support the import mechanism. The client generator (sproxy.exe) in both releases is able to handle multiple schemas within the same WSDL document correctly.

To work around this issue on the client side, you have to download the WSDL(s) and the imported documents, save them as files, and insert the imported documents instead of the import directives. The WSDL documents are also selected from the WSDL specification. For example, assume that the WSDL looks like this:

 << service1.wsdl>>  <definitions   xmlns:xsd1=  "http://example.com/stockquote/schemas">    <import namespace="http://example.com/stockquote/schemas"       location="http://example.com/stock/schemas/quote.xsd"/>    <message name="GetLastTradePriceRequest">      <part name="body" element="xsd1:GetLastTradePrice"/>    </message>   </definitions> 

Also assume that the http://example.com/stock/schemas/quote.xsd document looks like this:

 <?xml version="1.0"?>  <schema targetNamespace=http://example.com/stock/schemas      xmlns=http://www.w3.org/2001/XMLSchema>    <element name="GetLastTradePrice">      <complexType>        <sequence>          <element name="tickerSymbol" type="string"/>        </sequence>      </complexType>    </element>   </schema> 

After you insert the imported document in the WSDL file, the result will look like this:

 << service1_with_import.wsdl>>  <definitions   xmlns:xsd1="http://example.com/stock/schemas">  <schema targetNamespace=http://example.com/stock/schemas   xmlns=http://www.w3.org/2001/XMLSchema>   <element name=  "  GetLastTradePrice  "  >   <complexType>   <sequence>   <element name=  "  tickerSymbol  "  type=  "  string  "  />   </sequence>   </complexType>   </element>       </schema>  <message name="GetLastTradePriceRequest">      <part name="body" element="xsd1:GetLastTradePrice"/>    </message>   </definitions> 

This document is now valid input for the sproxy.exe tool.

A Specific Interoperability Problem

Even between implementations that use the same XSD, there s a need for interoperability, as perfect interoperation isn t always 100 percent guaranteed . We describe such a problem, resulting from different interpretations of the XSD, in this section. In this case, the problem appears between an ATL Server “based server and an ASP.NET client application, in the scenario where the ATL Server Web service exposes a fixed size array of unsignedBytes .

The 2001 version of XSD contains the following definition for a byte (see http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/#unsignedByte):

3.3.24 unsignedByte definition: unsignedByte is derived from unsignedShort by setting the value of · maxInclusive to be 255. The base type of unsignedByte is unsignedShort .

The WSDL generated by ATL Server for a fixed size array of elements, when each element is of type unsignedByte , looks like the following (the server-side code is also presented):

 HRESULT echoByteArray([in] unsigned __int8 arrIn[10], [out, retval] unsigned  __int8 arrOut[10]) <types>  <s:schema targetNamespace="urn:BArrayService"                   attributeFormDefault="qualified"                   elementFormDefault="qualified">    <s:complexType name="echoByteArray_return_Array">      <s:complexContent>        <s:restriction base="soapenc:Array">          <s:attribute ref="soapenc:arrayType" wsdl:arrayType="s:unsignedByte[10]"/>        </s:restriction>      </s:complexContent>    </s:complexType>    <s:complexType name="echoByteArray_arrIn_Array">      <s:complexContent>        <s:restriction base="soapenc:Array">          <s:attribute ref="soapenc:arrayType"                         wsdl:arrayType="s: unsignedByte [10]"/>        </s:restriction>      </s:complexContent>    </s:complexType>  </s:schema>  </types>  <message name="echoByteArrayIn">  <part name="arrIn" type="s0:echoByteArray_arrIn_Array"/>  </message>  <message name="echoByteArrayOut">  <part name="return" type="s0:echoByteArray_return_Array"/>  </message> 

Therefore, the echoByteArray_arrIn_Array type is defined as an soapenc:Array with arrayType="s:unsignedByte[10]" .

The ATL Server Web service expects a payload that looks like the following:

 <snp:echoByteArray    xmlns:snp="urn:BArrayService">    <arrIn soapenc:arrayType="xsd:byte[10]">      <unsignedByte>1</ unsignedByte >      <unsignedByte>2</ unsignedByte >      ...      <unsignedByte>10</ unsignedByte >    </arrIn>  </snp:echoByteArray> 

The ASP.NET client interprets the WSDL fragment as being a BLOB, an object that usually is defined using one of the xsd:base64Binary or xsd:hexBinary XSD types, and sends a message containing 10 bytes encoded as a BLOB (in this case, base64 encoding). The ASP.NET payload will look like this:

 <tns:echoByteArray>    <arIn xsi:type="xsd:base64Binary">      AQIDBAUGBwgJAA==    </arIn>  </tns:echoByteArray> 

which will cause the ATL Server Web service to fault in processing the request.

To solve this problem, from the perspective of the ATL Server Web service, the unsignedByte type should be replaced by a different type, say unsignedShort , making the function look like this:

 HRESULT echoByteArray([in] unsigned __int116 arrIn[10],                                   [out, retval] unsigned __int16 arrOut[10]) 



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