Complex type nested elements are never populated when invoking an AXIS-based web service with .NET.

I’ve been trying for a couple of days to get a .NET client that works fully with the web server provided by my Coldfusion web application. I'm not a .NET developer, in fact, but I have a copy of VS 2003, which seems to do the trick.

I can use a simple multiplier () method in my web service, which takes two numbers and returns a number, so simple types work fine. These are the complex types that are killing me. I am basically trying to return an associative array from the get_struct () method. I get an object of type Map back, but a property (called item), which should be an array with two elements (of type mapItem), always has the value "undefined".

Here's the WSDL created by ColdFusion:

<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions targetNamespace="http://trunk.v.pfapi.remote_api" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://trunk.v.pfapi.remote_api" xmlns:intf="http://trunk.v.pfapi.remote_api" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns1="http://rpc.xml.coldfusion" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <!--WSDL created by Macromedia ColdFusion MX version 7,0,2,142559--> <wsdl:types> <schema targetNamespace="http://rpc.xml.coldfusion" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://trunk.v.pfapi.remote_api"/> <import namespace="http://xml.apache.org/xml-soap"/> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="CFCInvocationException"> <sequence/> </complexType> <complexType name="QueryBean"> <sequence> <element name="columnList" nillable="true" type="impl:ArrayOf_xsd_string"/> <element name="data" nillable="true" type="impl:ArrayOfArrayOf_xsd_anyType"/> </sequence> </complexType> </schema> <schema targetNamespace="http://xml.apache.org/xml-soap" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://trunk.v.pfapi.remote_api"/> <import namespace="http://rpc.xml.coldfusion"/> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="mapItem"> <sequence> <element name="key" nillable="true" type="xsd:anyType"/> <element name="value" nillable="true" type="xsd:anyType"/> </sequence> </complexType> <complexType name="Map"> <sequence> <element maxOccurs="unbounded" minOccurs="0" name="item" type="apachesoap:mapItem"/> </sequence> </complexType> </schema> <schema targetNamespace="http://trunk.v.pfapi.remote_api" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://rpc.xml.coldfusion"/> <import namespace="http://xml.apache.org/xml-soap"/> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="ArrayOf_xsd_string"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/> </restriction> </complexContent> </complexType> <complexType name="ArrayOfArrayOf_xsd_anyType"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:anyType[][]"/> </restriction> </complexContent> </complexType> </schema> </wsdl:types> <wsdl:message name="CFCInvocationException"> <wsdl:part name="fault" type="tns1:CFCInvocationException"/> </wsdl:message> <wsdl:message name="multiplierResponse"> <wsdl:part name="multiplierReturn" type="xsd:double"/> </wsdl:message> <wsdl:message name="get_structResponse"> <wsdl:part name="get_structReturn" type="apachesoap:Map"/> </wsdl:message> <wsdl:message name="struct_keycountResponse"> <wsdl:part name="struct_keycountReturn" type="xsd:double"/> </wsdl:message> <wsdl:message name="get_structRequest"> </wsdl:message> <wsdl:message name="multiplierRequest"> <wsdl:part name="factor1" type="xsd:double"/> <wsdl:part name="factor2" type="xsd:double"/> </wsdl:message> <wsdl:message name="struct_keycountRequest"> <wsdl:part name="theStruct" type="apachesoap:Map"/> </wsdl:message> <wsdl:portType name="remote_io_test"> <wsdl:operation name="multiplier" parameterOrder="factor1 factor2"> <wsdl:input message="impl:multiplierRequest" name="multiplierRequest"/> <wsdl:output message="impl:multiplierResponse" name="multiplierResponse"/> <wsdl:fault message="impl:CFCInvocationException" name="CFCInvocationException"/> </wsdl:operation> <wsdl:operation name="get_struct"> <wsdl:input message="impl:get_structRequest" name="get_structRequest"/> <wsdl:output message="impl:get_structResponse" name="get_structResponse"/> <wsdl:fault message="impl:CFCInvocationException" name="CFCInvocationException"/> </wsdl:operation> <wsdl:operation name="struct_keycount" parameterOrder="theStruct"> <wsdl:input message="impl:struct_keycountRequest" name="struct_keycountRequest"/> <wsdl:output message="impl:struct_keycountResponse" name="struct_keycountResponse"/> <wsdl:fault message="impl:CFCInvocationException" name="CFCInvocationException"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="remote_io_test.cfcSoapBinding" type="impl:remote_io_test"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="multiplier"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="multiplierRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://trunk.v.pfapi.remote_api" use="encoded"/> </wsdl:input> <wsdl:output name="multiplierResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://trunk.v.pfapi.remote_api" use="encoded"/> </wsdl:output> <wsdl:fault name="CFCInvocationException"> <wsdlsoap:fault encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" name="CFCInvocationException" namespace="http://trunk.v.pfapi.remote_api" use="encoded"/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="get_struct"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="get_structRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://trunk.v.pfapi.remote_api" use="encoded"/> </wsdl:input> <wsdl:output name="get_structResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://trunk.v.pfapi.remote_api" use="encoded"/> </wsdl:output> <wsdl:fault name="CFCInvocationException"> <wsdlsoap:fault encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" name="CFCInvocationException" namespace="http://trunk.v.pfapi.remote_api" use="encoded"/> </wsdl:fault> </wsdl:operation> <wsdl:operation name="struct_keycount"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="struct_keycountRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://trunk.v.pfapi.remote_api" use="encoded"/> </wsdl:input> <wsdl:output name="struct_keycountResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://trunk.v.pfapi.remote_api" use="encoded"/> </wsdl:output> <wsdl:fault name="CFCInvocationException"> <wsdlsoap:fault encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" name="CFCInvocationException" namespace="http://trunk.v.pfapi.remote_api" use="encoded"/> </wsdl:fault> </wsdl:operation> </wsdl:binding> <wsdl:service name="remote_io_testService"> <wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"> This is a collection of test methods to allow remote developers to evaluate datatype support, etc in their programming environment. The WSDL endpoint for this web service is [YOUR PEERFOCUS SITE]/remote_api/pfapi/v/trunk/remote_io_test.cfc?wsdl </wsdl:documentation> <wsdl:port binding="impl:remote_io_test.cfcSoapBinding" name="remote_io_test.cfc"> <wsdlsoap:address location="http://leon.cupahr.tafkan.localhost/remote_api/pfapi/v/trunk/remote_io_test.cfc"/> </wsdl:port> </wsdl:service> </wsdl:definitions> 

and here the web service stub is generated when adding a web link to VS:

 //------------------------------------------------------------------------------ // <autogenerated> // This code was generated by a tool. // Runtime Version: 1.1.4322.2443 // // 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 Microsoft.VSDesigner, Version 1.1.4322.2443. // namespace pfapi_test.remote_io_test { using System.Diagnostics; using System.Xml.Serialization; using System; using System.Web.Services.Protocols; using System.ComponentModel; using System.Web.Services; /// <remarks/> [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Web.Services.WebServiceBindingAttribute(Name="remote_io_test.cfcSoapBinding", Namespace="http://trunk.v.pfapi.remote_api")] [System.Xml.Serialization.SoapIncludeAttribute(typeof(QueryBean))] [System.Xml.Serialization.SoapIncludeAttribute(typeof(CFCInvocationException))] public class remote_io_testService : System.Web.Services.Protocols.SoapHttpClientProtocol { /// <remarks/> public remote_io_testService() { this.Url = "http://leon.cupahr.tafkan.nooch/remote_api/pfapi/v/trunk/remote_io_test.cfc"; } /// <remarks/> [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://trunk.v.pfapi.remote_api", ResponseNamespace="http://trunk.v.pfapi.remote_api")] [return: System.Xml.Serialization.SoapElementAttribute("multiplierReturn")] public System.Double multiplier(System.Double factor1, System.Double factor2) { object[] results = this.Invoke("multiplier", new object[] { factor1, factor2}); return ((System.Double)(results[0])); } /// <remarks/> public System.IAsyncResult Beginmultiplier(System.Double factor1, System.Double factor2, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("multiplier", new object[] { factor1, factor2}, callback, asyncState); } /// <remarks/> public System.Double Endmultiplier(System.IAsyncResult asyncResult) { object[] results = this.EndInvoke(asyncResult); return ((System.Double)(results[0])); } /// <remarks/> [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://trunk.v.pfapi.remote_api", ResponseNamespace="http://trunk.v.pfapi.remote_api")] [return: System.Xml.Serialization.SoapElementAttribute("get_structReturn")] public Map get_struct() { object[] results = this.Invoke("get_struct", new object[0]); return ((Map)(results[0])); } /// <remarks/> public System.IAsyncResult Beginget_struct(System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("get_struct", new object[0], callback, asyncState); } /// <remarks/> public Map Endget_struct(System.IAsyncResult asyncResult) { object[] results = this.EndInvoke(asyncResult); return ((Map)(results[0])); } /// <remarks/> [System.Web.Services.Protocols.SoapRpcMethodAttribute("", RequestNamespace="http://trunk.v.pfapi.remote_api", ResponseNamespace="http://trunk.v.pfapi.remote_api")] [return: System.Xml.Serialization.SoapElementAttribute("struct_keycountReturn")] public System.Double struct_keycount(Map theStruct) { object[] results = this.Invoke("struct_keycount", new object[] { theStruct}); return ((System.Double)(results[0])); } /// <remarks/> public System.IAsyncResult Beginstruct_keycount(Map theStruct, System.AsyncCallback callback, object asyncState) { return this.BeginInvoke("struct_keycount", new object[] { theStruct}, callback, asyncState); } /// <remarks/> public System.Double Endstruct_keycount(System.IAsyncResult asyncResult) { object[] results = this.EndInvoke(asyncResult); return ((System.Double)(results[0])); } } /// <remarks/> [System.Xml.Serialization.SoapTypeAttribute("Map", "http://xml.apache.org/xml-soap")] public class Map { /// <remarks/> public mapItem[] item; } /// <remarks/> [System.Xml.Serialization.SoapTypeAttribute("mapItem", "http://xml.apache.org/xml-soap")] public class mapItem { /// <remarks/> public object key; /// <remarks/> public object value; } /// <remarks/> [System.Xml.Serialization.SoapTypeAttribute("QueryBean", "http://rpc.xml.coldfusion")] public class QueryBean { /// <remarks/> public string[] columnList; /// <remarks/> public object[] data; } /// <remarks/> [System.Xml.Serialization.SoapTypeAttribute("CFCInvocationException", "http://rpc.xml.coldfusion")] public class CFCInvocationException { } } 

And finally, my CLI application that checks the service:

 using System; namespace pfapi_test { /// <summary> /// Summary description for Class1. /// </summary> class Class1 { /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main(string[] args) { // // TODO: Add code to start application here // Console.WriteLine("Instantiating WS"); remote_io_test.remote_io_testService testWS = new remote_io_test.remote_io_testService(); Console.WriteLine("Calling multiplier(3,15)"); Console.WriteLine(testWS.multiplier(3,15)); Console.WriteLine("Calling get_struct()"); remote_io_test.Map theStruct = testWS.get_struct(); Console.Write("result: "); Console.WriteLine(theStruct); Console.Write("result.item: "); Console.WriteLine(theStruct.item); Console.WriteLine("Press Enter to exit..."); Console.ReadLine(); } } } 

No matter what I try, theStruct.item always has an "undefined value" according to the debugger. The printed result is as follows:

 Instantiating WS Calling multiplier(3,15) 45 Calling get_struct() result: pfapi_test.remote_io_test.Map result.item: Press Enter to exit... 

I tried using ColdFusion 8 and it makes no difference. I tried to return a real user database with two properties instead of my ad-hoc associative array, and this works fine, but rewriting my API to avoid associative arrays is not an option at the moment. The API works great with ColdFusion, PHP / NuSOAP, and Ruby on Rails, so it seems like it can also make it work with .NET.

Hope someone can give some insight. I have a suspicion that there is some kind of namespace here, but I do not know SOAP and XML well enough to understand what it is. I also looked for a solution to solve the problem online, but I did not find a single person who solved this problem, which is very unpleasant!

Request:

 POST /remote_api/pfapi/v/trunk/remote_io_test.cfc HTTP/1.1 VsDebuggerCausalityData: [snip] User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 1.1.4322.2443) Content-Type: text/xml; charset=utf-8 SOAPAction: "" Content-Length: 488 Expect: 100-continue Host: leon.cupahr.tafkan.nooch <?xml version="1.0" encoding="utf-8"?> <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://trunk.v.pfapi.remote_api" xmlns:types="http://trunk.v.pfapi.remote_api/encodedTypes" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <soap:Body soap:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <tns:get_struct /> </soap:Body> </soap:Envelope> 

Answer:

 HTTP/1.1 200 OK Date: Thu, 17 Dec 2009 15:14:33 GMT Server: Apache/2.2.11 (Unix) mod_ssl/2.2.11 OpenSSL/0.9.7l DAV/2 PHP/5.2.8 JRun/4.0 Phusion_Passenger/2.2.7 Set-Cookie: CFID=21543;expires=Sat, 10-Dec-2039 15:14:33 GMT;path=/ Set-Cookie: CFTOKEN=479cc311ca4875db-9D346355-ED36-6183-C8895635E4EE1252;expires=Sat, 10-Dec-2039 15:14:33 GMT;path=/ Transfer-Encoding: chunked Content-Type: text/xml; charset=utf-8 <?xml version="1.0" encoding="utf-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <ns1:get_structResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://trunk.v.pfapi.remote_api"> <get_structReturn xsi:type="ns2:Map" xmlns:ns2="http://xml.apache.org/xml-soap"> <item xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"> <key xsi:type="soapenc:string">FOO</key> <value xsi:type="soapenc:string">bar</value> </item> <item> <key xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">ANOTHERKEY</key> <value xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">another value</value> </item> </get_structReturn> </ns1:get_structResponse> </soapenv:Body> </soapenv:Envelope> 

Update: I heard from the .NET developer on the other end, and he tried all of the following to no avail:

  • using WCF instead of ASMX
  • using .NET 3.5
  • using VB.NET to communicate with a web service instead of C #

He sent me a screenshot of the Data Type section of the Service Link Settings dialog box. Is it possible that changing the settings of type Collection and type of collection Dictionary can solve this problem?

Update 2: here is the ColdFusion code for remote_io_test.cfc

 <cfcomponent name="remote_io_test" hint="This is a collection of test methods to allow remote developers to evaluate datatype support, etc in their programming environment."> <cffunction name="get_struct" returntype="struct" access="remote" output="no" hint="Returns an associative array with two keys, 'foo' and 'anotherKey'. Allows you to test your implementation support for WDDX encoding. ColdFusion and PHP (w/ NuSOAP) will automatically decode the result into an associative array. Feedback on other languages is appreciated."> <cfset var stFoo = structNew()> <cfset stFoo.foo = "bar"> <cfset stFoo.anotherKey = "another value"> <cfreturn duplicate(stFoo)> </cffunction> <!--- get_struct ---> <cffunction name="multiplier" returntype="numeric" access="remote" output="no" hint="Multiplies two factors and returns the result. Allows you to test passing simple variables to a remote method."> <cfargument name="factor1" type="numeric" required="yes"> <cfargument name="factor2" type="numeric" required="yes"> <cfreturn factor1 * factor2> </cffunction> <!--- multiplier ---> <cffunction name="struct_keycount" returntype="numeric" access="remote" output="no" hint="Returns the number of keys in an upload associative array. Allows you to test passing complex variables to a remote method."> <cfargument name="theStruct" type="struct" required="yes"> <cfreturn structCount(theStruct)> </cffunction> <!--- struct_keycount ---> 

Thanks for reading and in advance for your answers!

Cross reference to link text

+6
c # soap coldfusion web-services
source share
3 answers

Answer: do not use Coldfusion structures in your web service.

Like everyone else in front of us, we refused and rewrote our API so as not to use any associative arrays in the request or response. Now we use scalars, arrays and complexTypes, which are automatically created from CFC. This time, we tested our proof of concept with PHP, Ruby, Coldfusion, Java, and .NET to make sure it is truly compatible.

Now it becomes clear that a statically typed language will not be able to process an absolutely arbitrary remote data type in any reasonable way.

Thanks for all your feedback!

+1
source share

I am struggling with this issue with this element from the client side. I am trying to use a web service written in ColdFusion. From the documentation I found, the structure data type in ColdFusion does not map directly to any types of web services, and it seems to me that this is a bug in Axis.

You may have read the same web pages as you tried to solve this problem, but it seems that if you want to create a web service using ColdFusion, it is recommended not to use the structure type. If your web service is not working yet and you can get away from using something else, I would suggest going along this route. I tried to return objects from ColdFusion that worked perfectly for me from the .NET client.

I really abandoned this problem and wrote a user client for my .NET program that would just read the Xml returned by the ColdFusion web service and turn it into a dictionary, since I do not affect the service I'm trying to call.

One thing I found during my testing is that the service I'm trying to call works on an older version of ColdFusion (7, I believe). Whenever I call this service, the .NET client returns null. I installed ColdFusion on my own computer and wrote a simple service, and found that the .NET client returned a Map object (which came from WSDL), but the properties of the Map object were empty.

I would be interested to know if Chris Haas allows the suggestion in the comments on your question about installing dotNetSoapEncFix.

+2
source share

There is a solution to your problem, and it is here:

http://ws-i.org/Profiles/BasicProfile-2.0-2010-11-09.html#soapenc_Array

http://ws-i.org/Profiles/BasicProfile-1.2-2010-11-09.html#soapenc_Array

Your problem here, to be precise:

  <complexType name="ArrayOf_xsd_string"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/> </restriction> </complexContent> </complexType> <complexType name="ArrayOfArrayOf_xsd_anyType"> <complexContent> <restriction base="soapenc:Array"> <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:anyType[][]"/> </restriction> </complexContent> </complexType> 

Just override these types:

 <element name="ArrayOf_xsd_string" type="tns:OnlyStringArrayType"/> <complexType name="OnlyStringArrayType"> <sequence> <element name="array_element" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/> </sequence> </complexType> <element name="ArrayOfArrayOf_xsd_anyType" type="tns:AnyTypeArrayType"/> <complexType name="AnyTypeArrayType"> <sequence> <element name="array_element" type="xsd:anyType" minOccurs="0" maxOccurs="unbounded"/> </sequence> </complexType> 

it still does not fully comply with the WS-I profiles described above, due to the names of the elements, but they are very easy to handle by clients and class file generators.

I wrote this solution for others who stumbled upon this problem :)

And by the way, WSDL and SOAP are one big pain in ....;)

0
source share

All Articles