KSoap Android Web Service Tutorial With Sample Code



A few months ago I was engaged into working with Android and I wanted to make an application that will communicate with the server via .NET SOAP web services, but I soon found out that I will need a library to do the "donkey work for me". Unfortunately, what Visual Studio was doing for me behind the scenes when importing WSDL document, was not present in Android. That means that, I would either parse the WSDL XML myself, or use an external library. After little search, I came up to KSOAP, which looked like a promising library. But soon I got into lot of trouble to make it work.
Partly because there was no complete tutorial with the WHOLE sample WORKING code for passing complex objects as parameters and/or arrays as return values (read this post for returning arrays of objects with KSOAP ), I spent many hours debugging exceptions which were filled with nulls and poor documentation in first place.

Therefore I decided to publish the code I managed to make it work, so many lives will be saved :-) hopefully. I almost forgot about the idea of publishing my code, but today I got some e-mails from some of the Google groups where I was begging for help when I was developing the Android application. So, tortured developer souls, a complete working code for working with the KSOAP library for Android:

Scenario:
We will assume that we want to write a web service that retrieves the details about a given Category by its Id. So, in .NET, the service signature would be:


[Web Method]
public Category GetCategoryById(Category C);

The class that we want to work with has 3 properties: CategoryId, Name and Description. But in order to use it with KSOAP, we need to implement the KvmSerializable interface (Code below is in Java):


package CommonObjects;

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

/**
 * 
 * @author Vladimir
 * Represents the Category object. KvmSerializable interface needs to be 
 * implemented for performing serialization.
 */
public class Category implements KvmSerializable
{
    public int CategoryId;
    public String Name;
    public String Description;
    
    public Category(){}
    

    public Category(int categoryId, String name, String description) {
        
        CategoryId = categoryId;
        Name = name;
        Description = description;
    }


    public Object getProperty(int arg0) {
        
        switch(arg0)
        {
        case 0:
            return CategoryId;
        case 1:
            return Name;
        case 2:
            return Description;
        }
        
        return null;
    }

    public int getPropertyCount() {
        return 3;
    }

    public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
        switch(index)
        {
        case 0:
            info.type = PropertyInfo.INTEGER_CLASS;
            info.name = "CategoryId";
            break;
        case 1:
            info.type = PropertyInfo.STRING_CLASS;
            info.name = "Name";
            break;
        case 2:
            info.type = PropertyInfo.STRING_CLASS;
            info.name = "Description";
            break;
        default:break;
        }
    }

    public void setProperty(int index, Object value) {
        switch(index)
        {
        case 0:
            CategoryId = Integer.parseInt(value.toString());
            break;
        case 1:
            Name = value.toString();
            break;
        case 2:
            Description = value.toString();
            break;
        default:
            break;
        }
    }
}

All methods in this class are members of the KvmSerializable Interface, and are used to tell KSOAPhow to map the properties, read them and write them.

Now, the actual web service call:

public void WebServiceCallExample()
    {
        String NAMESPACE = "http://vladozver.org/";
        String METHOD_NAME = "GetCategoryById";
        String SOAP_ACTION = "http://vladozver.org/GetCategoryById";
        String URL = "http://192.168.1.3/VipEvents/Services/CategoryServices.asmx";
        
        SoapObject Request = new SoapObject(NAMESPACE, METHOD_NAME);
        
        /*
         * Create Category with Id to be passed as an argument
         * 
         * */
        Category C = new Category();
        C.CategoryId = 1;
        
        /*
         * Set the category to be the argument of the web service method
         * 
         * */
        PropertyInfo pi = new PropertyInfo();
        pi.setName("C");
        pi.setValue(C);
        pi.setType(C.getClass());
        Request.addProperty(pi);
        
        /*
         * Set the web service envelope
         * 
         * */
        SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
        envelope.dotNet = true;
        envelope.setOutputSoapObject(Request);
        
        envelope.addMapping(NAMESPACE, "Category",new Category().getClass());
        AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(URL);
        /*
         * Call the web service and retrieve result ... how luvly <3
         * 
         * */
        try
        {
            androidHttpTransport.call(SOAP_ACTION, envelope);
            SoapObject response = (SoapObject)envelope.getResponse();
            C.CategoryId =  Integer.parseInt(response.getProperty(0).toString());
            C.Name =  response.getProperty(1).toString();
            C.Description = (String) response.getProperty(2).toString();
            TextView tv = (TextView)findViewById(R.id.TextView01);
            tv.setText("CategoryId: " +C.CategoryId + " Name: " + C.Name + " Description " + C.Description);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }

In order to use this code, make sure that you replace the first three variables in this method with your own. NOTE: The SOAP_ACTION could actually be computed as NAMESPACE + METHOD_NAME

In the lines about the property info, I show how to actually pass a Category class complex object to KSOAP.

PropertyInfo pi = new PropertyInfo();
        pi.setName("Category");
        pi.setValue(C);
        pi.setType(C.getClass());
        Request.addProperty(pi);

Regarding the return type, if your web method returns a complex object (such as ours), you need to tell KSOAP how to handle the response. That is done with the following code:

envelope.addMapping(NAMESPACE, "Category",new Category().getClass());

This part of the code is the actual retrieval of the response:
androidHttpTransport.call(SOAP_ACTION, envelope);
            SoapObject response = (SoapObject)envelope.getResponse();
            C.CategoryId =  Integer.parseInt(response.getProperty(0).toString());
            C.Name =  response.getProperty(1).toString();
            C.Description = (String) response.getProperty(2).toString();

For further reading, see my post about returning an array of complex objects with KSOAP

309 comments:

1 – 200 of 309   Newer›   Newest»
teno said...

i went through the code which u have suggested and it worked fine for me.. however i want to send class to web service. but i am gettin null value while receiving the class in service.. can u suggest me how to do it..?

teno said...

tat was wrong question... forgive me..

JM said...

I'm having a similar problem. I'm getting a "org.xml.sax.SAXException: Deserializing parameter 'custom': could not find deserializer.." error when sending the request. I'm gathering the addMapping method isn't working correctly. The namespace works fine for simple primatives but I have tried lots of variations for the custom type and it's not working. Any ideas? I'd appreciate it.

SeeSharpWriter said...

did you make sure you have implemented KVMSerializable interface ?

and did you add the mapping like this:

envelope.addMapping(NAMESPACE, "Category",new Category().getClass());

SeeSharpWriter said...

The issue on code.google project is considered solved and closed. Please make sure you download the latest version of KSOAP

Anonymous said...

Has anyone tried passing up arrays as parameters? I am unable to.

For example) Try modifying the server to request Category[] instead of Category in the above example and then try and pass in an array of Category.

kSOAP always throws an exception 'Cannot serialize: Category '

SeeSharpWriter said...

Did you also try to change the property type to Array as well?

pi.setType(C.getClass());

Also make sure that the class Category implements
implements KvmSerializable interface.

kishore said...
This comment has been removed by the author.
kishore said...

hi thanks for the post, I am new to java and android, i have been searching for how to pass xml as parameter like authentication of user, i tried with code below but error says object reference not set to an instance of an object,

String xml=EmailAddress>string
Password>string
TokenID>318974764453;

request.addProperty("clsAuthenticateAndGetUserProfileRequest",xml);

for the soap

POST /Services.asmx HTTP/1.1
Host:
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://staringhero.com/AuthenticateUser"


soap:Body>
AuthenticateUser xmlns="http://parkinghero.com/"
clsAuthenticateAndGetUserProfileRequest
clsCredentials
EmailAddress>string /EmailAddress
Password>string/Password
TokenID>string/TokenID
/clsCredentials
/clsAuthenticateAndGetUserProfileRequest
/AuthenticateUser
/soap:Body
/soap:Envelope

SeeSharpWriter said...

So on .NET side, your webservice is invoked but the parameter object properties are null?
As from your code, I can see that you are sending XML as a string, you might try to add the property this way:
String xml = "..."; // contains Email, Password, TokenId etc
PropertyInfo pi = new PropertyInfo();
pi.setName("clsAuthenticateAndGetUserProfileRequest");
pi.setValue(xml);
pi.setType(String.getClass());
Request.addProperty(pi);

I am not sure whether this solves the situation as I am assuming how your code looks like and it is not in front of me.

teno said...

i have a doubt regarding calling WCF service.. can i make use of same SOAPOBJECTS to call WCF Servies also.. If not Please suggest me how to do it..

Henrik said...

Do you have any examples of how to implement the Marshal interface as well? Especially the readInstance and writeInstance methods.

SeeSharpWriter said...

@teno, basically WCF uses http binding stream and it should work the same way as ASMX web service, so you should have no trouble using KSOAP with WCF.

SeeSharpWriter said...

@Henrik, yes I do have implemented the Marshal interface as well, I will post examples later today or tomorrow - thanks for reminding me.

teno said...

thanks for the reply.. when i try calling using same soap objects it is throwing XMLPULLPARSER exception along with some weird exception.. what would be going wrong..? any idea? if you have example please uploaded it.. Thanks..

SeeSharpWriter said...

@Henrik, I published my code for Marshal interface, here it is:

Implementing KSOAP Marshal Interface

SeeSharpWriter said...

@teno, I will need to write my own WCF service - I will reply again and tell you about my experience

kishore said...
This comment has been removed by the author.
kishore said...
This comment has been removed by the author.
kishore said...

hi SeeSharp thanks for ur responce. i tried the code you suggested but i got the following error

11-11 14:37:46.514: WARN/System.err(360): SoapFault - faultcode: 'soap:Client' faultstring: 'Server was unable to read request. ---> There is an error in XML document (1, 332). ---> The specified type was not recognized: name='string', namespace='http://www.w3.org/2001/XMLSchema', at emp xmlns='http://stringhero.com/'>.' faultactor: 'null' detail: org.kxml2.kdom.Node@43d2dc50


this is my code
String name=
"Name>"+"kishore"+"/Name>"+
"Designation>"+"developer"+"/Designation>";

TextView tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

tv=(TextView)findViewById(R.id.text);

SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

PropertyInfo pi = new PropertyInfo();

pi.setName("emp");

pi.setValue(name);

pi.setType(req.getClass());

request.addProperty(pi);

SoapSerializationEnvelope sez=new SoapSerializationEnvelope(SoapEnvelope.VER11);

sez.dotNet = true;

sez.setOutputSoapObject(request);

System.out.println(request);

HttpTransportSE aht= new HttpTransportSE(URL);


aht.setXmlVersionTag("");


try{

aht.call(SOAP_ACTION, sez);

SoapPrimitive resultstring= (SoapPrimitive)sez.getResponse();


System.out.println(resultstring);

tv.setText("result:"+resultstring);


}

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



And this is .net code

[WebMethod] public string employee(clsEmp emp) { try { return "Name : " + emp.Name + ", Designation : " + emp.Designation; } catch (Exception ex) { return "Excetpion : " + ex.Message; } }

kishore said...

hi SeeSharp thanks for ur responce. i tried the code you suggested but i got the following error

11-11 14:37:46.514: WARN/System.err(360): SoapFault - faultcode: 'soap:Client' faultstring: 'Server was unable to read request. ---> There is an error in XML document (1, 332). ---> The specified type was not recognized: name='string', namespace='http://www.w3.org/2001/XMLSchema', at emp xmlns='http://stringhero.com/'>.' faultactor: 'null' detail: org.kxml2.kdom.Node@43d2dc50


this is my code
String name=
"Name>"+"kishore"+"/Name>"+
"Designation>"+"developer"+"/Designation>";

TextView tv;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);

setContentView(R.layout.main);

tv=(TextView)findViewById(R.id.text);

SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

PropertyInfo pi = new PropertyInfo();

pi.setName("emp");

pi.setValue(name);

pi.setType(req.getClass());

request.addProperty(pi);

SoapSerializationEnvelope sez=new SoapSerializationEnvelope(SoapEnvelope.VER11);

sez.dotNet = true;

sez.setOutputSoapObject(request);

System.out.println(request);

HttpTransportSE aht= new HttpTransportSE(URL);


aht.setXmlVersionTag("?xml version=\"1.0\" encoding=\"utf-8\"?>");


try{

aht.call(SOAP_ACTION, sez);

SoapPrimitive resultstring= (SoapPrimitive)sez.getResponse();


System.out.println(resultstring);

tv.setText("result:"+resultstring);


}

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



And this is .net code

[WebMethod] public string employee(clsEmp emp) { try { return "Name : " + emp.Name + ", Designation : " + emp.Designation; } catch (Exception ex) { return "Excetpion : " + ex.Message; } }

SeeSharpWriter said...

Kishore, if you are trying to pass a string as a parameter you need to do the following:
pi.setType(String.getClass());
instead of
pi.setType(req.getClass());

And I also find it a little bit strange that you are passing an XML string as a parameter on Android side but waiting for clsEmp instance on .NET side. I am not sure whether that would work.

kishore said...

hi can u suggest the best way to call this web service.I need to send request in xml format exactly as the below soap, is it possible in ksoap2

For the soap

?xml version="1.0" encoding="utf-8"?>
soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
soap:Body>
employee xmlns="http://abcd.com/">
emp>
Name>string/Name>
Designation>string/Designation>
/emp>
/employee>
/soap:Body>
/soap:Envelope>

responce will be

?xml version="1.0" encoding="utf-8"?>
soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
soap:Body>
employeeResponse xmlns="http://abcd.com/">
employeeResult>string/employeeResult>
/employeeResponse>
/soap:Body>
/soap:Envelope>

SeeSharpWriter said...

I would either change the .NET webservice to have the following signature:

[WebMethod] public string employee(string emp){}

and pass the XML as string from Android,

or

I would make a class in Android called clsEmp which will implement the KVMSerializable interface, just as the class Category in my post

SeeSharpWriter said...

Did you manage to solve the problem yet?

kishore said...

No seesharp the problem is not solved

SeeSharpWriter said...

It could be that XML tags contain the "<" sign, and KSOAP does not expect XML in a string value, so maybe it's a good idea to escape the string first.
On a second thought, is it really necessary to pass XML? Why don't you pass a complex object instead?

Kishore Babu said...

Hai SeeSharp, I have solved the problem. I used java code for solving my problem.

SeeSharpWriter said...

Thanks for posting the solution

Anonymous said...

hi i tried to get the countryid of a particular country in the list and i got it...next i need to get the region of that country using this countryid...But am not getting response...

This is my code

super.onCreate(savedInstanceState);
setContentView(R.layout.main_countryids);
Bundle b=this.getIntent().getExtras();
String countryids=b.getString("TEXT");
//String s="{countryId=5;};";


SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

GetCountryIdModel m=new GetCountryIdModel();
m.countryId=countryids;
PropertyInfo pi = new PropertyInfo();
pi.setName("GetCountryIdModel");
pi.setValue(m);
pi.setType(m.getClass());
request.addProperty(pi);
request.addProperty("GetCountryIdModel", m);

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(URL);

try{
envelope.addMapping(NAMESPACE, "GetCountryIdModel",new GetCountryIdModel().getClass());
androidHttpTransport.call(SOAP_ACTION,envelope);
SoapObject response = (SoapObject)envelope.getResponse();
m.countryId = response.getProperty(0).toString();

System.out.println("coun : "+m.countryId);
System.out.println("response "+response.toString());


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

my model class


package com.AndroidStoreLocater;

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

public class GetCountryIdModel implements KvmSerializable
{

String countryId;

public GetCountryIdModel(){}
public GetCountryIdModel(String countryid){
countryId=countryid;
}

public String getCountryId() {
return countryId;
}

public void setCountryId(String countryId) {
this.countryId = countryId;
}

public Object getProperty(int arg0) {
return countryId;
}

public int getPropertyCount() {
// TODO Auto-generated method stub
return 1;
}

public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo info) {
info.type = PropertyInfo.STRING_CLASS;
info.name = "countryId";
}

public void setProperty(int arg0, Object value) {
countryId = value.toString();


}


}

Anonymous said...

please help me for the above....

Anonymous said...

hi i have taken the countryid of a particular country and using that id i need to get the region list of that particular country....but am not getting the response
....SeeSharpWriter pls help me

my code is
super.onCreate(savedInstanceState);
setContentView(R.layout.main_countryids);
Bundle b=this.getIntent().getExtras();
String countryids=b.getString("TEXT");
//String s="{countryId=5;};";


SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);

GetCountryIdModel m=new GetCountryIdModel();
m.countryId=countryids;
PropertyInfo pi = new PropertyInfo();
pi.setName("GetCountryIdModel");
pi.setValue(m);
pi.setType(m.getClass());
request.addProperty(pi);
request.addProperty("GetCountryIdModel", m);

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(URL);

try{
envelope.addMapping(NAMESPACE, "GetCountryIdModel",new GetCountryIdModel().getClass());
androidHttpTransport.call(SOAP_ACTION,envelope);
SoapObject response = (SoapObject)envelope.getResponse();
m.countryId = response.getProperty(0).toString();

System.out.println("coun : "+m.countryId);
System.out.println("response "+response.toString());


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


my model class is ..

String countryId;

public GetCountryIdModel(){}
public GetCountryIdModel(String countryid){
countryId=countryid;
}

public String getCountryId() {
return countryId;
}

public void setCountryId(String countryId) {
this.countryId = countryId;
}

public Object getProperty(int arg0) {
return countryId;
}

public int getPropertyCount() {
// TODO Auto-generated method stub
return 1;
}

public void getPropertyInfo(int arg0, Hashtable arg1, PropertyInfo info) {
info.type = PropertyInfo.STRING_CLASS;
info.name = "countryId";
}

public void setProperty(int arg0, Object value) {
countryId = value.toString();


}


please help me...

SeeSharpWriter said...

Can you post the code of your web service method as well? Is the web service .NET ?

If yes, then you have to add this line:

envelope.dotNet = true;

after instantiating the envelope object.


Secondly, if your web service works with complex objects, you need to map the class that implements KVMSerializable interface to the envelope, like this:

envelope.addMapping(NAMESPACE, "Category",new Category().getClass());


I hope this helps.

rajesh said...

i m totaly new to android n java, i wwnt to sent user name & password to web service from android eclipse framework, so can u help me out wit complete code & details of how d code flows

SeeSharpWriter said...

Rajesh,
I think you should refer to this tutorial post:

http://seesharpgears.blogspot.com/2010/11/basic-ksoap-android-tutorial.html

Basically, you need to write Web Service with the following definition:

[WebMethod]
public int ValidateUser(string Username, string Password)

After that, go to Eclipse and generate SOAP object to the Web Service's pointing location (for example http://127.0.0.1/ws/ValidateUser.asmx)

Invoke the service like it is described in my tutorial, with the difference that you will pass strings instead of int.

At the end, only compare whether the result of the web service is 1 or 0.

Anonymous said...

YES I GOT IT....It was not .NET ....AND I CHANGED pi.setName("GetCountryIdModel"); TO pi.setName("arg");


Its working fine now...
Thank u so much

Anonymous said...

I need to send two floating point types to the soap..

So when try to send Float values am getting the following error..

ERROR/AndroidRuntime(1370): Caused by: java.lang.RuntimeException: Cannot serialize: -25.237501


-25.237501 is the value that am sending...


So what should i do to send the floating point type to ksoap...

please help me...
Thanks in advance...

SeeSharpWriter said...

You need to write a class that implements the Marshal interface. See the example here:

http://seesharpgears.blogspot.com/2010/11/implementing-ksoap-marshal-interface.html

There I have shown how it would work for double, so the same principle would apply for float.

Anonymous said...

Thanku so much...

Anonymous said...

I am new to java and android..when i try to connect with webservice i get an error message in the textbox.I am trying to calculate temperature.my coding is...


public class test12 extends Activity {


private static final String SOAP_ACTION = "http://tempuri.org/CelsiusToFahrenheit";
private static final String METHOD_NAME = "CelsiusToFahrenheit";
private static final String NAMESPACE = " http://tempuri.org/";
private static final String URL = "http://www.w3schools.com/webservices/tempconvert.asmx";

private EditText celtext;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
celtext=(EditText)findViewById(R.id.EditText01);
celtext.setText("");
}

public void celtofaren(View view) {
webservice();
}

public void webservice()
{
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);


request.addProperty("Celsius","50");

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);

envelope.dotNet = true;
envelope.setOutputSoapObject(request);
AndroidHttpTransport androidHttpTransport = new AndroidHttpTransport(URL);
try {
androidHttpTransport.call(SOAP_ACTION,envelope);
SoapPrimitive result = (SoapPrimitive)envelope.getResponse();
celtext.setText(String.valueOf(result));
} catch (Exception E) {
E.printStackTrace();

}
}
}



plz help me

SeeSharpWriter said...

What error do you get? On what line? How does your webservice definition look like ?

Anonymous said...

I just get "Error" text in the textbox.I could not find what is the error.

SeeSharpWriter said...

On what line of the code do you get the error? Use debug mode to find that out. It would also be useful if you pasted the code of your web service

Anonymous said...

In my response I have variables like option1Id and option2Id.

Eg:
productOptions=anyType{option1Id=2; option2Id=0; option3Id=0; option4Id=0; option5Id=0; optionChoice=1; optionDescription=Green; optionFlag=Color; optionHexColor=#FF0000; optionId=2; optionLTKey=21; productId=14; productSkuCode=ST.AC.DV.2.TST15.09; productSkuId=3; quantityAvailable=0; unitPrice=2.0; };

productOptions=anyType{option1Id=0; option2Flag=Desc; option2Id=5; option3Id=0; option4Id=0; option5Id=0; optionChoice=2; optionDescription=L; optionId=5; optionLTKey=24; productId=14; productSkuCode=ST.AC.DV.2.TST15.09; productSkuId=3; quantityAvailable=0; unitPrice=2.0; };

productOptions=anyType{option1Id=0; option2Id=0; option3Flag=Img; option3Id=9; option4Id=0; option5Id=0; optionChoice=3; optionDescription=Lavendar; optionId=9; optionImage=images/optionImages/k_544_cuivre.jpg; optionLTKey=30; productId=14; productSkuCode=ST.AC.DV.2.TST15.09; productSkuId=3; quantityAvailable=0; unitPrice=2.0; };


So the problem is when the option1Id and option2Id has value 0. Then the loop will stop there and it shows error message "RunTimeException Illegal Property option1Id". So what shud I do to get that even if the value is 0...


SeeSharpWriter please help me...

Thanks in advance....

Anonymous said...

Sorry that was wrong question........forgive me...pls..

Anonymous said...

info.type = PropertyInfo.INTEGER_CLASS;

it was for int

what would type be for map

SeeSharpWriter said...

I don't think you can pass a map just like that. You would need to derive from the Map class and implement KVMSerializable interface, but I have never really done that.

lucrus said...

I can't quite get the point here... you first implemented KvmSerializable, and that's ok, then you manually parsed the server's response with getProperty(...) calls and manually set the Category fields one after the other.

Wasn't all this supposed to do the monkey work for you? So does that mean there's no way to have it done? I expected to see something like

Category result = new Category();
SomeMagicKSOAP2Class.mapResponseToObject(result, envelope.getResponse());

Please tell me I misunderstood...

SeeSharpWriter said...

I know what you mean, but I don't think that is possible out of the box. Maybe there exists some other way, I am not 100% sure.

KSOAP is really poorly documented, so we may not be aware of its full capabilities.

If you find a better way to handle the response, please paste that here.

lucrus said...

Ok, I'll have a look at the KSoap2 source code then. Meanwhile, do you happen to know the difference (in functionality) between implementing KvmSerializable or Marshal? Am I supposed to implement both somewhere in order to have a working solution or are they one alternative to the other?

SeeSharpWriter said...

KvmSerializable is interface for passing and retrieving objects that are part of the web service signature. You need to implement this interface if your web service works with custom types (classes).

Marshal is interface for passing encapsulated (complex)objects within another object. Keep in mind that date and double types are considered to be complex types by KSOAP2. You need to implement this interface when your complex objects encapsulate other objects for which KSOAP2 needs instructions on how to Serialize and Deserialize them within the complex object you are passing to the web service.

Horacio said...

Hello, I've got this property pDataset, in my webservice. Yes, it's
supposed to be a Dataset, but forget about that now. "sendZipFilesToU2" is the method name. With pU2Table
obviously there's no problem. But with pDataset, the value is "xml"
and there is also the schema. I've been trying to add the property
several ways, but it's not working out.
Would anybody have an idea of how to set it correctly?


schemaxml
string



Thanks,
Horacio.

Horacio said...

Sorry, it seems it reads the xml, there is the property of my webservice. ( [] = <> )

[sendZipFilesToU2 xmlns="http://gpetto.ODBC.WebService/"]
[pDataSet][xsd:schema>schemaxmlstring</pU2Table]
[/sendZipFilesToU2]

Horacio said...

Sorry, this is the right one:

[sendZipFilesToU2 xmlns="http://gpetto.ODBC.WebService/"]
[pDataSet]
[xsd:schema] schema [/xsd:schema]xml[/pDataSet]
[pU2Table]string[/pU2Table]
[/sendZipFilesToU2]

Thanks,
Horacio.

Alex R said...

Hello,

Thanks for tutorial, I've use it for a lot of simple web service but I've a problem for another.

My soap message is the following:






a_username
a_password

1
2


3
4





I've try two solution without success:

- Create a new PropertyInfo for all int and add her to the PropertyInfo "idProduct" and "anotherId"
- And the following:
PropertyInfo piProduit = new PropertyInfo();

piProduct.setName("idProduct");
piProduct.setValue("12");
request.addProperty(piProduct);


Have you an id for xml node with more of one child with the same name?

Thanks for help

adhavan said...

hi,
if i want to execute this program behind a proxy,whether i want to pass any proxy this the httptransport??? and also let me know how to find out namespace,soap_action and from a wsdl file.

SeeSharpWriter said...

Hey Alex, please send the XML with [ and ] instead of < and > - they get rendered by the browser and that makes them invisible.
See Horacio's comments to see how to do it.

SeeSharpWriter said...

Horacio, perhaps the best way is to send the XML with its own schema as a string. Have you tried to do that?

SeeSharpWriter said...

Adhavan, I am not sure about working with proxies with httpTransport - never used one so far.

As long as WSDL is concerned, I am not sure if it is possible through KSOAP, since its point is to hide the raw WSDL document from the developer and provide abstractions instead.

You could, however, download the WSDL document directly from its URL and then parse it manually.

Anonymous said...

Good example and tutorial.
Cheers

SeeSharpWriter said...

Thanks, I am really glad you find it helpful

adhavan said...

Thank u. nice tutorial.

Brian said...
This comment has been removed by the author.
brianthesmith said...

Any way you can post the actual soap envelopes for the request and response? It would be helpful in determining how to actually map the xml types to Java. For example, did you have wrapping types around Category using Doc Literal Wrapped notation or was this Doc Literal ?

Sorry not a DotNet developer so I don't know much about WCF. Trying to make this work against an Apache Axis2 service

SeeSharpWriter said...

I am not sure how I to display the actual SOAP.

Anyway, the point of having libraries like KSOAP2 is to hide the details of the communication - perhaps someone else knows more about achieving this?

brianthesmith said...

easiest way to do it is to set debug = true on the transport then dump the request or response....out just use tcpmon

HttpTransportSE httpTransport = new HttpTransportSE(URL);
httpTransport.debug = true;

try
{
httpTransport.call(SOAP_ACTION, envelope);
System.out.println(httpTransport.responseDump);
System.out.println(httpTransport.requestDump);
}
catch(Exception e)
{
e.printStackTrace();
}

brianthesmith said...

I am trying to figure out how to map something like this on the response. I don't know how to deal with an unbounded sequence of elements like Employee using KvmSerializable. All examples I find are dealing with single complex objects containing primitives






1
Brian
Smith


2
Matt
Todd


3
Srdjan
Grubor

theforgery said...

well that sucked, again

<?xml version="1.0" encoding="http://schemas.xmlsoap.org/soap/envelope/" standalone="no"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns1:getEmployeesResponse xmlns:ns1="urn:us:com:asolutions:lnl:hr:service">
<ns1:Employee>
<id>1</id>
<firstName>Brian</firstName>
<lastName>Smith</lastName>
</ns1:Employee>
<ns1:Employee>
<id>2</id>
<firstName>Matt</firstName>
<lastName>Todd</lastName>
</ns1:Employee>
<ns1:Employee>
<id>3</id>
<firstName>Srdjan</firstName>
<lastName>Grubor</lastName>
</ns1:Employee>
</ns1:getEmployeesResponse>
</soapenv:Body>
</soapenv:Envelope>

Gabo said...

Hi, first of all... excellent tutorial...

I have a doubt, I have a webservice who receive a array of 'complex objects' and I couldn't find any sample who explain me how can I do that...

could you tell me how to do this?

Regards

SeeSharpWriter said...

Thanks Gabo, please take a look at this post:

KSOAP 2 - Web Service that returns array of complex objects

Anonymous said...

Hello SeeSharp,

Thanks for the post. Helped me play around with my android code for consuming the webservice.
Unfortunately, i am unable to get my scenario working; though i learnt a lot in the process. I hope you can help me through this mess.

My xml request body needs to be like this:

soapenv:Body>

n1:ServReq xmlns:n1="http://www.url.com">

ReqPre1>

Customer>1400/Customer>

Org>1111/Org>


/ReqPre1>

HiredTier>

Distribution>45/Distribution>

Divis>44/Divis>

/HiredTier>

/n1:ServReq>

/soapenv:Body>



With your way of marshalling:
I end up with something like this when i execute the request through the emulator:

n1:ServReq xmlns:n1="http://www.url.com">

ReqPre1 i:type="n1:ReqPre1">
Customer i:type="d:string">14000/Customer>
Org i:type="d:string">2320/Org>
/ReqPre1>
/n1:ServReq>

The required nesting is achieved. But there are unneeded type specifications in every tag. Please the the required xml request and the xml requested that the code produces. I need the tags to be just <, Customer>/Customer>, Org>/Org> etc.

Could you please guide me towards achieving this?

Thanks
-Soul

SeeSharpWriter said...

I really have no idea how this could be done. Perhaps you will need to change some lines for rendering tags in KSOAP2 source or you MIGHT (I am not sure at all) implement the Marshal interface to tell the XML writer how to serialize your object.

Soul said...

hmmm.....i am going to dig through the options and see how to get this done...i have been wandering around various forums..and what is interesting is..a lot of people have asked similar questions without getting any answer...ill post updates here as soon as i find a way to achieve this sort of a schema in the request...
Thanks SeeSharp!!

cheers
-Soul

8vius said...

Hey thanks a lot of the code. I'm trying to give it a test and i have an int in my properties but in the getProperty(int) method when i say return int it says that it can't convert int to Object yet no one seems to have this problem here. Any idea why this is? I'm developing on BlackBerry btw

8vius said...

Also another question: how does the web service know how to respond and with what structure? Do both objects (client and server Category) have to be exactly the same? And on the server side, does the Category item also have to implement serializable?

SeeSharpWriter said...

I believe the major issue here is that you are developing on Blackberry, while this KSOAP2 is for Android.

And yes, both client and server need to have the class Category with the same definition. On the server, the class does not need to implement KVMSerializable, but should have the .NET attribute Serializable.

8vius said...

kSOAP2 as far as i know is for J2ME in general there are specific ports for Android but the one I have doesn't have Android specific functions. Any idea on the other issues I raised? If i just want to receive a complex object and not send one should I also do the mapping? So far I haven't had issues with what i've done, i send and receive the data properly, but so far it's just been strings

lapaya said...

Thanks in advance... I Got great help on this article...

Anonymous said...

pi.setName("Category") in WebServiceCallExample() is wrong. if you use the code you will get the null value. because "[Web Method]
public Category GetCategoryById(Category C);"
have a variable named as C. so the name must be C.
The correct code is pi.setName("C").

SeeSharpWriter said...

Thank you for noticing that - corrected!

Anonymous said...

Hi,

I'm new to android. Is it possible to pass ArrayList of a nested class. For example ArrayList in the above example and one of the mamber of Category class is ArrayList of another custom class.

Thanks in advance.

Has anyone tried passing up arrays as parameters? I am unable to.

For example) Try modifying the server to request Category[] instead of Category in the above example and then try and pass in an array of Category.

kSOAP always throws an exception 'Cannot serialize: Category '

SeeSharpWriter said...

I can't figure out a solution for that problem yet.

Anyone else has succeeded in passing an array as parameter or complex object with an array as class attribute?

Anonymous said...

BreezeCardVo{ breezecardDetails=1|SerialNumber:02593257367 BreezeCardId:1~CardNickName:firstcard~
riderClass:null|1|SerialNumber:null BreezeCardId:2~CardNickName:Secondcard~
riderClass:null|:}


Hello sir, Please help me to solve this.I am new to android.I want this response to be split in the form of arrays.i have to display each object like Serialnumber,CardNickName seperately in a textview.pls help me how to split it.i am struggling with it.I dont have any idea..

Ehsan-ul-haq said...

hi

i am using ksoap2 to get array return from my php soap lib , i am getting response from php in 2d array how can i fill that in spinner

anyone can help me

thanks

http://pmedia4u.com
http://blogs.eventsrecorder.com

Domnic said...
This comment has been removed by the author.
Domnic said...

Hi there,
This article was tremedrously useful to get my web services client working in Android. I am now stuck at a point where I need to send a Soap Envelop like this.
<a:mobileNumber>07888888888</a:mobileNumber>
<a:tickets>
<b:coupon>
<b:Quantity>5</b:Quantity>
<b:Type>visitor</b:Type>
<b:Value>250</b:Value>
</b:coupon> <b:coupon>
<b:Quantity>2</b:Quantity>
<b:Type>member</b:Type>
<b:Value>20</b:Value>
</b:coupon>

</a:tickets>
The WS implementation has coupon type as an ArrayOfObjects. Could you please guide me on how my KVMSerialize method would look like and how I would create the SOAP envelop.

I tried

tickets.setValue(coupon); tickets.setType(coupon.class);

but I get a compile error that..

The method setValue(String) is undefined for the type PropertyInfo

any help would be highly appreciated.

SeeSharpWriter said...

Please paste the code of your Coupon class

pna said...
This comment has been removed by the author.
pna said...

string

string
string
string
string
string
string
string
string
string
string
string
string
string
string
int
int
int
int
string
string
int

boolean





How can I pass parameters into objusrpref object.
If I use add property I am not able to add parameters into objuspref object.I am able to add into set object all of my parameters.
I am stuck from so many days.

pna said...

this is my class code


SoapObject Request = new SoapObject(NAMESPACE,METHOD_NAME);






































Request.addProperty("SMSFlag", true);




Request.addProperty("pEmail", "pna@gmail.com");
Request.addProperty("sEmail", "pna@gmail.com");
Request.addProperty("batteryLevel", "10");
Request.addProperty("TimeZone", "0500");
Request.addProperty("Mobile1", "00919985542987");
Request.addProperty("Mobile2", "00919985542987");
Request.addProperty("Mobile3", "00919985542987");
Request.addProperty("Mobile4", "00919985542987");
Request.addProperty("Mobile5", "00919985542987");

Request.addProperty("MobileNet1", "00919985542987");
Request.addProperty("MobileNet2", "00919985542987");
Request.addProperty("MobileNet3", "00919985542987");
Request.addProperty("MobileNet4", "00919985542987");
Request.addProperty("MobileNet5", "00919985542987");
Request.addProperty("AlertMode", 1);
Request.addProperty("AlertSYS", 1);
Request.addProperty("VetsLoadFlag", 1);
Request.addProperty("trackInt", 1);

Request.addProperty("notificationType", "");
Request.addProperty("Geofence", "iiit");

Request.addProperty("SpeedLimit", 1);


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

// soapEnvelope.addMapping(Request.getNamespace(), "objusrpref",Category.class);




soapEnvelope.implicitTypes = true;

AndroidHttpTransport aht = new AndroidHttpTransport(URI);
aht.debug = true;
System.out.println("HT REQUEST DUMP" + aht.requestDump);
try{
System.out.println("HT REQUEST DUMP" + aht.requestDump);
aht.call(SOAP_ACTION, soapEnvelope);
System.out.println("HT REQUEST DUMP" + aht.requestDump);
SoapPrimitive resultString = (SoapPrimitive)soapEnvelope.getResponse();
System.out.println("HT REQUEST DUMP" + aht.requestDump);
System.out.println(soapEnvelope.bodyIn.toString());

Log.d(TAG,"result"+resultString);
}
catch(Exception e){
Log.d(TAG,"result");
e.printStackTrace();
}

pna said...

My web service soap1.1 file is as below:

soap:Body>
Set>
collarID>string
objusrpref>
pEmail>string
sEmail>string
batteryLevel>string
TimeZone>string
Mobile1>string
Mobile2>string
Mobile3>string
Mobile4>string
Mobile5>string
MobileNet1>string
MobileNet2>string
MobileNet3>string
MobileNet4>string
MobileNet5>string
AlertMode>int
AlertSYS>int
VetsLoadFlag>int
trackInt>int
notificationType>string
Geofence>string
SpeedLimit>int
/objusrpref>
SMSFlag>boolean
</Set

Domnic said...

Hi there,
Here is my coupon class


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

public class Coupon implements KvmSerializable {
public int Quantity;
public String Type;
public double Value;

public Coupon(){ }

public Coupon(int Quantity, String Type, double Value){
}


public Object getProperty(int index) {
switch(index)
{
case 0:
return Quantity;
case 1:
return Type;
case 2:
return Value;
}
return null;
}

public int getPropertyCount() {
return 3;
}

public void setProperty(int index, Object value) {
switch(index)
{
case 0:
Quantity = Integer.parseInt(value.toString());
break;
case 1:
Type = value.toString();
break;
case 2:
Value = Double.valueOf(value.toString());
break;
default:
break;
}
}


public void getPropertyInfo(int index, Hashtable properties,
PropertyInfo info) {
switch(index)
{
case 0:
info.type = PropertyInfo.INTEGER_CLASS;
info.name = "Quantity";
break;
case 1:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Type";
break;
case 2:
info.type = PropertyInfo.LONG_CLASS;
info.name = "Value";
break;
default:break;
}
}
}


thank you
Domnic

SeeSharpWriter said...

Hi Dominic,

you should be using Long instead of Double because KSOAP2 does not recognize Double as primitive data type. If you really have to use it as double, then you would need to implement the Marshal interface too.

Otherwise your class looks good.
Try downloading KSOAP2 from here if some properties are undefined for you:
Download KSOAP2

Domnic said...

Hi there,
Thanks for your suggestion. i will try it out. I was just confused with the outer element..




would it be a class on its own with one element - coupon ..?

<a:ticket>
<b:coupon>
<b:Quantity>5</b:Quantity>
<b:Type>visitor</b:Type>
<b:Value>250</b:Value>
</b:coupon>
<b:coupon>
<b:Quantity>2</b:Quantity>
<b:Type>member</b:Type>
<b:Value>20</b:Value>
</b:coupon>
</a:ticket>

thanks
Domnic

Domnic said...

I had the following..

PropertyInfo tickets = new PropertyInfo();
tickets.namespace = NAMESPACE;
tickets.name = "tickets";


if (visitorCount != 0) {
Coupon visitCou = new Coupon();
visitCou.Quantity = seniorCount;
visitCou.Type = "senior";
visitCou.Value = (Price * Count);
tickets.setValue(visitCou);
tickets.setType(Coupon.class);
}

request.addProperty("tickets", tickets);



And the Tickets class looks like


public class Ticket implements KvmSerializable{

Coupon[] ticketOrder = null;
//Vector<TicketOrder> ticketObjects = new Vector<Coupon>();

public Ticket(){}

public Ticket(Coupon[] ticketOrd){
ticketOrder = ticketOrd;
}

public Object getProperty(int index) {
switch(index)
{
case 0:
return ticketOrder;
}
return null;
}

public int getPropertyCount() {
// TODO Auto-generated method stub
return 1;
}

public void setProperty(int index, Object value) {
switch(index)
{
case 0:
ticketOrder[this.getPropertyCount()+1] = (Coupon) value;
}

}

public void getPropertyInfo(int index, Hashtable properties,
PropertyInfo info) {
switch(index)
{
case 0:
info.type = PropertyInfo.OBJECT_CLASS;
info.name = "Coupon";
break;
}

}

}

I am getting the Runtime exception...

cannot serialize tickets@....

Domnic said...

I think I figured this out.. I have a SOAP Envelop now.

I have an array of coupon class in the ticket class and it works.

Is there any way to tell KSOAP to use the GET method andnot http POST ?
thanks
Domnic

Domnic said...

Hi there,
Looks like KSOAP has a new version.. 2.5.4... did anyone work with it..perhaps..?
cheers
Domnic

Anonymous said...

Hello, Everyone. I am developing in .NET and Java.
I have implemented my web services in .NET and in Java. But if i change the local host to my IP in order to deploy the service in android i have problems.

What could be the problem with the .NET Development Server.?

Best regards.

SeeSharpWriter said...

Make sure your service is reachable through your ip address and also make sure Android has Internet permissions

Anonymous said...

hello Sir,

I need to pass a https url in android webservice.its not working when i used http transport.I dont have any other idea to pass https url.i am new to android.Can u pls help me?

Bruno Vinicius said...

Hi! I'm havinig a little trouble trying to pass a parameter to a method which expects a .Net Rectangle (http://schemas.datacontract.org/2004/07/System.Drawing namespace). I've created a Rectangle class with the same x,y,height and width parameters and implemented the KvmSerializable interface on it. From the client side (Android) it all looks fine, but the server always gets a Rectangle with x,y,width and height == 0, no matter what. Do you have any insight to offer? I belive I'm setting namespaces and parameters correcly, should I do something else?

Tks in advance!
Bruno

SeeSharpWriter said...

It's really hard to tell without actually seeing the code. Please paste some of your code so that we might be able to detect the problem

Bruno Vinicius said...

I didn't post any code because I'm using annotations and reflection to make the soap calls but I'll put the code here in any case.

--- Rectangle, the class i'm having trouble with ---
@SOAPObject(typeId="Rectangle", namespace=Namespaces.MS_SYSTEM_DRAWING)
public static class Rectangle extends Wrapper {
@SOAPProperty
private int height;
@SOAPProperty
private int width;
@SOAPProperty
private int x;
@SOAPProperty
private int y;
}

--- Wrapper, which implements the interface through reflection ---
public class Wrapper implements KvmSerializable {
private Object object;
protected Field[] fields;

protected Wrapper() {
this.object = this;
initialize();
}

public Wrapper(Object object) {
this.object = object;
initialize();
}

private void initialize() {
SOAPObject soapObjectAnnotaion = object.getClass().getAnnotation(SOAPObject.class);
fields = object.getClass().getDeclaredFields();
}

public Object getProperty(int index) {
Object result = null;
try {
fields[index].setAccessible(true);
result = fields[index].get(object);
System.out.println(result);
} catch (IllegalAccessException e) {
// probably never happens: we always set accessible = true
} catch (Throwable e) {
e.printStackTrace();
}

return result;
}

public int getPropertyCount() {
return fields.length;
}

@SuppressWarnings("rawtypes")
public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) {
Field field = fields[index];

String fieldName = fields[index].getAnnotation(SOAPProperty.class).name();

if(fieldName == "") {
fieldName = field.getName();
}

info.type = field.getType();
info.name = fieldName;
}

public void setProperty(int index, Object value) {
try {
fields[index].setAccessible(true);
fields[index].set(object, value);
} catch (IllegalAccessException e) {
// probably never happens: we always set accessible = true
}
}
}

--- Thats how I call the method ---
String soapMethod = namespace + URL_SEPARATOR + serviceInterface + URL_SEPARATOR + method;

SoapObject request = new SoapObject(namespace, method);

// I setup this collection before calling this method
if(params != null) {
for (String key : params.keySet()) {
Object value = params.get(key);

PropertyInfo pi = new PropertyInfo();
pi.name = key;
pi.setType(value.getClass());

Mapping mapping;
if((mapping = hasMapping(value.getClass())) != null) {
pi.setValue(value);
pi.setNamespace(mapping.namespace);
} else { // otherwise, we shall consider this a primitive value
pi.setValue(new SoapPrimitive(namespace, key, value.toString()));
}

request.addProperty(pi);
}
}

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

// I setup this collection before calling this method
for (Mapping mapping : mappings) {
envelope.addMapping(mapping.namespace, mapping.typeId, mapping.type);
}

HttpTransportSE httpTransport = new HttpTransportSE(serverUrl.toString() + URL_SEPARATOR + service);
httpTransport.call(soapMethod, envelope);
SoapObject response = (SoapObject) envelope.getResponse();

// parse responde....

--- Thats the output XML ---





fb7baa8b-3fbb-43da-85b4-22b4aaca7457


200
200
10
10





--- And finally, that my WSDL definition ---









true

Bruno Vinicius said...

I'm having little trouble posting the XMLs. Any hints...

SeeSharpWriter said...

Bruno, you can replace the < and > with [ and ] respectively.

Have you debugged your code? Do all variables have the proper value on the Android side ?

To me, the most suspicious part is the Rectangle binding namespace. I really have not used annotations before, but that external namespace might be the problem

Bruno Vinicius said...

Yeah sure! everythig seems Ok from the android perspective. I've debugged the KSOAP code and managed to get the XML that it is sending... if someone with more experience on the Soap XML sintaxe could take a look at that, maybe it can identify the problem... I shall setup the namespace so that the of the expected class (the Rectangle), otherwise, the server just reponds with a deserialization exeption (or somethig like this) telling that it don't know how to deserialize the restoreWindow (the Rectangle) parameter. The ksoap output XML and WSDL of the Rectangle type are below. Best regards!
--- Thats the output XML ---
[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]
[MinimizeApplication xmlns="http://mauell.xomnium.org"
id="o0" c:root="1"]
[n0:reference i:type="n0:ApplicationReference" xmlns:n0="http://mauell.xomnium.org"]
[Id i:type="d:string"]fb7baa8b-3fbb-43da-85b4-22b4aaca7457[/Id]
[/n0:reference]
[n1:restoreWindow i:type="n1:Rectangle"
xmlns:n1="http://schemas.datacontract.org/2004/07/System.Drawing"]
[height i:type="d:int"]200[/height]
[width i:type="d:int"]200[/width]
[x i:type="d:int"]10[/x]
[y i:type="d:int"]10[/y]
[/n1:restoreWindow]
[/MinimizeApplication]
[/v:Body]
[/v:Envelope]

--- And finally, that my WSDL definition ---
[?xml version="1.0" encoding="UTF-8"?]
[xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://schemas.datacontract.org/2004/07/System.Drawing"
elementFormDefault="qualified"
xmlns:tns="http://schemas.datacontract.org/2004/07/System.Drawing"]

[xs:import namespace="http://schemas.microsoft.com/2003/10/Serialization/" schemaLocation="http://192.168.10.10:7777/ApplicationService?xsd=xsd1" /]

[xs:complexType name="Rectangle"]

[xs:annotation]
[xs:appinfo]
[IsValueType xmlns="http://schemas.microsoft.com/2003/10/Serialization/"]true[/IsValueType]
[/xs:appinfo]
[/xs:annotation]

[xs:sequence]
[xs:element name="height" type="xs:int" /]
[xs:element name="width" type="xs:int" /]
[xs:element name="x" type="xs:int" /]
[xs:element name="y" type="xs:int" /]
[/xs:sequence]

[/xs:complexType]

[xs:element name="Rectangle" type="tns:Rectangle" nillable="true" /]

[/xs:schema]

Anonymous said...

Hi I need to biuld this structure:

complex type: get_entry_list_result
-int:result_count
-int:next_offset
-complex type:field_list = array of field
-->{field
-->string:name
-->string:type
-->string:label
-->string:required
-->}
-complex type:entry_list=array of entry_value
-->{entry_value
-->string:id
-->string:module_name
-->complex type: name_value_list=array of name_value
----->{name_value
----->string:name
----->string:value
----->}
-->}
-complex type:error=array of error_value
-->{error_value
-->string:number
-->string:name
-->string description
-->}



Main issue is the entry_list which is complex type and contains other complex type...can U help me please?

thx

Anonymous said...

Hi, I would appreciate it very much if you can help me.

I am trying to call a .Net web service that requests basic authentication.
That is, I need to pass a username and a password in the soap header.
I have found some examples, but I have not been able to get them working.
Basically they just add a base64 encoded string in the header request.
i.e.:

String Credentials = Base64.encodeToString("username:password".getBytes(), Base64.DEFAULT);
Log.d(TAG,Credentials);
List headers = new ArrayList();
headers.add(new HeaderProperty("Authorization","Basic "+Credentials));

The last time I tried it I got a XmlPullParserException : expected: STAR_TAG....

My question is if you could please provide a working sample of an
Android snippet that call a .Net web service using basic authentication

Thanks!

SeeSharpWriter said...

I wouldn't advise you to send complex objects with encapsulated complex objects.

SeeSharpWriter said...

I really don't know how that would work with credentials. Perhaps by enabling the debug mode of KSOAP you could find out what the problem is.

Valter said...

Hi
I am getting the following error when trying to send a complex object to the webservice:
SoapFault - faultcode: 'soap: Server' faultstring: 'System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.NullReferenceException: Object reference not set to an instance of an object.


My code:

public void logarWebService(View view) throws Exception{
String result = "";
EditText txtNome = (EditText)findViewById(R.id.txtUserName);
EditText txtPassword = (EditText)findViewById(R.id.txtPassword);

String nome = txtNome.getText().toString();
String senha = txtPassword.getText().toString();

AuthHeader a = new AuthHeader();
a.setUsername(nome);
a.setPassword(senha);

SoapObject request = new SoapObject(NAME_SPACE, METODO);

//setando o objeto "a" como uma propriedade
PropertyInfo pi = new PropertyInfo();
pi.setName("Authentication");
pi.setValue(a);
pi.setType(new AuthHeader().getClass());
request.addProperty(pi);

/*
pi = new PropertyInfo();
pi.setName("dataApontamento");
Date d = new Date();
pi.setValue(d.getTime());
pi.setType(d.getClass());
pi.setValue(d);

request.addProperty(pi);
*/

//montando o envelope Soap
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);

//mapeando o objeto para o envelope
envelope.addMapping(NAME_SPACE, "AuthHeader", new AuthHeader().getClass());

//MarshalDate m = new MarshalDate();
//m.register(envelope);
AndroidHttpTransport transport = new AndroidHttpTransport(URL);

try {
transport.call(ACTION, envelope);
result = envelope.getResponse().toString();


} catch (Exception e) {
result = e.getMessage() + "FALHOU";
e.printStackTrace();
}



TextView txt = (TextView)findViewById(R.id.texto);
txt.setText(result);
}


AuthHeader class:

public class AuthHeader implements KvmSerializable{

private String Username;
private String Password;

public AuthHeader(){};

public AuthHeader(String user, String pass) {
this.Username = user;
this.Password = pass;
}



/**
* Método que obtem o valor de username
*
* @return username
*/
public String getUsername() {
return Username;
}

/**
* Atribui valor à username
*
* @param username a username para atribuir
*/
public void setUsername(String username) {
Username = username;
}

/**
* Método que obtem o valor de password
*
* @return password
*/
public String getPassword() {
return Password;
}

/**
* Atribui valor à password
*
* @param password a password para atribuir
*/
public void setPassword(String password) {
Password = password;
}


@Override
public Object getProperty(int arg0) {
switch(arg0) {
case 0:
return Username;
case 1:
return Password;
}

return null;
}

@Override
public int getPropertyCount() {
return 2;
}

@Override
public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
switch(index) {
case 0:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Username";
break;
case 1:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Password";
break;
default: break;
}
}

@Override
public void setProperty(int index, Object value) {
switch(index) {
case 0:
Username = value.toString();
break;
case 1:
Password = value.toString();
break;
default:
break;
}
}


}



what could be wrong?

I'm sorry. my english is very bad

Thanks

Valter said...

SeeSharp

I solved the problem. The namespace was incorrect

Tanks

SeeSharpWriter said...

Great! I am glad it worked and that authentication can be implemented through KSOAP2!

Valter said...

I have a doubt. Do how to define an array of objects with kvmserializable?

SeeSharpWriter said...

Even if possible, I think it would be tremendously hard to achieve it. I know that you are going to need the Marshal interface as well, so that KSOAP knows how to serialize/deserialize the array.. You might check this link (at the bottom)
http://code.google.com/p/ksoap2-android/wiki/CodingTipsAndTricks

and this at the bottom, too:
http://supportforums.blackberry.com/t5/Java-Development/Ksoap-send-array-of-Strings/td-p/995743

Personally I would never recommend doing this, but please paste the code in case you succeed.
Thanks!

Valter said...

I found this project that the client generates the webservice. Although not tested, but should be interesting.

http://code.google.com/p/wsdl2ksoap/

Mahesh said...

Good stuff.. Thank you after week long hunt i found this page showing a simple ksoap implementation and was able to build from that success... Have you tried to transmit a file as Byte array from android to .NET using KSOAP ?

SeeSharpWriter said...

Yes, Mahesh I have transferred a file as a Byte array, but I am not sure if I still have the code. If I find it, I will post it. It isn't very neat though, but it can be done

Anonymous said...

Hi SeeSharpWriter, I got errors when trying your code. I think my web service code may have problems. The exception is:



2011-7-11 14:51:54 org.apache.axis2.rpc.receivers.RPCMessageReceiver invokeBusinessLogic
严重: Exception occurred while trying to invoke service method celsiusToFarenheit
org.apache.axis2.AxisFault: com.kuku.A
at org.apache.axis2.engine.DefaultObjectSupplier.getObject(DefaultObjectSupplier.java:28)
at org.apache.axis2.databinding.utils.BeanUtil.deserialize(BeanUtil.java:370)
at org.apache.axis2.databinding.utils.BeanUtil.processObject(BeanUtil.java:676)
at org.apache.axis2.databinding.utils.BeanUtil.ProcessElement(BeanUtil.java:624)
at org.apache.axis2.databinding.utils.BeanUtil.deserialize(BeanUtil.java:560)
at org.apache.axis2.rpc.receivers.RPCUtil.processRequest(RPCUtil.java:118)
at org.apache.axis2.rpc.receivers.RPCMessageReceiver.invokeBusinessLogic(RPCMessageReceiver.java:113)
at org.apache.axis2.receivers.AbstractInOutSyncMessageReceiver.receive(AbstractInOutSyncMessageReceiver.java:39)
at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:144)
at org.apache.axis2.transport.http.HTTPTransportUtils.processHTTPPostRequest(HTTPTransportUtils.java:279)
at org.apache.axis2.transport.http.AxisServlet.doPost(AxisServlet.java:116)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
....
Caused by: java.lang.InstantiationException: com.kuku.A
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at org.apache.axis2.engine.DefaultObjectSupplier.getObject(DefaultObjectSupplier.java:26)
... 24 more



Please help me figure out this problem.
Thanks very much!

Anonymous said...

My web service wsdl is:

-
Please Type your service description here
-
-
-
-
-





-
-





-
-
-




-
-
-




-
-
-






-


-


-


-


-
-



-




-

-

-


-



-

-


-




-

-

-


-



-

-


-




-

-

-


-



-

-


-




-
-


-


-

Anonymous said...

The java web service code is:

public class Converter
{
public A celsiusToFarenheit (A a)

{

A aa=new A(25,"how","are");


return aa;
}


class A {
public A(int a,String b, String c){
this.CategoryId=a;
this.Name=b;
this.Description=c;
}
public int CategoryId;
public String Name;
public String Description;

}


I am new to java.
Thanks.

Anonymous said...

The exception is:

SoapFault-faultcode: 'soapenv:Client' faultstring: 'Exception occureed while trying to invoke service method celsiusToFarenheit' faultactor: 'null' detail:org.kxml2.kdom.Node@44c26c90

Look forward to getting your answer soon.

SeeSharpWriter said...

Hi, what is the code with which you invoke the service ?

Anonymous said...

Hi SeeSharpWriter,

Thanks for your reply.
Could you please provide me some simple java based web service code so that I can make it work.

Best regards.

Anonymous said...

Hi SeeSharpWriter,

The code I provided is the web service code and I used your way to connect the web service and get an object from the method "celsiusToFarenheit". Is there anything wrong with my web service code?

Thanks very much!

eren said...

hi,
I have a web services.url = http://62.244.199.18:8888/ergo-ergoService-context-root/ergoSoapHttpPort?WSDL
and my code is below
private static final String METHOD_NAME = "checkloginnew";
private static final String SOAP_ACTION = "http://ergoconn/Ergo.wsdl/checkloginnew";
private static final String NAMESPACE = "http://ergoconn/Ergo.wsdl";
private static final String URL = "http://62.244.199.18:8888/ergo-ergoService-context-root/ergoSoapHttpPort?WSDL";

SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
PropertyInfo pi = new PropertyInfo();
pi.setName("pPid");
pi.setValue(1149688);
pi.setType(BigDecimal.class);
request.addProperty(pi);

PropertyInfo pi2 = new PropertyInfo();
pi2.setName("pPass");
pi2.setValue("074920");
pi2.setType(String.class);
request.addProperty(pi2);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
HttpTransportSE httpTransport = new HttpTransportSE(URL);
httpTransport.debug = true;
httpTransport.call(SOAP_ACTION, envelope);
SoapObject result=(SoapObject)envelope.getResponse();

But I get an error "Caught exception while handling request: unrecognized operation: {http://ergoconn/Ergo.wsdl}checkloginnew"

Thanks very much

SeeSharpWriter said...

In order to work with complex objects, you need to implement KVMSerializable interface and register the class in the envelope

SeeSharpWriter said...

I have never tried KSOAP for non-.NET web service, but from the exception you get, I think you have messed something with the NAMESPACE and the METHOD_NAME . Also for the BigDecimal you will need to implement Marshal interface as KSOAP 2 does not recognize it as a primitive data type

Anonymous said...

Hi SeeSharpWriter,

Should I implement KVMSerializable interface on both server and client sides?

Thanks very much.

eren said...

Hi SeeSharpWriter,
my updated my code below.I use KvmSerializable. But my project get error "SoapFault - faultcode: 'env:Client' faultstring: 'Caught exception while handling request: unrecognized operation: {http://ergoconn/Ergo.wsdl}getzimpoliceno' faultactor: 'null' detail: null"


SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
GetzimpolicenoElement elm = new GetzimpolicenoElement();
elm.setpFormno("12345");
elm.setpZimtip("1233");
PropertyInfo pi = new PropertyInfo();
pi.setName("getzimpolicenoElement");
pi.setValue(elm);
pi.setType(elm.getClass());
request.addProperty(pi);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
envelope.addMapping(NAMESPACE, "getzimpolicenoElement",new GetzimpolicenoElement().getClass());

HttpTransportSE httpTransport = new HttpTransportSE(URL);
httpTransport.debug = true;
httpTransport.call(SOAP_ACTION, envelope);
SoapObject result=(SoapObject)envelope.getResponse();


Please help
Thanks

SeeSharpWriter said...

It might be related to the fact that you are not using a .NET based service - personally I have never seen this message before. Maybe someone else does? Have you tried googling about it?

SeeSharpWriter said...

You should implement it only on the client side, but it is important that both the client and server have the same class.

eren said...

Yes. But I didn't find any thing about it. I'm looking for two days.

eren said...
This comment has been removed by the author.
eren said...

Hi SeeSharpWriter,
I look into my httptransport request is
"[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]
[n0:getzimpoliceno id="o0" c:root="1" xmlns:n0="http://ergoconn/Ergo.wsdl/getzimpoliceno"]
[getzimpolicenoElement i:type="n0:getzimpolicenoElement"]
[pFormno i:type="d:string"]12345[/pFormno]
[pZimtip i:type="d:string"]1233[/pZimtip]
[/getzimpolicenoElement]
[/n0:getzimpoliceno]
[/v:Body]
[/v:Envelope]
"
and response is
"
[?xml version="1.0" encoding="UTF-8"?]
[env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns0="http://ergoconn/Ergo.wsdl/types/"]
[env:Body]
[env:Fault]
[faultcode]env:Client[/faultcode]
[faultstring]Caught exception while handling request: unrecognized operation: {http://ergoconn/Ergo.wsdl/getzimpoliceno}getzimpoliceno[/faultstring]
[/env:Fault]
[/env:Body]
[/env:Envelope]
"

I think in request this line -[n0:getzimpoliceno id="o0" c:root="1" xmlns:n0="http://ergoconn/Ergo.wsdl/getzimpoliceno"]- is incorrect. I tried to delete it
but didnt do it. Do you know when do this line create in ksoap2 or how do i delete this line
thanks

bharath2598 said...

Hi To All

any one please tell me how to send the "xmldocument" to server using ksoap

Thanks in advance

SeeSharpWriter said...

Eren, it basically says it cannot find the web method on the address you specify

SeeSharpWriter said...

bharath2598, what xmldocument are you referring to? You want to transfer a file from the client to the server?

bharath2598 said...

Thanks for response sir

In my Android Project there is an xml file.i want to create object for that xml file and send to server. I know how to send a String to server but i didn't understand how to create object for xml file

bharath2598 said...

Here i send the xml file as a String to server

this is the code i used.

But i want to create object for xml and send that object to server


public class service extends Activity {
private static final String METHOD_NAME = "SaveData";
private static final String NAMESPACE = "http://tempuri.org/";
private static final String URL = "http://192.168.0.51/WebServiceExample/Service.asmx";
final String SOAP_ACTION = "http://tempuri.org/SaveData";

TextView tv;
StringBuilder sb;
private XmlSerializer writer;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tv = new TextView(this);
sb = new StringBuilder();
call();
tv.setText(sb.toString());
setContentView(tv);

}
public void call() {
try {

SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("parameter",writeXml());
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapPrimitive result = (SoapPrimitive)envelope.getResponse(); String resultData = result.toString();
// 0 is the first object of data
sb.append(resultData + "\n");
} catch (Exception e) {
sb.append("Error:\n" + e.getMessage() + "\n");
}

}
private String writeXml(){
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
try {
serializer.setOutput(writer);
serializer.startDocument("UTF-8", true);
serializer.startTag(null, "root");
//i indent code just to have a view similar to xml-tree
serializer.startTag(null,"child1");

serializer.text("One");
serializer.endTag(null, "child1");
serializer.startTag(null, "child2");
serializer.text("Child For One");
serializer.endTag(null, "child2");
serializer.startTag(null, "child3");
//write some text inside
serializer.text("Child Child for one");
serializer.endTag(null, "child3");
serializer.endTag(null, "root");
serializer.endDocument();
return writer.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

bharath2598 said...

But I send my xml file as a String form like this


ublic class service extends Activity {
private static final String METHOD_NAME = "SaveData";
private static final String NAMESPACE = "http://tempuri.org/";
//private static final String URL = "http://61.12.109.69/AndroidWebservice/Service.asmx";
private static final String URL = "http://192.168.0.51/WebServiceExample/Service.asmx";
final String SOAP_ACTION = "http://tempuri.org/SaveData";

TextView tv;
StringBuilder sb;
private XmlSerializer writer;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
tv = new TextView(this);
sb = new StringBuilder();
call();
tv.setText(sb.toString());
setContentView(tv);

}
public void call() {
try {

SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
request.addProperty("parameter",writeXml());
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapPrimitive result = (SoapPrimitive)envelope.getResponse(); String resultData = result.toString();
// 0 is the first object of data
sb.append(resultData + "\n");
} catch (Exception e) {
sb.append("Error:\n" + e.getMessage() + "\n");
}

}
private String writeXml(){
XmlSerializer serializer = Xml.newSerializer();
StringWriter writer = new StringWriter();
try {
serializer.setOutput(writer);
serializer.startDocument("UTF-8", true);
serializer.startTag(null, "root");
//i indent code just to have a view similar to xml-tree
serializer.startTag(null, "child1");

serializer.text("One");
serializer.endTag(null, "child1");

serializer.startTag(null, "child2");
serializer.text("Child For One");
serializer.endTag(null, "child2");

serializer.startTag(null, "child3");
//write some text inside
serializer.text("Child Child for one");
serializer.endTag(null, "child3");

serializer.endTag(null, "root");
serializer.endDocument();
return writer.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}

But I want to send as an object


Please tell me how to create a object for xml and send to it server

SeeSharpWriter said...

I think it is much easier to send it as string instead of a file. If you insist to send it as a file you would need a mechanism to convert the file in byte array and then divide it to packets. You will need to keep track on which packet is next to be sent. In the end the server will have to collect all packets into one single file. In my opinion, this is quite more complex than sending a string.

bharath2598 said...

Is there any code for "enable gps programatically"

SeeSharpWriter said...

GPS is enabled in the Android phone by default, but I think you can manipulate access with it with the configuration file in your project

bharath2598 said...

Hi sir

"Is there any tutorial for access database files from sdcard to our project"

The Ngo said...
This comment has been removed by the author.
The Ngo said...

Hi all, how about it when i send a List of Categories object? any idea ?

SeeSharpWriter said...

I have never done that so far - I advise you to avoid such situations by all means, but if you find a way that works, please paste it here

rumshenoy said...

Hey,

Ive tried out your code.Could you please help me out on the server side a bit.Could you post the Web Method that you are using too.and how are you implementing it.

Thank you.

SeeSharpWriter said...

The server side basically performs a SELECT query to the database, constructs a Category object and returns it. I am not at home right now but I hope this helps.

rumshenoy said...
This comment has been removed by the author.
adi said...

Hey
i am working with rumshenoy on the same issue,

our class in the server is :
public class Category
{
public int CategoryId;
public String Name;
public String Description;

public Category(){
CategoryId = 1;
Name = "justname";
Description = "somedescription";
}
}
and the web method is :
public Category GetCategoryById(){
Category c = new Category();
return c;
}

But this not working and we get so many exceptions..
Do we have to include any annotations or something ????

rumshenoy said...

Thanks for the immediate response.:)

Im using eclipse for development and axis 2 for the creating the web service.

so everything on the client side is exactly identical to what you have posted.

One the server side I have a method called print.

public Category print(Category C){

System.out.println("We have reached the server\n");
if(C.CategoryId==1){
System.out.println("Id is "+C.CategoryId);
}//just so that i know its recieved here
Category temp = new Category();
temp.CategoryId=3;
temp.Name ="rrrr";
temp.Description="ssss";

System.out.println("We've done the assignment");
return temp;

}

First,
I get all the sysouts on the server side .But when I print C.CategoryId prints a 0... though this must be some minor thing.


Second,
I'm getting an ArrayIndexOutOfBounds:0 in the android logcat for the following line.
C.CategoryId = Integer.parseInt(response.getProperty(0).toString());
this is what i'm more concerned about.Why isn't it returning the object properly.


The passing/returning of Category type Object isnt working for me.Can u please tell me where exactly I'm going wrong. I'm assuming this has to do something with my server side web service ,the print my method..

p.s.
I'm new to java programming as well as android.

bharath2598 said...

Hi Sir

I face on eproblem since last three days.

My Problem is:: i have a list view with check boxes in my activity my list view contain 20 items .firsti check the three items and scroll up the checked boxes are un checked.how to overcome this problem please give me solution pleaseeeee.

SeeSharpWriter said...

Rumshoy and Adi, as per my understanding, your web service is not .NET based. Is that correct?

SeeSharpWriter said...

bharath2598 I really do not know how to help you. Does anyone else here can help you out?

rumshenoy said...

Hey... yea its not .NET based..But isn't it like a soap object is passed around so irrespective of the web service u use it should communicate? Please correct me if im wrong here...

I have a new problem.. i have to connect to a web service which is based on apache CXF.. and I can't find any support for ksoap with cxf.....

SeeSharpWriter said...

The code I posted refers only to .NET web service. Personally I have never worked with Apache CXF web services.
Maybe someone else could help you more...

maxblaster said...

Whoops, it looks like the page consume my XML. The point is, it's adding a RemoteAuthenticateResult tag like this:

-RemoteAuthenticateResponse
--RemoteAuthenticateResult
---username
---password
---isAuth
--/RemoteAuthenticateResult
-/RemoteAuthenticateResponse

If it helps, the web service method is called RemoteAuthenticate, and the .Net web service is generating the RemoteAuthenticateResult tag, apparent because I can see it in the wsdl.

I know I didn't provide enough code. Let me know if I should post something more comprehensive. Thanks!

maxblaster said...

Hey SeeSharpWriter,

Please disregard my previous post - it was incomplete. This one is comprehensive.

Thanks for this excellent post. I'm running into an issue where my .NET web service is adding an extra XML element, and I can't find any documentation for this particular problem.

I have an object, RemoteAuthenticateResponse, that I'm passing to a web service method, and I'm receiving the same object back (similar to this example). Mapping is fine, and I can verify the web service is consuming the object.

Here's the web service method:

[WebMethod]
public RemoteAuthenticateResponse RemoteAuthenticate(RemoteAuthenticateResponse remoteAuthenticateResponse)
{
RemoteAuthenticateResponse rtnResponse = new RemoteAuthenticateResponse();
rtnResponse.username = "test";
rtnResponse.password = "test";
rtnResponse.isAuth = true;

return rtnResponse;
}

And I get this exception:

java.lang.RuntimeException: Unknown Property: RemoteAuthenticateResult

Because the xml returned to the Android deserializer is this:

-RemoteAuthenticateResponse
--RemoteAuthenticateResult
---username
---password
---isAuth
--/RemoteAuthenticateResult
-/RemoteAuthenticateResponse

So I figure the .Net web service is adding the RemoteAuthenticateResult tag, when those properties should belong to the RemoteAuthenticateResponse object. Any familiarity with this issue? Thank you in advance!

maxblaster said...

Sorry, I made several posts, and none of them stuck except for the most cryptic one. Essentially, I'm passing an object (RemoteAuthenticateResponse) from the droid client to the web service (to a web method called RemoteAuthenticate). The object I'm passing has 3 properties - username, password, and isAuth(boolean). If the login attempt succeeds on the server, the web service updates the isAuth property to 'true', and returns the object back to the client.

I can verify the web service is consuming the object that's sent, and it's returning a response, but the .Net web service seems to be adding a RemoteAuthenticateResult tag. The client can't parse the XML as a result, and I get a runtime exception (Unknown Property) that's thrown in SoapSerializationEnvelope.readSerializable.

Hoping to find some insight - I haven't been able to find any documentation for this issue. Thanks!

SeeSharpWriter said...

Why don't you try to make isAuth an int? Make sure that you change it in both server and client classes.

maxblaster said...

Thanks for your response! I updated the client and server to use an int instead, and the web service is still returning xml with that RemoteAuthenticateResult tag. I'm thinking there must be something wrong with either my RemoteAuthenticateResponse object declaration on the server (within which I just define 3 public properties and include a Serializable attribute).

Also, on the server, does your web method return the same instance of the Category object that's passed in, or do you instantiate a new one to return? I'm figuring that probably doesn't matter either way, but it's a thought. Thanks!

SeeSharpWriter said...

Does the error still remain the same?
Btw I create a new instance when returning the Category.

maxblaster said...

Same runtime error. This RemoteAuthenticationResult object still throws the parser off. I can see it defined in the wsdl, too:

{s:complexType}{s:sequence}{s:element minOccurs="0" maxOccurs="1" name="RemoteAuthenticateResult" type="tns:RemoteAuthenticateResponse"/}{/s:sequence}{/s:complexType}

Which is bizarre, because I didn't define it in code anywhere. I'm figuring .Net creates it by default, and maybe it's supposed to be there. Do you know perchance if there's some proxy result object returned by your web service?

maxblaster said...

So I found a solution, albeit a kind of tricky one that probably isn't good practices. If I stick this property on my web method:

[SoapDocumentMethod(ParameterStyle=SoapParameterStyle.Bare)]

And I add an additional mapping attribute for the .Net result object:

envelope.addMapping(NAMESPACE, "RemoteAuthenticateResult", new RemoteAuthenticateResponse().getClass());

Then the outer RemoteAuthenticateResponse tag is omitted by the server, and the client is able to parse the result object instead.

I'll probably keep messing around with it to see if there's a way to avoid mapping the additional entity, but this will work for now. Thanks for your help!

maxblaster said...

Just a follow up - my previous post is not a valid fix, as the SoapParameterStyle.Bare attribute will strip attributes from the request object as well as the response object. So while it removes the [MethodName]+[Result] object from the response, it removes the [RequestObject] tag from the request, so the server won't be able to interpret the request.

I did some debugging and found a workaround that does work - in my request object on the client (in my case, RemoteAuthenticateResponse), increase the value in getPropertyCount() by 1, and add additional cases to the getPropertyInfo and setProperty methods (but don't add any more properties to the request object!) as such:

getPropertyInfo:

case 3:
arg2.type = RemoteAuthenticateResponse.class;
arg2.name = "RemoteAuthenticateResult";
break;

setProperty:

case 3:
Username = ((RemoteAuthenticateResponse)(arg1)).Username;
etc...
break;

This tricks the SoapSerializationEnvelope in ksoap2-android-assembly-2.5.7 to think there's an additional property (of the same type) on the response object, and when it tries to populate the pretend object, you tell it to populate the properties on the response object itself.

Probably 100,000 better ways to do this. But this works for me.

SeeSharpWriter said...

As long as it works - it is great!Perhaps someone will find it useful, too. Thanks for sharing, maxblaster!

Anonymous said...

Hiii I tried ur code as it is.. but it gives the exception as follows

SoapFault - faultcode: 'soapenv:Server.userException' faultstring: 'org.xml.sax.SAXException: Deserializing parameter 'C': could not find deserializer for type {http://ws.com}Category' faultactor: 'null' detail: org.kxml2.kdom.Node@405306b0

Please help me. Is there anything to consder writting the web service

Frionel said...

Hi. I did this tutorial but I didn't success. I tryied with the webservice wsdl that my company has. I send an user complex object to the WS.

I get the error below:
SoapFault - faultcode: 'a:DeserializationFailed' faultstring: 'The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:user. The InnerException message was 'Element user from namespace http://tempuri.org/ cannot have child contents to be deserialized as an object. Please use XmlNode[] to deserialize this pattern of XML.'. Please see InnerException for more details.' faultactor: 'null' detail: null

Any help pls? Really thanks

Anonymous said...

Hii please help me for this.......... let say if we having an another property test[] t ; (test is another class) simply say the category class have another property of object array... how accommodate this.. please help me its urgent.

SeeSharpWriter said...

Frionel, please post your code - there are plenty of places where you might have missed something - like addding a mapping, for instance.

SeeSharpWriter said...

Anonymous, I don't think that is feasible with KSOAP 2. My advice is to stay away from such encapsulations

CnC Tera said...

I hope i'm not spamming, but I have wrote an article on some high level @annotation + reflection solution on receiving/parsing/sending soap objects and I guess it might be useful for anybody finding this useful. In fact i shall give this blog full credit as I would neve had made it without their help.

The bad news is that it is written in portuguese, but then comes Google Translate for the rescue. As the code itself is already English.

I'd recomend anyone to check it out. Including the SeeSharpGears. We may setup another post in english here for further helping anyone with these problems.

http://zbra.com.br/2011/07/06/androidksoap-pt-1-transcrevendo-soapobjects-atraves-de-annotations-reflection/
http://zbra.com.br/2011/08/19/androidksoap-pt-2-parametros-complexos/

SeeSharpWriter said...

Great Articles CnC Tera! I am sure people will find this useful!

Andy T. said...

How can pass domain username and password to get sopa response?

SeeSharpWriter said...

If I understand correctly, you just need to write a web service with two string arguments and then invoke it with KSOAP

Anonymous said...

Hi I tried your code but while executing I am getting


10-10 23:23:23.603: WARN/System.err(351): java.net.SocketTimeoutException: Socket is not connected.

how can i fix this?

SeeSharpWriter said...

I really do not know. Maybe someone else knows - please share your opinions.

MikeH said...

Are you behind a firewall which is blocking the connection?

try running it on your device using 3G see if you get the same error.

MikeH said...

On that note I've got a problem converting my response into an array of objects.

I've resolved my problem regarding a custom soap authentication header. but I've spent hours googleing this problem without success;

The returned envelope from my webservice looks like:







1234567
Household
Complete
07/10/2011 14:56:19
255
255


45454545
Household
Complete
07/10/2011 14:55:33
11
11


41244455
Household
Complete
30/09/2011 13:57:21
145
145


45454545
Household
Complete
28/09/2011 09:13:15
168
168


45454555
Household
Complete
28/09/2011 09:12:13
174
174






I've previously coded an application to do this exact thing in a c# .net enviroment and its just a simple case of creating an array of objects ready to receive each object and its properties, like this:


C#

ObjectClass[] arrayofobjects = null;
try
{
arrayofobjects = SoapProxy.MethodName(Param1,Param2,Param3);
}

catch (Exception Error)
{
MessageBox.Show(Error.Message.ToString());
}

foreach (ObjectClass SingleObject in arrayofobjects)
{
MessageBox.Show(SingleObject.Id.ToString() + SingleObject.Status.ToString() + SingleObject.Category.ToString() );
}

MikeH said...

looks like my XML has been rendered by the browser, lets try again I'll break it this time;

.soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
.soap:Body>
.GetItemsWithinDateRangeResponse xmlns="http://url/">
.GetItemsWithinDateRangeResult>
.Items>
.Id>1234567./Id>
.Category>Household./Category>
.Status>Complete./Status>
.DateScheduled>07/10/2011 14:56:19./DateScheduled>
.ListSize>255./ListSize>
.TotalSuccess>255./TotalSuccess>
./Items>
.Items>
.Id>45454545./Id>
.Category>Household./Category>
.Status>Complete./Status>
.DateScheduled>07/10/2011 14:55:33./DateScheduled>
.ListSize>11./ListSize>
.TotalSuccess>11./TotalSuccess>
./Items>
.Items>
.Id>41244455./Id>
.Category>Household./Category>
.Status>Complete./Status>
.DateScheduled>30/09/2011 13:57:21./DateScheduled>
.ListSize>145./ListSize>
.TotalSuccess>145./TotalSuccess>
./Items>
.Items>
.Id>45454545./Id>
.Category>Household./Category>
.Status>Complete./Status>
.DateScheduled>28/09/2011 09:13:15./DateScheduled>
.ListSize>168./ListSize>
.TotalSuccess>168./TotalSuccess>
./Items>
.Items>
.Id>45454555./Id>
.Category>Household./Category>
.Status>Complete./Status>
.DateScheduled>28/09/2011 09:12:13./DateScheduled>
.ListSize>174./ListSize>
.TotalSuccess>174./TotalSuccess>
./Items>
./GetItemsesWithinDateRangeResult>
./GetItemsesWithinDateRangeResponse>
./soap:Body>
./soap:Envelope>

SeeSharpWriter said...

Hi Mike,

do you happen to remember the link where you have found the answer by googling? Please feel free to post it here. Maybe someone else will find it useful, too.

MikeH said...

The below link describes the method I've used to create my header elements;

http://stackoverflow.com/questions/5613675/how-to-set-soap-header-using-ksoap2-android

[code]
import org.kxml2.kdom.Element;

//then while preparing envelope

soapEnvelope.headerOut = new Element[1];
soapEnvelope.headerOut[0] = buildAuthHeader();


// ...send request...




private Element buildAuthHeader() {
Element h = new Element().createElement(NAMESPACE, "AuthHeader");
Element username = new Element().createElement(NAMESPACE, "user");
username.addChild(Node.TEXT, USERNAME);
h.addChild(Node.ELEMENT, username);
Element pass = new Element().createElement(NAMESPACE, "pass");
pass.addChild(Node.TEXT, PASSWORD);
h.addChild(Node.ELEMENT, pass);

return h;
}
[/code]



I'm still stumped on using the returned objects in an array like I would in c#

SeeSharpWriter said...

Hi Mike, thanks for posting that. You might want to check this article of mine:

http://seesharpgears.blogspot.com/2010/10/web-service-that-returns-array-of.html

In it, I explain how you can return an array of complex objects as a result from a web service in Android.

Anonymous said...

Hi, Could you please provide me sample code how to handle enum type object from web service by implementing KvmSerializable? I want to know the model to handle the enum type response.
For example, the web service is:
http://ws-emc.rolosoft.com/MXInfo.asmx?WSDL
I was trying to invocate the method "ValidateMailBox" but I do not know how to handle the eumn response. For example, I define the Valid eumn class as below:
import java.util.Hashtable;

import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapSerializationEnvelope;

import com.kuku.emailchecker.ksoap.BaseObject;

public class ValidationResult extends BaseObject{
public enum Validation{True, False, Unknown};
public Validation validation;

public Object getProperty(int index)
{

return validation;

}

public int getPropertyCount()
{
return 1;
}

@SuppressWarnings("unchecked")
public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) {
//info.type = PropertyInfo.STRING_CLASS;
info.name = "validation";
info.type = validation.getClass();

}

public void setProperty(int index, Object value)
{

validation = (Validation)value;

}

public void register(SoapSerializationEnvelope envelope)
{
envelope.addMapping(NAMESPACE, "ValidationResult", new ValidationResult().getClass());

}
}

Could you please tell me is it right?

Anonymous said...

the baseobject implements KvmSerializable.

SeeSharpWriter said...

How about working with int and then mapping it with a corresponding enum value on both .NET and Java(Android) sides ?

MikeH said...
This comment has been removed by the author.
Anonymous said...

Great article! Using the information that you posted, really helped me with KSOAP2. Unfortunately, I am stuck on one thing - enum. A web service returns a class with a property that is an enumeration defined in the web service. KSOAP2 throws an error because it doesn't know how to handle it. Any ideas on what to do? I tried to marshal it, no go. I am think serialization like your previous article, but what should the value actually be stored as? Do you have a code snipet with an enum being supported?

Nath of God said...

Everything works fine for me except passing in parameters... my web service never receives them????

SeeSharpWriter said...

What kind of parameters are you trying to send ?
Have you tried simple scenarios, like sending and receiving integers ?

Anonymous said...

Hi SeeSharp Writer,

Could you please comment on the enum object in KSOAP2 as I posted before?
Thanks in advance.

Great article! Using the information that you posted, really helped me with KSOAP2. Unfortunately, I am stuck on one thing - enum. A web service returns a class with a property that is an enumeration defined in the web service. KSOAP2 throws an error because it doesn't know how to handle it. Any ideas on what to do? I tried to marshal it, no go. I am think serialization like your previous article, but what should the value actually be stored as? Do you have a code snipet with an enum being supported?

Anonymous said...

Hello!
I really need help, I spent a week to find solution for that problem, but no succes.
I have WCF service. If I call methods with arguments, which are String, int,.. it works ok.
But when I try to pass custom object to WCF there is error when read it.
My Tag class:
public class Tag implements KvmSerializable {

public int TagID;
public String Name;

public Tag() {}

public Tag(int tagID, String name) {
TagID = tagID;
Name = name;
}

// KSOAP methods implementation
public Object getProperty(int arg0) {

switch (arg0) {
case 0:
return TagID;
case 1:
return Name;
}

return null;
}

public int getPropertyCount() {
return 2;
}

public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
switch (index) {
case 0:
info.type = PropertyInfo.INTEGER_CLASS;
info.name = "TagID";
break;
case 1:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Name";
break;
default:
break;
}
}

public void setProperty(int index, Object value) {
switch (index) {
case 0:
TagID = Integer.parseInt(value.toString());
break;
case 1:
Name = value.toString();
break;
default:
break;
}
}

}

in .NET class name of properties and types are the same.

Request DUMP:





12
TEST FROM ANDROID





RESPONSE DUMP:



a:InternalServiceFault
Object reference not set to an instance of an object.




Object reference not set to an instance of an object.

at WcfService.Service1.SyncFromMobileToServer(Tag tag) in C:\Users\Primož\Documents\My Dropbox\WCF\Zapravljivec\WcfService\Service1.svc.cs:line 47

at SyncInvokeSyncFromMobileToServer(Object , Object[] , Object[] )

at System.NullReferenceException






LINE 47 in .SVC:
public String SyncFromMobileToServer(Tag tag){
47: return tag.Name.toString();
}

Activity:
private void MobileToServer() {
if (VerifyUser()) {

String SYNC_METHOD_NAME = "SyncFromMobileToServer";
String SYNC_SOAP_ACTION = "http://zapravljivec.com/IService1/SyncFromMobileToServer";

SoapObject request = new SoapObject(NAMESPACE, SYNC_METHOD_NAME);
// request.addProperty("userid", loggedInUserUUID.toUpperCase());

Tag tag = new Tag();
tag.Name = "TEST FROM ANDROID";
tag.TagID = 12;

PropertyInfo pi = new PropertyInfo();
pi.setName("tag");
pi.setValue(tag);
pi.setType(new Tag().getClass());
pi.setNamespace(NAMESPACE);
request.addProperty(pi);

SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);

envelope.dotNet = true;
envelope.setOutputSoapObject(request);

envelope.addMapping(NAMESPACE, "tag", new Tag().getClass());
envelope.implicitTypes=true;
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);

try {
androidHttpTransport.debug = true;

androidHttpTransport.call(SYNC_SOAP_ACTION, envelope);

String requestDump = androidHttpTransport.requestDump;
String resultDump = androidHttpTransport.responseDump;

SoapObject resultsRequestSOAP = (SoapObject) envelope.bodyIn;
//boolean b = Boolean.parseBoolean(resultsRequestSOAP.getProperty(0).toString());

String s = resultsRequestSOAP.getProperty(0).toString();

//int a = 2;

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

Please help, I tried with sending SoapObject too, but no success...

Anonymous said...

Hello!

It's possible to see web.config file for WCF service??
I tried all, spent a whole week but no succes.
I can send String, Integer,.. but not my complex class with ID (int) and Name (String)..
When I want to read class.Name in my WCF there is an error Object reference is not set to an instance of an object.
Property name is same in Java and .NET and class implement KVMSerializable..

Please help!
Thanks,
Primoz

SeeSharpWriter said...

Hi, regarding the enum, this is my thought:

Enums can typically be represented by numbers:

Enum Color = new Enum {red = 0, green = 1, blue = 2};

Instead of sending an enum type to the web service:

[WebMethod]
public Car GetCarsByColor(Color carColor){ //... }

do this:

[WebMethod]
public Car GetCarsByColor(int carColor){//...}

this is the easiest workaround. Hope it helps

SeeSharpWriter said...

I didn't know that KSOAP works with WCF! That's great news! Regarding your problem, it would be wise to try this: rewrite the web service as an ordinary .asmx web service with a web method that accepts your Tag object. If it passes the object, you should look for a way to map the object in WCF - at least you will know what to look for.

Anonymous said...

WCF with basicHttpBinding is .ASMX web service.
And for "classic" object types it works great. Problems appear when I want to send custom object to web service..

lomza_t said...

Hi. I was re-viewving your posts about kSOAP library and the use of it! They were very helpful! However I have an issue which I'm struggling to resolve, but as for now without any success. The point is, I have a function request with these structure: http://codeviewer.org/view/code:1f9b and this function returns an xml string with a fallowing format: http://codeviewer.org/view/code:1f9c
I have created a Params class and passed its object as PropertyInfo value, then passed property info object like this: request.addProperty(propertyInfo);
I set mapping to Params class and did not do the deserialization, just wrote this:
try {
httpTransport.debug = true;
httpTransport.call(SOAP_ACTION_URL, envelope);

response = envelope.getResponse();
} catch(Exception e) {
Log.e(getClass().getSimpleName(), "Error while trying to get a response.", e);
}

Hovewer, I'm getting an error. Here is the stack: http://s013.radikal.ru/i324/1110/07/a0a0ab6d3f3d.png Do You have any idea why am I getting this error? Thank You very much!

SeeSharpWriter said...

It complains that it does not how to parse the [data] tags in the response. You might want to write that class too and thus implement the Marshal interface for it.
Here is my post about marshaling parameters:
http://seesharpgears.blogspot.com/2010/11/implementing-ksoap-marshal-interface.html

Hope you find this helpful.

«Oldest ‹Older   1 – 200 of 309   Newer› Newest»

Post a Comment