[Mono-dev] wsdl to C#: generated stub raises exception on dynamic array casting

Julien MARBACH jmarbach at quelisid.com
Tue Jan 17 14:50:38 EST 2006


Hello,
I've generated a C# client stub from a wsdl file with Mono "wsdl"
command. The stub works great for most of the remote methods but one is
not functioning. 
The problematic method consist in transferring a dynamic array of struct
from the server to the client. 
When returning its result, the stub function that calls the remote
method makes a cast form Object[] to TagIdArray (my custom type : array
of TagID, see attached code snippets) and an invalid cast exception is
generated :

Unhandled Exception: System.InvalidCastException: Cannot cast from
source type to destination type.
in <0x000f1> quelisapi:getTagIdList (Boolean blocking, Int64 timeout,
System.Boolean scanning)
in (wrapper remoting-invoke-with-check) quelisapi:getTagIdList
(bool,long,bool&)
in [0x00018]
(at /home/jmarbach/workspace/cvs/SmartReader/warehouse_demo/quelisapiclient/quelisapiclient/Main.cs:40) QuelisapiClient:getIDList ()
in [0x00039]
(at /home/jmarbach/workspace/cvs/SmartReader/warehouse_demo/quelisapiclient/quelisapiclient/Main.cs:25) QuelisapiClient:Main (System.String[] args)

The exception is raised by the cast on the return statement of this
function :
    public TagIdArray getTagIdList(bool blocking, long timeout, out bool
scanning) {
        object[] results = this.Invoke("getTagIdList", new object[] {
            blocking,
            timeout});
        scanning = ((bool)(results[1]));
        return ((TagIdArray)(results[0]));
    }

Does this means that Mono SOAP implementation is not compatible with the
one I use on the server side (gSOAP) ? 

And/or does this means that Mono SOAP implementation does not support
the serialization/deserialization of this kind of structure?

What kind of table could I use that would be supported by Mono?

Thanks,
Julien


PS1 : Here are the code snippets ( "[...]" stands for non relevant
omitted code) :

[************************** wsdl file end ***************************] 

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="quelisapi"
 targetNamespace="urn:QuelisReader"
 xmlns:tns="urn:QuelisReader"
 xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 xmlns:api="urn:QuelisReader"
 xmlns:SOAP="http://schemas.xmlsoap.org/wsdl/soap/"
 xmlns:MIME="http://schemas.xmlsoap.org/wsdl/mime/"
 xmlns:DIME="http://schemas.xmlsoap.org/ws/2002/04/dime/wsdl/"
 xmlns:WSDL="http://schemas.xmlsoap.org/wsdl/"
 xmlns="http://schemas.xmlsoap.org/wsdl/">

<types>

 <schema targetNamespace="urn:QuelisReader"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:api="urn:QuelisReader"
  xmlns="http://www.w3.org/2001/XMLSchema"
  elementFormDefault="unqualified"
  attributeFormDefault="unqualified">
  <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>

[...]

  <complexType name="TagId">
   <sequence>
     <element name="uid" type="xsd:string" minOccurs="0" maxOccurs="1"
nillable="true"/>
     <element name="readings" type="xsd:int" minOccurs="1"
maxOccurs="1"/>
   </sequence>
  </complexType>
  <simpleType name="TagIdArray">
   <restriction base="xsd:base64Binary">
   </restriction>
  </simpleType>
 </schema>

</types>

[...]

<message name="getTagIdList">
 <part name="blocking" type="xsd:boolean"/>
 <part name="timeout" type="xsd:long"/>
</message>

<message name="TagIdList">
 <part name="tagIdArray" type="api:TagIdArray"/>
 <part name="scanning" type="xsd:boolean"/>
</message>

<portType name="quelisapiPortType">

[...]

 <operation name="getTagIdList">
  <documentation>Service definition of function
api__getTagIdList</documentation>
  <input message="tns:getTagIdList"/>
  <output message="tns:TagIdList"/>
 </operation>

</portType>

<binding name="quelisapi" type="tns:quelisapiPortType">
 <SOAP:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>

[...]

 <operation name="getTagIdList">
  <SOAP:operation style="rpc" soapAction=""/>
  <input>
     <SOAP:body use="encoded" namespace="urn:QuelisReader"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
  </input>
  <output>
     <SOAP:body use="encoded" namespace="urn:QuelisReader"
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"/>
  </output>
 </operation>

</binding>

<service name="quelisapi">
 <documentation>gSOAP 2.7.6c generated service
definition</documentation>
 <port name="quelisapi" binding="tns:quelisapi">
  <SOAP:address location="http://api.quelisid.com"/>
 </port>
</service>

</definitions>

[************************** wsdl file end ***************************] 

[************************ generated stub ****************************] 
//
------------------------------------------------------------------------------
//  <autogenerated>
//      This code was generated by a tool.
//      Mono Runtime Version: 1.1.4322.573
// 
//      Changes to this file may cause incorrect behavior and will be
lost if 
//      the code is regenerated.
//  </autogenerated>
//
------------------------------------------------------------------------------

// 
// This source code was auto-generated by Mono Web Services Description
Language Utility
//
using System;
/// <remarks/>
/// <remarks>
///gSOAP 2.7.6c generated service definition
///</remarks>
[System.Web.Services.WebServiceBinding(Name="quelisapi",Namespace="urn:QuelisReader"),
System.Diagnostics.DebuggerStepThroughAttribute(),
System.ComponentModel.DesignerCategoryAttribute("code")]
public class quelisapi:
System.Web.Services.Protocols.SoapHttpClientProtocol {
    
    public quelisapi () {
        this.Url = "http://api.quelisid.com";
    }
    
[...]
    
    /// <remarks>
    ///Service definition of function api__getTagIdList
    ///</remarks>

[System.Web.Services.Protocols.SoapRpcMethodAttribute("",RequestNamespace="urn:QuelisReader",ResponseNamespace="urn:QuelisReader")]
    [return: System.Xml.Serialization.SoapElement("tagIdArray")]
    public TagIdArray getTagIdList(bool blocking, long timeout, out bool
scanning) {
        object[] results = this.Invoke("getTagIdList", new object[] {
            blocking,
            timeout});
        scanning = ((bool)(results[1]));
        return ((TagIdArray)(results[0]));
    }
    
    public System.IAsyncResult BegingetTagIdList(bool blocking, long
timeout, System.AsyncCallback callback, object asyncState) {
        return this.BeginInvoke("getTagIdList", new object[] {
            blocking,
            timeout}, callback, asyncState);
    }
    
    public TagIdArray EndgetTagIdList(System.IAsyncResult asyncResult,
out bool scanning) {
        object[] results = this.EndInvoke(asyncResult);
        scanning = ((bool)(results[1]));
        return ((TagIdArray)(results[0]));
    }
}

/// <remarks/>
[System.Xml.Serialization.SoapType(Namespace="urn:QuelisReader")]
public class TagIdArray {
    
    /// <remarks/>
    [System.Xml.Serialization.SoapElement()]
    public TagId[] item;
}

/// <remarks/>
[System.Xml.Serialization.SoapType(Namespace="urn:QuelisReader")]
public class TagId {
    
    /// <remarks/>
    public string uid;
    
    /// <remarks/>
    public int readings;
}

[******************** generated stub end **************************] 
[********* My code, used to call the getTagIdList function ********]

TagIdArray tagIdArray;// = new TagIdArray();
bool nonBlocking = false;
long timeout = 10000;
bool scanning = false;

tagIdArray = Service.getTagIdList(nonBlocking , timeout, out scanning);

[*********               End                               ********]

PS2 : on mono irc channel I've discussed about it with "jonp" who made
me some suggestions :

(09:48:07) jonp: as a test, change the C# method argument accepting the
array to a System.Xml.XmlNode (iirc)
(09:48:18) jonp: this should give you direct access to the underlying XML, without any unmarshaling
(09:49:26) jonp: sadly this was reported on mono-devel-list sep-2004, but there were no replies 

I'm working on it.

He also pointed out some compatibility info between gSOAP and other SOAP implementations :
http://www.cs.fsu.edu/~engelen/interop11/interop2results.html
This page shows that arrays support (and mostly struct arrays) seems to be a big compatibility challenge between the existing SOAP implementations.

-- 
MARBACH Julien
Embedded software engineer
Quelis ID Systems
11845 Irenee-Vachon
J7N 1G2 Mirabel (QC)
Canada

Phone : +1 (450) 476-1930 - x230
Fax   : +1 (450) 476-0246

--- www.quelisid.com ---





More information about the Mono-devel-list mailing list