views:

848

answers:

1

Hi there,

I have a webservice programmed in coldfusion which I'm attempting to consume using c#.net.

The particular webservices returns a coldfusion structure (a collection of items with a key and a value) which is exposed by the webservice as a complex object of type apachesoap:Map

<wsdl:message name="getDetailResponse">
    <wsdl:part name="getDetailReturn" type="apachesoap:Map"/>
</wsdl:message>

The complex type is correctly declared in the WSDL file automatically generated by coldfusion

<schema targetNamespace="http://xml.apache.org/xml-soap"&gt;
    <import namespace="http://webservice.templates"/&gt;
    <import namespace="http://rpc.xml.coldfusion"/&gt;
    <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/&gt;
    <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>

When attempting to consume this using the following c# code:

theWebservice.theWebservice myWS = new theWebservice.theWebservice();
theWebservice.Map myMap = myWS.searchForRecord("some record data");

if (myMap.item == null) {
    Response.Write("myMap.item is null");
}

The code compiles fine but displays the "myMap.item is null" rather than being an object with a key and value pair.

Inspection with the debugger shows myMap has two children item and itemField both of type theWebservice.mapItem[] and both of value null.

I've seen other forum posts with a similar issue but no replies, does anyone know how I can consume the service correctly without having to alter the webservice to use just simple types?

Edited to provide more information

As per John Saunders' questions, I'm using .NET Framework 3.5 in Visual Web Developer 2008. the webservice was included as a web reference and the response SOAP code is provided below (from soapUI):

<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"&gt;
    <soapenv:Body>
        <ns1:getDetailResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://DefaultNamespace"&gt;
            <getDetailReturn xsi:type="ns2:Map" xmlns:ns2="http://xml.apache.org/xml-soap"&gt;
                <item xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"&gt;
                    <key xsi:type="soapenc:string">a</key>
                    <value xsi:type="soapenc:string">1</value>
                </item>
                <item>
                    <key xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"&gt;b&lt;/key&gt;
                    <value xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"&gt;2&lt;/value&gt;
                </item>
            </getDetailReturn>
        </ns1:getDetailResponse>
    </soapenv:Body>
</soapenv:Envelope>

Thanks,

Tom

+1  A: 

You can always consume the coldfusion web service without using .NETs built in services. This would require that you manually parse the response, but hey, It's XML so it's not that bad.

Lets say you have this web service:

<cfcomponent>
  <cffunction name="GetStruct" access="remote" returntype="struct" output="no">
        <cfscript>
           var struct = StructNew();
           struct.foo = "bar";
           struct.baz = 2;
           struct.Stooges = StructNew();
           struct.Stooges.Larry = 1;
           struct.Stooges.Moe = "Hi Mom";
           struct.Stooges.Curley = "Not Shemp"; 
        </cfscript>

    <cfreturn struct>
  </cffunction>
</cfcomponent>

set up your request in .Net like this:

var request = WebRequest.Create("http://localhost/test.cfc?method=GetStruct");
var response = request.GetResponse();
String content;
using (var reader = new StreamReader(response.GetResponseStream()))
{
  content = reader.ReadToEnd();
}

The content you get back will be a wddx packet like this:

<wddxPacket version="1.0">
    <header /> 
    <data>
        <struct>
            <var name="BAZ">
                <string>2</string> 
            </var>
            <var name="STOOGES">
                <struct>
                    <var name="MOE">
                      <string>Hi Mom</string> 
                    </var>
                    <var name="CURLEY">
                      <string>Not Shemp</string> 
                    </var>
                    <var name="LARRY">
                      <string>1</string> 
                    </var>
                </struct>
          </var>
          <var name="FOO">
            <string>bar</string> 
          </var>
        </struct>
    </data>
</wddxPacket>

of course the even better solution might be to just return XML to begin with

P.S. You can also force coldfusion to serialize the struct as JSON with returnformat="json" on the cffunction tag.

ryber