Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

passing objects to wcf soap service from android using ksoap2; it sends and receives 0

I am trying to use ksoap2 to access methods in a wcf soap service from android. I was able to successfully pass simple type parameters to the method, it worked fine. But when I try to pass objects, the wcf method is receiving 0 for all the object values.

I have used the same SOAP service with a WP7 app and it runs fine.

I have 2 methods in my service, ksoapadd and addParam. addParam takes in two integer and returns their sum(this works). ksoapadd takes in an object of class testadd which has two integer elements and ksoapadd returns their sum(this gets and sends 0).

I think it has something to do with the namespace but I can't figure out how to resolve it. I have been doing trial and error to get the soap request right, but no luck yet.

Can anyone help me figure out what to do? I have tried many options which somehow helped other people with similar problem but with no avail.

here is my wsdl:

<?xml version="1.0" encoding="UTF-8"?>
-<wsdl:definitions xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex"
xmlns:wsa10="http://www.w3.org/2005/08/addressing" 
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" 
xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" 
xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" 
xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" 
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" 
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" 
xmlns:tns="http://tempuri.org/" 
xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" 
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
targetNamespace="http://tempuri.org/" name="Service1">
-<wsdl:types>
-<xsd:schema targetNamespace="http://tempuri.org/Imports">
<xsd:import namespace="http://tempuri.org/" schemaLocation="http://localhost:51086/Service1.svc?xsd=xsd0"/>
<xsd:import namespace="http://schemas.microsoft.com/2003/10/Serialization/" schemaLocation="http://localhost:51086/Service1.svc?xsd=xsd1"/>
<xsd:import namespace="http://schemas.datacontract.org/2004/07/InsertIntoUserWCF" schemaLocation="http://localhost:51086/Service1.svc?xsd=xsd2"/>
</xsd:schema>
</wsdl:types>
-<wsdl:message name="IService1_ksoapAdd_InputMessage">
<wsdl:part name="parameters" element="tns:ksoapAdd"/>
</wsdl:message>
-<wsdl:message name="IService1_ksoapAdd_OutputMessage">
<wsdl:part name="parameters" element="tns:ksoapAddResponse"/>
</wsdl:message>
-<wsdl:message name="IService1_addParam_InputMessage">
<wsdl:part name="parameters" element="tns:addParam"/>
</wsdl:message>
-<wsdl:message name="IService1_addParam_OutputMessage">
<wsdl:part name="parameters" element="tns:addParamResponse"/>
</wsdl:message>
-<wsdl:portType name="IService1">
-<wsdl:operation name="ksoapAdd">
<wsdl:input message="tns:IService1_ksoapAdd_InputMessage"    wsaw:Action="http://tempuri.org/IService1/ksoapAdd"/>
<wsdl:output message="tns:IService1_ksoapAdd_OutputMessage" wsaw:Action="http://tempuri.org/IService1/ksoapAddResponse"/>
</wsdl:operation>
-<wsdl:operation name="addParam">
<wsdl:input message="tns:IService1_addParam_InputMessage" wsaw:Action="http://tempuri.org/IService1/addParam"/>
<wsdl:output message="tns:IService1_addParam_OutputMessage" wsaw:Action="http://tempuri.org/IService1/addParamResponse"/>
</wsdl:operation>
</wsdl:portType>
-<wsdl:binding name="BasicHttpBinding_IService1" type="tns:IService1">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
-<wsdl:operation name="InsertUserDetails">
<soap:operation style="document" 
-<wsdl:operation name="ksoapAdd">
<soap:operation style="document" soapAction="http://tempuri.org/IService1/ksoapAdd"/>
-<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
-<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
-<wsdl:operation name="addParam">
<soap:operation style="document" soapAction="http://tempuri.org/IService1/addParam"/>
-<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
-<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
-<wsdl:service name="Service1">
-<wsdl:port name="BasicHttpBinding_IService1" binding="tns:BasicHttpBinding_IService1">
<soap:address location="http://localhost:51086/Service1.svc"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

this is my xsd2:

<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema xmlns:tns="http://schemas.datacontract.org/2004/07/InsertIntoUserWCF"
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://schemas.datacontract.org/2004/07/InsertIntoUserWCF" 
elementFormDefault="qualified">
-<xs:complexType name="testadd">
-<xs:sequence>
<xs:element name="number_1" type="xs:int" minOccurs="0"/>
<xs:element name="number_2" type="xs:int" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:element name="testadd" type="tns:testadd" nillable="true"/>
</xs:schema>

here is my soap request:

<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>
<ksoapAdd xmlns="http://tempuri.org/" id="o0" c:root="1">
<n0:num1 xmlns:n0="http://tempuri.org/">
<number_1>25</number_1>
<number_2>25</number_2>
</n0:num1>
</ksoapAdd>
</v:Body>
</v:Envelope>

soap response:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ksoapAddResponse xmlns="http://tempuri.org/">
<ksoapAddResult>0</ksoapAddResult>
</ksoapAddResponse>
</s:Body>
</s:Envelope>

this is my java code using ksoap2:

private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "http://10.0.2.2:51086/Service1.svc?wsdl";
private static final String SOAP_ACTION4 = "http://tempuri.org/IService1/ksoapAdd";
private static final String METHOD_NAME4 = "ksoapAdd";
private static final String SOAP_ACTION5 = "http://tempuri.org/IService1/addParam";
private static final String METHOD_NAME5 = "addParam";

try {
    testadd numX = new testadd(25,25);

    SoapObject Request = new SoapObject(NAMESPACE, METHOD_NAME4);

    PropertyInfo prop = new PropertyInfo();
    prop.setNamespace(NAMESPACE);
    prop.setName("num1");
    prop.setType(numX.getClass());
    prop.setValue(numX);
    Request.addProperty(prop);

    SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    envelope.dotNet = true;
    envelope.setOutputSoapObject(Request);

    envelope.implicitTypes = true;

    HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
    androidHttpTransport.debug=true;
    androidHttpTransport.call(SOAP_ACTION4, envelope);

    Log.d(logtag + " request dump", androidHttpTransport.requestDump);
    Log.d(logtag + " response dump", androidHttpTransport.responseDump);

    final SoapPrimitive response = (SoapPrimitive)envelope.getResponse();
    final int num = Integer.parseInt(response.toString());

    } catch (Exception e) 
    {
        e.printStackTrace();
    }

this is my java class testadd:

import java.util.Hashtable;
import org.ksoap2.serialization.KvmSerializable;
import org.ksoap2.serialization.PropertyInfo;

public class testadd implements KvmSerializable{
int number1;
int number2;

testadd(){}
testadd(int a, int b){ number1 = a; number2 = b;}


@Override
public Object getProperty(int arg0) {
    switch(arg0)
    {
    case 0:
        return number1;
    case 1:
        return number2;

    }

return null;
}

@Override
public int getPropertyCount() {

    return 2;
}

@Override
public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo arg2) {

     switch(arg0)
        {
        case 0:
            arg2.type = PropertyInfo.INTEGER_CLASS;
            arg2.name = "number_1";
            break;
        case 1:
            arg2.type = PropertyInfo.INTEGER_CLASS;
            arg2.name = "number_2";
            break;

        default:break;
        }

}

@Override
public void setProperty(int arg0, Object value) {

    switch(arg0)
    {
    case 0:
       number1 = Integer.parseInt(value.toString());
        break;
    case 1:
        number2 = Integer.parseInt(value.toString());
        break;

    default:
        break;
    }
}
}

service code:

<ServiceContract()> _
Public Interface IService1
<OperationContract()> _
Function ksoapAdd(ByVal num1 As testadd) As Integer

<OperationContract()> _
Function addParam(ByVal num1 As Integer, ByVal num2 As Integer) As Integer

End Interface

<DataContract()> _
Public Class testadd
Private number1 As Integer
Private number2 As Integer

<DataMember()> _
Public Property number_1() As Integer
    Get
        Return number1
    End Get
    Set(ByVal value As Integer)
        number1 = value
    End Set
End Property

<DataMember()> _
Public Property number_2() As Integer
    Get
        Return number2
    End Get
    Set(ByVal value As Integer)
        number2 = value
    End Set
End Property

End Class

service methods:

Public Function ksoapAdd(ByVal num1 As testadd) As Integer Implements IService1.ksoapAdd
    MsgBox(num1.number_1)
    Return num1.number_1 + num1.number_2
End Function

Public Function addParam(ByVal num1 As Integer, ByVal num2 As Integer) As Integer Implements IService1.addParam
    MsgBox(num1 + num2)
    Return num1 + num2
End Function

I know this is a lot of code, but it think its necessary to understand the whole picture.

Thank you!

like image 487
Ravi Chimmalgi Avatar asked Oct 11 '12 18:10

Ravi Chimmalgi


1 Answers

I finally got it to work!

Turns out my android ksoap2 code didn't like the default namespace(tempuri.org) set by WCF in the SOAP service.

My guess is that with the default namespace, the request envelop was unable to map the passed testadd object to the datacontract in which the testadd class is defined in the service. By defining a namespace explicitly to the servicecontract and datacontract in the WCF service, this changes/rearranges the wsdl and makes the datacontract accessible.

I followed this tutorial to get rid of the tempuri.org namespace- http://blogs.msdn.com/b/endpoint/archive/2011/05/12/how-to-eliminate-tempuri-org-from-your-service-wsdl.aspx

I added the following in the appropriate places in the service code (VB)

<ServiceContract(Namespace:="http://wcfservicetest.org/Service1")> _
<DataContract(Namespace:="http://wcfservicetest.org/Service1")> _
<ServiceBehavior(Namespace:="http://wcfservicetest.org/Service1")> _

I changed my namespace to "http://wcfservicetest.org/Service1" and edited NAMESPACE and SOAP_ACTION in the android java code with the new namespace.

After doing this I got the result I wanted!

Here is the soap request:

<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>
<ksoapAdd xmlns="http://wcfservicetest.org/Service1" id="o0" c:root="1">
<n0:num1 xmlns:n0="http://wcfservicetest.org/Service1">
<number_1>25</number_1>
<number_2>25</number_2>
</n0:num1>
</ksoapAdd>
</v:Body>
</v:Envelope>

soap response:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<ksoapAddResponse xmlns="http://wcfservicetest.org/Service1">
<ksoapAddResult>50</ksoapAddResult>
</ksoapAddResponse>
</s:Body>
</s:Envelope>

So my advice to anyone else learning SOAP services with ksoap2, do no use the default namespace, set your own namespace. I wasted a week trying to figure this out.

Hope this helps someone someday!!

like image 79
Ravi Chimmalgi Avatar answered Oct 17 '22 00:10

Ravi Chimmalgi