使用具有复杂对象的 KSoap2 调用 WCF 服务。 WCF 接收空值

Calling WCF Service with KSoap2 with complex objects. WCF receives empty values

我有一个接收和 returns 编译对象的 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; }
}

Android 使用 KSoap2 的代码

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 Forms 测试应用程序测试了 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 的信息,我也没有找到解决方案。有人可以帮我解决这个问题吗?

尝试使用 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; }
    }

如果问题仍然存在,请随时告诉我。

更新

我也觉得这是序列化的问题。我不知道你是如何调用服务的。如果我们通过添加服务引用来调用它,客户端 class 应该如下所示:

经过几个小时的调查,我已经解决了这个问题。我会post这个答案来帮助遇到同样情况的其他人。

使用 SoapUI 我看到了命名空间和 XML 发送然后尝试使用 KSoap2 生成类似的东西。

在我的 class 中,我在 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;
    }
}

然后在我的 class 中添加了一个生成 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 如此详细以接收正确的参数。所以希望我的回答能帮到有同样问题的人。