【问题标题】:Calling WCF Service with KSoap2 with complex objects. WCF receives empty values使用具有复杂对象的 KSoap2 调用 WCF 服务。 WCF 接收空值
【发布时间】: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 的信息,我也没有找到解决方案。有人可以帮我解决这个问题吗?

【问题讨论】:

    标签: android wcf soap ksoap2 android-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 是如何如此详细地接收正确的参数。所以希望我的回答能帮助遇到同样问题的人。

    【讨论】:

      猜你喜欢
      • 2016-02-11
      • 1970-01-01
      • 2016-06-27
      • 2014-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多