我已经尝试了几天让.NET客户端完全使用基于Coldfusion的Web应用程序提供的Web服务器。我本身不是.NET开发人员,但我碰巧有一份VS 2003的副本,看起来应该可以解决这个问题。
我可以在我的Web服务中使用一个简单的multiplier()方法,它接受两个数字并返回一个数字,因此简单的类型工作正常。这是复杂的类型,正在杀死我。我基本上试图从一个名为get_struct()的方法返回一个关联数组。我得到一个类型为Map的对象,但属性(称为item),应该是一个包含两个元素(类型为mapItem)的数组,总是有一个“未定义的值”。
这是ColdFusion生成的WSDL:
<?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>
这是我在VS中添加Web引用时生成的Web服务存根:
//------------------------------------------------------------------------------
// <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 {
}
}
最后,我的CLI应用程序测试服务:
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();
}
}
}
无论我尝试什么,根据调试器,Struct.item始终是“未定义的值”。打印输出如下:
Instantiating WS
Calling multiplier(3,15)
45
Calling get_struct()
result: pfapi_test.remote_io_test.Map
result.item:
Press Enter to exit...
我尝试过使用ColdFusion 8,但没有区别。我已经尝试使用两个属性而不是我的ad-hoc关联数组返回一个真正的自定义数据库,并且工作正常,但是重写我的API以避免关联数组目前不是一个真正的选项。该API适用于ColdFusion,PHP / NuSOAP和Ruby on Rails,因此似乎应该可以使用.NET。
我希望有人可以提供一些见解。我怀疑这里存在某种命名空间问题,但我不太了解SOAP和XML,无法弄清楚它是什么。我也疯狂搜索在线解决方案,但我找不到一个人解决了这个问题,这非常令人沮丧!
请求:
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>
响应:
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>
更新:我从另一端的.NET开发人员那里听说,他尝试了以下所有方面都无济于事:
他确实向我发送了“服务参考设置”对话框的“数据类型”部分的屏幕截图。是否可能更改Collection类型和Dictionary集合类型的设置可能会解决此问题?
更新2:这是remote_io_test.cfc的
的ColdFusion代码<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 --->
感谢您的阅读,并提前感谢您的回复!
交叉发布答案 0 :(得分:2)
我自己从.NET客户端一直在努力解决这个问题 - 我正在尝试使用ColdFusion编写的Web服务。从我发现的文档中,ColdFusion中的struct数据类型不直接映射到任何Web Services类型,在我看来它是Axis的错误。
您可能已经阅读了与尝试解决此问题时相同的网页,但如果您想使用ColdFusion创建Web服务,建议不要使用结构类型。如果您的网络服务尚未生效,并且您可以使用不同的东西,我会建议沿着这条路走下去。我尝试从ColdFusion返回对象,这对我来说非常适合.NET客户端。
我实际上放弃了这个问题并为我的.NET程序编写了一个自定义客户端,它只读取ColdFusion Web服务返回的Xml并将其转换为字典,因为我对我正在尝试的服务没有任何影响打电话。
我在测试期间找到的一件事 - 我试图调用的服务是在旧版本的ColdFusion上运行(我相信7)。每当我调用该服务时,.NET客户端都会返回null。我在自己的机器上安装了ColdFusion并编写了一个简单的服务,发现.NET客户端返回了一个Map类型的对象(它来自WSDL),但是Map对象的属性都是null。
我有兴趣看看Chris Haas在你的设置dotNetSoapEncFix问题的评论中是否能解决这个问题。
答案 1 :(得分:1)
答案是:不要在Web服务中使用Coldfusion结构。
与我们之前的其他人一样,我们放弃并重写了我们的API,以便在请求或响应中不使用任何关联数组。我们现在使用从CFC自动创建的标量,数组和complexType。这一次,我们使用PHP,Ruby,Coldfusion,Java和.NET测试了我们的概念验证,以确保它实际上是可互操作的。
现在很有意义的是,静态类型的语言无法以任何合理的方式处理完全任意的远程数据类型。
感谢您的所有反馈!
答案 2 :(得分:0)
您的问题有一个解决方案,就在这里:
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
你的问题确切存在:
<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>
重新定义这样的类型:
<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>
由于元素名称,它仍然不完全符合上面提到的WS-I配置文件,但是客户端和类文件生成器应该很容易处理它。
我为那些偶然发现这个问题的人写了这个解决方案:)
顺便说一句,WSDL和SOAP是一个很大的痛苦......;)