I am creating a WCF Client in VS 2013 using a supplied third party WSDL for a web service - most likely running on Java.
Running svcutil on the raw WSDL gives me an error similar to this:
Error: Cannot import wsdl:binding
Detail: There was an error importing a wsdl:portType that the wsdl:binding is dependent on.
XPath to wsdl:portType:
//wsdl:definitions[#targetNamespace='<ns>']/wsdl:portType[#name='xxxPort']
XPath to Error Source:
//wsdl:definitions[#targetNamespace='<ns>']/wsdl:binding[#name='xxxPortSoap11']
Error: Cannot import wsdl:port
Detail: There was an error importing a wsdl:binding that the wsdl:port is dependent on.
XPath to wsdl:binding:
//wsdl:definitions[#targetNamespace='<ns>']/wsdl:binding[#name='xxxPortSoap11']
XPath to Error Source:
//wsdl:definitions[#targetNamespace='<ns>']/wsdl:service[#name='xxxPortService']/wsdl:port[#name='xxxPortSoap11']
Generating files...
Warning: No code was generated. ...
In order to get the Service Reference working (or svcutil running without errors) I have to comment out the fault definitions in the port and bindings. I can live with that (as I have made a MessageInspector to pull out errors from the various detail elements), but want to get it working properly.
Simplifying the WSDL to only show the elements that give me problems gives:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions
xmlns:tns="http://www.example.com/data/common/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:sch0="http://www.example.com/data/common/"
targetNamespace="http://www.example.com/data/common/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<xsd:schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns1="http://www.example.com/data/common/"
attributeFormDefault="unqualified" elementFormDefault="qualified"
targetNamespace="www.example.com/data/common/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType xmlns="http://www.w3.org/2001/XMLSchema" name="BusinessErrorType">
<xsd:sequence xmlns="http://www.w3.org/2001/XMLSchema">
<xsd:element xmlns="http://www.w3.org/2001/XMLSchema"
name="Error" maxOccurs="unbounded" type="string" />
</xsd:sequence>
</xsd:complexType>
<xsd:element xmlns="http://www.w3.org/2001/XMLSchema"
name="BusinessErrorFault" type="tns1:BusinessErrorType" />
</xsd:schema>
</wsdl:types>
<wsdl:message name="BusinessErrorFault">
<wsdl:part name="BusinessErrorFault" element="sch0:BusinessErrorFault" />
</wsdl:message>
<wsdl:portType name="ViewMessagesPort">
<wsdl:operation name="BusinessError">
<wsdl:fault name="BusinessErrorFault" message="sch0:BusinessErrorFault" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="ViewMessagesPortSoap11" type="sch0:ViewMessagesPort">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="BusinessError">
<soap:operation soapAction="" />
<wsdl:fault name="BusinessErrorFault">
<soap:fault use="literal" name="BusinessErrorFault" />
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="ViewMessagesPortService">
<wsdl:port name="ViewMessagesPortSoap11" binding="sch0:ViewMessagesPortSoap11">
<soap:address location="https://www.example.com/ws/" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
I have looked at many SO questions and other places on the net including Scott Hanselman's breaking the rules with no joy.
Hopefully it is something blindingly obvious ... I gratefully await any answers from across the pond as I wend my way home in the UK.
UPDATE
Passing the above WSDL through https://www.wsdl-analyzer.com/ gives an error on the binding:
Style: Unknown [Warn!]
Could not detect the 'use' for the operations of binding ViewMessagesPortSoap11
I'm still none the wiser.
The WSDL you published above has an issue that there is no schema with targetNamespace of "http://www.example.com/data/common/" which is what expected by the sch0:BusinessErrorFault element. I assume this may be because you did not provide the full WSDL so I changed the targetNamespace of the schema to it. The next error if this this operation:
<wsdl:operation name="BusinessError">
<wsdl:fault name="BusinessErrorFault" message="sch0:BusinessErrorFault" />
</wsdl:operation>
has no input or output but just fault, which does not make since.
I guess this might also be because you simplified the WSDL so please publish the full one if you get more errors.
I have one WCF service and two console app clients.
Service: The service code is created from a wsdl contact using WCSF Blue tool.
Client 1: This client is using wsdl that is obtained by browsing the svc file. This browsed wsdl file is slightly different from the contract wsdl file.
Client 2: This client is created using the original wsdl contract.
Cleint1 is working fine. Client 2 is not working. What all could be potential issues?
App.Config file of both the clients look similar – only the name changes. I think, the problem will be in the client C# code generated – most probably in the Action – ReplyAction. What need to be corrected here?
One noticeable difference is in Action and ReplyAction
Client 1:
Action="urn:lijo:demos:multiplyservice:calculation:v1/ICalculationService/GetMultiplied", ReplyAction="urn:lijo:demos:multiplyservice:calculation:v1/ICalculationService/GetMultipliedRe" +
"sponse"
Client 2:
Action="urn:lijo:demos:multiplyservice:calculation:v1:getMultipliedIn", ReplyAction="*"
Trace Message
The message with Action 'urn:lijo:demos:multiplyservice:calculation:v1:getMultipliedIn' cannot be processed at the receiver, due to a ContractFilter mismatch at the EndpointDispatcher. This may be because of either a contract mismatch (mismatched Actions between sender and receiver) or a binding/security mismatch between the sender and the receiver. Check that sender and receiver have the same contract and the same binding (including security requirements, e.g. Message, Transport, None).
EDIT
This can be corrected by changing the Action and ReplyAction as below (Copied it from Service).
[System.ServiceModel.OperationContractAttribute(Action = "urn:lijo:demos:multiplyservice:calculation:v1/ICalculationService/getMultiplied", ReplyAction = "urn:lijo:demos:multiplyservice:calculation:v1/ICalculationService/getMultipliedRe" +
"sponse")]
Note: It is important to ensure that the casing in the service is correct (i.e, getMultiplied not GetMultiplied)
Copying from the service is not a good option, though it works. What would be the correct Action and ReplyAction?
Also, Can you please point out how to modify the wsdl so that the ReplyAction will be correct in the generated client proxy? That is the essential part to mark it as answered.
WCF: Actions, Asterisk and Metadata
WsdlExporter, which is used for metadata publishing, ignores operations with asterisk actions (both Action and ReplyAction).
From MSDN -ReplyAction Property
Specifying an asterisk in the service instructs WCF not to add a reply action to the message, which is useful if you are programming against messages directly.
REFERENCES:
WCF metadata missing operations
RestaurantData.xsd
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema id="RestaurantData" targetNamespace="urn:lijo:demos:multiplyservice:data:v1"
elementFormDefault="qualified" xmlns="urn:lijo:demos:multiplyservice:data:v1"
xmlns:mstns="urn:lijo:demos:multiplyservice:data:v1" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:complexType name="multipliedResult">
<xs:sequence>
<xs:element name="resultNumber" type="xs:int" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Original Contract wsdl
<definitions xmlns:import0="urn:lijo:demos:multiplyservice:messages:v1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:import1="urn:lijo:demos:multiplyservice:data:v1" xmlns:tns="urn:lijo:demos:multiplyservice:calculation:v1" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" name="CalculationService" targetNamespace="urn:lijo:demos:multiplyservice:calculation:v1" xmlns="http://schemas.xmlsoap.org/wsdl/">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" />
<types>
<xsd:schema>
<xsd:import schemaLocation="C:\toolbox\LijosServiceApp\NewService\RestaurantMessages.xsd" namespace="urn:lijo:demos:multiplyservice:messages:v1" />
<xsd:import schemaLocation="C:\toolbox\LijosServiceApp\NewService\RestaurantData.xsd" namespace="urn:lijo:demos:multiplyservice:data:v1" />
</xsd:schema>
</types>
<message name="getMultipliedIn">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" />
<part name="parameters" element="import0:getMultiplied" />
</message>
<message name="getMultipliedOut">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" />
<part name="parameters" element="import0:getMultipliedResponse" />
</message>
<portType name="CalculationServiceInterface">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" />
<operation name="getMultiplied">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" />
<input message="tns:getMultipliedIn" />
<output message="tns:getMultipliedOut" />
</operation>
</portType>
<binding name="BasicHttpBinding_CalculationServiceInterface" type="tns:CalculationServiceInterface">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="getMultiplied">
<soap:operation soapAction="urn:lijo:demos:multiplyservice:calculation:v1:getMultipliedIn" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
</operation>
</binding>
<service name="CalculationServicePort">
<port name="CalculationServicePort" binding="tns:BasicHttpBinding_CalculationServiceInterface">
<soap:address location="http://localhost/CalculationService" />
</port>
</service>
</definitions>
I figured it out. For the benefit of others I will explain it here.
Before that please refer answer to the 400 Bad Request Exception: Simple SOAP WCF service with small data for some debugging ideas.
This due to Format SOAP Action option in WCSF Blue tool.
I have used "Format Soap Actions" while generating the code using WCSF Blue. But while client, I did not use the tool. That mismatch is the key issue.
Format Soap Actions force the SOAP actions (Action and ReplyAction) applied to each operation contract follow the standard WCF format:
<namespace>/<service>/<operation>[Response]
If I have no control over the client, I should not use Format SOAP Action option in WCSF Blue Tool.
Please refer Service works from wcfTestClient but fails in Console Application for a working example.
[Still I have a question - what if I have no control over the client still need to use ReplyAction? What will be the URI in xml format in such scenario that is to be used in the client and service ? ]
General Debugging Ideas:
Ensure that the service is good by using wcfTestClient (type wcfTestClient in VS command prompt to launch)
Use Tracing as mentioned in How to turn on WCF tracing?
Verify that the configuration values are in web.config/app.config and not in output.config (in case of auto generation using tools)
Verify that you are referring proper wsdl (is it local file or url from running service?)
Verify that the wsdl can be viewed by browsing the svc file. Metadata is enabled
Check whether it is relative path or absolute path in the "address" in the service
You are right that there is an issue in ReplyAction. When ReplyAction is set to "*" makes WCF to ignore that operation. Correct the ReplyAction to your operation contract will work.
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/41f5fe72-3ab3-4741-867e-a93119fe62aa
We have a WSDL which contains the following type definition:
...
<xsd:complexType name="OrderItem">
<xsd:all>
<xsd:element name="source" type="xsd:string" />
</xsd:all>
</xsd:complexType>
<xsd:complexType name="OrderItems">
<xsd:sequence>
<xsd:element name="item" type="tns:OrderItem" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
...
When adding the service as a Service Reference in VS 2010, the OrderItems class contains an item property which is of type OrderItem[]. The SOAP request is then generated as follows:
...
<items>
<OrderItem>
<item>foo</item>
<item>bar</item>
</OrderItem>
</items>
...
Using the XmlArray and XmlArrayItem attributes we can control the names of the <OrderItem> and <item> elements respectively, but can't get to the desired structure:
...
<items>
<item>foo</item>
<item>bar</item>
</items>
...
I'm aware that this problem could be avoided if the WSDL specified something like <xsd:restriction base="soap-enc:Array"> rather than an unbounded sequence, but given the above is the only way forward to use some custom serialization?
EDIT: Example WSDL at https://gist.github.com/1422704
It seems that .NET WCF services do not play nice with our WSDL (which was manually created with a focus on the XSD and not on SOAP).
The easiest way to get the SOAP API to work with .NET was to alter the WSDL to use the SOAP array type, so <items> becomes a soap-enc:Array with soap-enc:arrayType="tns:OrderItem[]".
The resulting XML generated by the Service Reference's auto-generated code is then correct.
In my XSD, I have something similar to this:
<?xml version="1.0" encoding="utf-8" ?>
<schema xmlns:jump="testThingy" elementFormDefault="qualified" targetNamespace="testThingy" xmlns="http://www.w3.org/2001/XMLSchema">
<element name="command" type="jump:commandType" />
<complexType name="loginType">
<sequence>
<element name="userName" />
</sequence>
</complexType>
<complexType name="commandType">
<sequence>
<choice>
<element name="login" type="jump:loginType" />
<element name="logout" />
</choice>
<!-- There are other elements here but they are IRRELEVANT to the question -->
</sequence>
</complexType>
</schema>
So, using an XSD to C# tool (xsd.exe or Xsd2Code), this generates 2 classes (commandType and loginType). But, if I wanted dto submit a logout command, the XML needs to look like this:
<command>
<logout />
</command>
But, I haven't got - whatever the equivalent of a - logoutType. In the generated class, if I wanted to use logout, then commandType is expecting an "XmlElement".
Assuming the XSD to C# tools can't generate this class for me, how do you write a class that basically comes down to just serializing to and is of type XmlElement so it fits with the commandType?
(note: I have no control over the XSD's, otherwise I would have changed it to include a new complexType)
Based on the schema that has now been posted, it's clear why you have an XmlElement for logout. What do you think the type of the logout element is? It's xs:anyType. It could be anything at all. The only .NET type that matches that is XmlElement, unless you prefer object.
What did you want instead of XmlElement?
I've been trying for a couple of days now to get a .NET client working fully with a Web Server provided by my Coldfusion-based web app. I'm not a .NET developer, per se, but I happen to have a copy of VS 2003, which seems like it should do the trick.
I can use a simple multiplier() method in my web service that takes two numbers and returns a number, so simple types are working fine. It's the complex types that are killing me. I'm basically trying to return an associative array from a method called get_struct(). I get an object of type Map back, but the property (called item), which is supposed to be an array with two elements (of type mapItem) always has an "undefined value".
Here's the WSDL that is generated 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's the web service stub generated when I add a web reference in 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 app that tests 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 is always "undefined value" according to the debugger. The printed output looks like:
Instantiating WS
Calling multiplier(3,15)
45
Calling get_struct()
result: pfapi_test.remote_io_test.Map
result.item:
Press Enter to exit...
I've tried using ColdFusion 8, and there's no difference. I've tried returning a real custom database with two properties instead of my ad-hoc associative array, and that works fine, but rewriting my API to avoid associative arrays isn't really an option at this time. The API works fine with ColdFusion, PHP/NuSOAP, and Ruby on Rails, so it seems like it should be possible to get it working with .NET as well.
I hope someone can provide some insight. I have the suspicion that there's some kind of namespace issue here, but I don't know SOAP and XML well enough to figure out what it is. I've also searched like mad for a solution online, but I haven't found a single person who's solved this problem, which is very disheartening!
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>
Response:
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's tried all of the following to no avail:
using WCF instead of ASMX
using .NET 3.5
using VB.NET to communicate with the web service instead of C#
He did send me a screenshot of the "Data Type" section of the Service Reference Settings dialog. Is it possible that changing the settings for Collection type and Dictionary collection type might resolve this issue?
Update 2: here's 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's 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 thanks in advance for your replies!
Cross-posted at link text
I've been struggling with this item myself from the .NET client side of things - I'm trying to consume a web service written in ColdFusion. From the documentation I found, the struct data type in ColdFusion does not map directly onto any Web Services types, and it would seem to me that it is a fault with Axis.
You've probably read the same web pages as I have when trying to solve this problem, but it would seem if you want to create a web service using ColdFusion, the recommendation is not to use the struct type. If your web service is not live yet, and you can get away with using something different, I would suggest going down this route. I tried returning objects from ColdFusion, which worked fine for me from a .NET client.
I actually gave up on this problem and wrote a custom client for my .NET program which would just read the Xml returned by the ColdFusion web service and convert this into a dictionary, as I have no influence over the service I am trying to call.
One thing I did find during my testing - the service I am trying to call is running on an older version of ColdFusion (7 I believe). Whenever I call that service, the .NET client returns null. I installed ColdFusion on my own machine and wrote a simple service, and found that the .NET client returned an object of type Map (which had come from the WSDL), but the properties of the Map object were all null.
I'd be interested to see if Chris Haas's suggestion in the comments to your question of setting dotNetSoapEncFix solves the problem.
The answer is: don't use Coldfusion structs in your web service.
Like everyone else before us, we gave up and rewrote our API to not use any associative arrays in the request or response. We're now using scalars, arrays, and complexTypes that are automatically created from CFCs. This time around, we tested our proof-of-concept with PHP, Ruby, Coldfusion, Java, and .NET to make sure it was actually interoperable.
It makes a lot of sense now that a statically-typed language would be unable to handle a totally arbitrary remote datatype in any sensible way.
Thanks for all of your feedback!
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 lays here to be exact:
<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 redefine those types like this:
<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 doesn't fully conform to the WS-I profiles mentioned above , because of the element names, but it should be very easy to process by the clients and the class file generators.
I wrote this solution for others who would stumble upon this problem :)
And by the way WSDL and SOAP it is a one big pain in the.... ;)