使用具有复杂对象的 KSoap2 调用 WCF 服务。 WCF 接收空值
Posted
技术标签:
【中文标题】使用具有复杂对象的 KSoap2 调用 WCF 服务。 WCF 接收空值【英文标题】:Calling WCF Service with KSoap2 with complex objects. WCF receives empty values 【发布时间】:2020-12-02 04:24:49 【问题描述】:我有一个接收和返回复杂对象的 WCF 服务,我需要在 android 中调用它。我已经阅读了很多如何使用 Ksoap 的内容,目前我的应用正在调用 WCF 服务,但 WCF 服务在请求对象的属性中接收到空值。
WCF 服务
[OperationContract]
WrAsignChkResponse CheckTrsRequest(WrAsignChkModel WrAsignData);
//Request and response objects in .Net
public class WrAsignChkModel
public string Arg1 get; set;
public string Arg2 get; set;
public string Arg3 get; set;
public string Arg4 get; set;
public class WrAsignChkResponse
public int ResponseCode get; set;
public string Message get; set;
public string RequestStatus get; set;
public string RequestTimeStamp get; set;
使用 KSoap2 的 Android 代码
private SoapSerializationEnvelope getWebServiceEnvelope()
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.implicitTypes = true;
return envelope;
private void callWebService()
SoapObject body = new SoapObject(this.callHeader.getNamespace(), this.callHeader.getMethodName());
if (this.parameters != null && !this.parameters.isEmpty())
for (PropertyInfo param : this.parameters)
body.addProperty(param);
SoapSerializationEnvelope envelope = this.getWebServiceEnvelope();
envelope.setOutputSoapObject(body);
envelope.addMapping(callHeader.getNamespace(), "WrAsignData", WrAsignChkModel.class);
HttpTransportSE transport = new HttpTransportSE(this.webServiceUrl, this.timeOut);
transport.debug = true;
transport.call(callHeader.getSoapAction(), envelope);
this.soapResponse = envelope.getResponse();
我在 Android 中也有实现 KVM Serializable 的请求对象。
public class WrAsignChkModel implements KvmSerializable
private String Arg1;
private String Arg2;
private String Arg3;
private String Arg4;
//Getter and setters
@Override
public Object getProperty(int index)
switch(index)
case 0:
return Arg1;
//...
return null;
@Override
public int getPropertyCount()
return 4;
@Override
public void setProperty(int index, Object value)
switch(index)
case 0:
Arg1 = value.toString();
break;
//...
default:
break;
@Override
public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info)
switch(index)
case 0:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Arg1";
break;
//...
default:
break;
HttpTransportSE 请求转储 通过此请求,WCF 服务将在 WrAsignData 对象中接收空值
<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/">
<v:Header />
<v:Body>
<CheckTrsRequest xmlns="http://tempuri.org/">
<WrAsignData>
<Arg1>XXXX</Arg1>
<Arg2>XXXX</Arg2>
<Arg3>XXXX</Arg3>
<Arg4>XXXX</Arg4>
</WrAsignData>
</CheckTrsRequest>
</v:Body>
</v:Envelope>
我已经使用 Windows 窗体测试应用程序测试了 Web 服务,并且我已经捕获了该应用程序使用 wireshark 发送的 XML,我发现这是参数命名空间的差异。
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<CheckTrsRequest xmlns="http://tempuri.org/">
<WrAsignData xmlns:a="http://schemas.datacontract.org/2004/07/Models.TrsApiModel" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Arg1>XXXX</a:Arg1>
<a:Arg2>XXXX</a:Arg2>
<a:Arg3>XXXX</a:Arg3>
<a:Arg4>XXXX</a:Arg4>
</WrAsignData>
</CheckTrsRequest>
</s:Body>
</s:Envelope>
互联网上没有很多关于如何正确使用 KSoap2 的信息,我也没有找到解决方案。有人可以帮我解决这个问题吗?
【问题讨论】:
【参考方案1】:尝试使用 Datacontract 和 DataMember:
[DataContract]
public class WrAsignChkModel
[DataMember]
public string Arg1 get; set;
[DataMember]
public string Arg2 get; set;
[DataMember]
public string Arg3 get; set;
[DataMember]
public string Arg4 get; set;
[DataContract]
public class WrAsignChkResponse
[DataMember]
public int ResponseCode get; set;
[DataMember]
public string Message get; set;
[DataMember]
public string RequestStatus get; set;
[DataMember]
public string RequestTimeStamp get; set;
如果问题仍然存在,请随时告诉我。
更新
我也认为这是一个序列化问题。我不知道你怎么称呼这项服务。如果我们通过添加服务引用来调用它,客户端类应该如下所示:
【讨论】:
嗨!我已将它添加到 .Net 代码的 resquest 和 response 对象上,但仍然是同样的问题。我认为问题可能出在 KSoap 序列化中。感谢您的帮助! 我更新我的回复,客户端和服务端类都需要添加DataMember。 您在客户端没有序列化属性。 抱歉,我没有在客户端使用 .Net。我正在使用 Android 中 Java 的 KSoap2 库调用该服务 建议你根据服务的WSDL文件生成一个代理类来调用WCF服务。【参考方案2】:经过数小时的调查,我已经解决了这个问题。我会发布答案以帮助遇到同样情况的其他人。
使用 SoapUI,我看到了要发送的命名空间和 XML,然后尝试使用 KSoap2 生成类似的东西。
在我的课程中,我在 getPropertyInfo 方法中添加了命名空间。它是所有属性的相同命名空间,这将生成一个包含所有标签中命名空间的 XML。与我在问题中提到的 XML 不同。但是没关系,而且兼容。
@Override
public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info)
switch(index)
case 0:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Arg1";
info.namespace = "http://schemas.datacontract.org/2004/07/Models.TrsApiModel"
break;
//...
default:
break;
然后在我的班级中,我添加了一个生成 SoapObject 的方法。命名空间与对象内部的属性不同。
public SoapObject getSoapRequest(String nameSpace, String name)
SoapObject soapRequest = new SoapObject(nameSpace, name);
for(int i = 0; i < this.getPropertyCount(); i++)
PropertyInfo prp = new PropertyInfo();
this.getPropertyInfo(i, null, prp);
prp.setValue(this.getProperty(i));
soapRequest.addProperty(prp);
return soapRequest;
如果您有要发送的 SoapObject,则必须使用 addSoapObject 方法将 int 添加到 Body SoapObject。
SoapObject body = new SoapObject(this.callHeader.getNamespace(), this.callHeader.getMethodName());
//soapObj is an instance using the getSoapRequest() method mentioned in my piece of code
body.addSoapObject(soapObj);
SoapSerializationEnvelope envelope = this.getWebServiceEnvelope();
envelope.setOutputSoapObject(body);
使用该代码,一切似乎都可以正常工作,但并非完全正常。我经历过一些参数被服务器很好地接收,但不是全部。另一件棘手的事情是对象属性必须与 SoapUi 请求中的参数的顺序相同。因此,您必须修改对象方法中的开关,以使索引的顺序与您在 SoapUI XML 请求中看到的顺序相同。
注意与索引顺序一致的方法
public Object getProperty(int index)
public void setProperty(int index, Object value)
public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info)
我花了很多时间才发现 WCF 是如何如此详细地接收正确的参数。所以希望我的回答能帮助遇到同样问题的人。
【讨论】:
以上是关于使用具有复杂对象的 KSoap2 调用 WCF 服务。 WCF 接收空值的主要内容,如果未能解决你的问题,请参考以下文章
Ksoap2 Android - 如何为复杂对象的子属性指定命名空间?