Complex Object hosting Array of Complex Objects to .NET Web Service - android

I am getting a "casting" error on a property of complex object that is sent to a .NET web service using KSOAP2 from an Android device. The property is an array of complex objects. The documentation on the internet has helped me send and receive simple data types (strings, ints, dates, etc). I can even read an array of complex objects from a .NET web service. I just cannot send back an array of complex objects to the web service. Please help. Here is what I have:
Environment:
Client = Android Development using the latest KSOAP lib for communication.
Server = .NET Web Service (Visual Studio 2008). Note: this is NOT WCF.
.NET Web Service:
[SoapRpcMethod(), WebMethod]
public void WriteCaseInfo(CaseInformation caseInfo)
{
...
...
}
ANDROID CLIENT CODE:
Parent Class Sent as Complex Parameter:
public class CaseInformation extends IABaseKSoap2Serializable
{
public String Name;
public int Id;
public Vector<MultiPartDataElement> SiteListItems = new Vector<MultiPartDataElement>();
#Override
public Object getProperty(int arg0)
{
switch(arg0)
{
case 0:
return Name;
case 1:
return Id;
case 2:
return SiteListItems;
}
return null;
}
#Override
public int getPropertyCount()
{
return 3;
}
#Override
public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info)
{
switch(index)
{
case 0:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Name";
break;
case 1:
info.type = PropertyInfo.INTEGER_CLASS;
info.name = "Id";
break;
case 2:
info.type = new Vector<MultiPartDataElement>().getClass();
info.name = "SiteListItems";
break;
default:break;
}
}
#Override
public void setProperty(int index, Object value)
{
switch(index)
{
case 0:
Name = value.toString();
break;
case 1:
Id = Integer.parseInt(value.toString());
break;
case 2:
SiteListItems = (Vector<MultiPartDataElement>)value;
break;
default:
break;
}
}
}
Note: If I remove the SiteListItems property from the client code and the web service, everything works.
Complex Class used in Array within the above object:
public class MultiPartDataElement extends IABaseKSoap2Serializable
{
public int Id;
public String Name;
// default constructor
public MultiPartDataElement()
{
}
// overloaded constructor
public MultiPartDataElement(int id, String name)
{
Id = id;
Name = name;
}
#Override
public Object getProperty(int arg0)
{
switch(arg0)
{
case 0:
return Id;
case 1:
return Name;
}
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.INTEGER_CLASS;
info.name = "Id";
break;
case 1:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Name";
break;
default:break;
}
}
#Override
public void setProperty(int index, Object value)
{
switch(index)
{
case 0:
Id = Integer.parseInt(value.toString());
break;
case 1:
Name = value.toString();
break;
default:
break;
}
}
}
Code to Send object as a Parameter to the .Net Web Service:
public static boolean WriteCaseInfo()
{
boolean status = false;
CaseInformation caseInfo = new CaseInformation();
caseInfo.Id = 2725;
caseInfo.Name = "Craig M. Buck";
caseInfo.SiteListItems = new Vector<MultiPartDataElement>();
caseInfo.SiteListItems.add(new MultiPartDataElement(1, "CMB1"));
caseInfo.SiteListItems.add(new MultiPartDataElement(2, "CMB2"));
String methodName = "WriteCaseInfo";
SoapObject request = new SoapObject(NAMESPACE, methodName);
request.addProperty("caseInfo", caseInfo);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.bodyOut = request;
envelope.dotNet = false;
envelope.encodingStyle = SoapSerializationEnvelope.XSD;
envelope.addMapping(IABaseKSoap2Serializable.NAMESPACE, "MultiPartDataElement", new MultiPartDataElement().getClass());
envelope.addMapping(IABaseKSoap2Serializable.NAMESPACE, "CaseInformation", new CaseInformation().getClass());
HttpTransportSE transport = new HttpTransportSE(WebAPIURL + CaseServicesURL);
transport.debug = true;
transport.setXmlVersionTag("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
try
{
List<HeaderProperty> headers = BuildHeader();
transport.call(NAMESPACE + methodName, envelope, headers);
String requestDump = transport.requestDump;
String soapDump = transport.responseDump;
SoapObject response = (SoapObject) envelope.bodyIn;
if(response != null)
status = new Boolean(response.getProperty(0).toString());
}
catch(Exception e)
{
status = false;
}
return status;
}
Request Dump from KSOAP:
<?xml version="1.0" encoding="utf-8"?><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:WriteCaseInfo id="o0" c:root="1" xmlns:n0="http://www.medical.draeger.com/webservices/"><caseInfo i:type="n1:CaseInformation" xmlns:n1="http://www.medical.draeger.com/webservices/encodedTypes"><Name i:type="d:string">Craig M. Buck</Name><Id i:type="d:int">2725</Id><SiteListItems i:type="c:Array" c:arrayType="d:anyType[2]"><item i:type="n1:MultiPartDataElement"><Id i:type="d:int">1</Id><Name i:type="d:string">CMB1</Name></item><item i:type="n1:MultiPartDataElement"><Id i:type="d:int">2</Id><Name i:type="d:string">CMB2</Name></item></SiteListItems></caseInfo></n0:WriteCaseInfo></v:Body></v:Envelope>
Note: What I think the issue is, is that the array is defined as "anyTyp" and not MultiPartDataElement -> ... the question is what am I doing wrong here??
Response Dump from KSOAP (After Call):
SoapException: Server was unable to read request. ---> System.InvalidOperationException: There is an error in XML document (1, 828). ---> System.InvalidCastException: Cannot assign object of type System.Object[] to an object of type Draeger.IT.Platform.Web.WebServices.MultiPartDataElement[]

I've had similar problem. You might want to try my personal solution.
http://www.codeproject.com/Tips/222578/Android-access-to-NET-Web-Service-with-object-as-p

You could do this:
int propertyCount = countryDetails.getPropertyCount();
ArrayList list = new ArrayList(propertyCount);
lv_arr = new String[propertyCount];
for (int i = 0; i < propertyCount; i++) {
Object property = countryDetails.getProperty(i);
if (property instanceof SoapObject) {
SoapObject countryObj = (SoapObject) property;
String countryName = countryObj.getProperty("countryName").toString();
list.add(countryName);
}
}
from : Parsing ksoap2 response

Related

How to send object in ksoap2 request

I'm trying to pass an object to web service using ksopa2 library. I'm trying something like this:
RangeInfo controllingArea = new RangeInfo();
controllingArea.setLow(txtControllingAreaSearch.getText().toString());
PropertyInfo propertyControllingArea = new PropertyInfo();
propertyControllingArea.setType(new RangeInfo().getClass());
propertyControllingArea.setName("IControllingarea");
propertyControllingArea.setValue(controllingArea);
request.addProperty(propertyControllingArea);
PropertyInfo maxNoOfHits = new PropertyInfo();
maxNoOfHits.setValue(txtMaxNoHitsSearch.getText().toString());
maxNoOfHits.setName("IMaxnoofhits");
maxNoOfHits.setType(PropertyInfo.INTEGER_CLASS);
request.addProperty(maxNoOfHits);
My RangeInfo class is like this:
public String sign = "I";
public String option = "EQ";
public String low;
public String high;
public RangeInfo(){}
public RangeInfo(SoapObject soapObject)
{
if (soapObject == null)
return;
if (soapObject.hasProperty("Sign"))
{
Object obj = soapObject.getProperty("Sign");
if (obj != null && obj.getClass().equals(SoapPrimitive.class)){
SoapPrimitive j =(SoapPrimitive) obj;
sign = j.toString();
}else if (obj!= null && obj instanceof String){
sign = (String) obj;
}
}
if (soapObject.hasProperty("Option"))
{
Object obj = soapObject.getProperty("Option");
if (obj != null && obj.getClass().equals(SoapPrimitive.class)){
SoapPrimitive j =(SoapPrimitive) obj;
option = j.toString();
}else if (obj!= null && obj instanceof String){
option = (String) obj;
}
}
if (soapObject.hasProperty("Low"))
{
Object obj = soapObject.getProperty("Low");
if (obj != null && obj.getClass().equals(SoapPrimitive.class)){
SoapPrimitive j =(SoapPrimitive) obj;
low = j.toString();
}else if (obj!= null && obj instanceof String){
low = (String) obj;
}
}
if (soapObject.hasProperty("High"))
{
Object obj = soapObject.getProperty("High");
if (obj != null && obj.getClass().equals(SoapPrimitive.class)){
SoapPrimitive j =(SoapPrimitive) obj;
high = j.toString();
}else if (obj!= null && obj instanceof String){
high = (String) obj;
}
}
}
#Override
public Object getProperty(int arg0) {
switch(arg0){
case 0:
return sign;
case 1:
return option;
case 2:
return low;
case 3:
return high;
}
return null;
}
#Override
public int getPropertyCount() {
return 4;
}
#Override
public void getPropertyInfo(int index, #SuppressWarnings("rawtypes") Hashtable arg1, PropertyInfo info) {
switch(index){
case 0:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Sign";
break;
case 1:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Option";
break;
case 2:
info.type = PropertyInfo.STRING_CLASS;
info.name = "Low";
break;
case 3:
info.type = PropertyInfo.STRING_CLASS;
info.name = "High";
break;
}
}
#Override
public void setProperty(int arg0, Object arg1) {
}
public void setSign(String sign) {
this.sign = sign;
}
public void setOption(String option) {
this.option = option;
}
public void setLow(String low) {
this.low = low;
}
public void setHigh(String high) {
this.high = high;
}
In the server side I'm getting value of "IMaxnoofhits" variable, but "IControllingarea" is always null!!!
Someone has passed or imagine what could be the problem?
Thanks!
It looks to me like when you instantiate your RangeInfo controllingArea = new RangeInfo(); class you're not passing in a SoapObject so you're just calling the empty constructor, instead of the second constructor which has all your code.
Also, I know this isn't a part of your question but your maxNoOfHits parameter is set to the Integer class, even though .setValue looks like you're passing in a String.
Thanks guys,
I solved it by my self. Here is what i did. And it is working to send complex object to the request.
RangeInfo controllingArea = new RangeInfo();
controllingArea.setLow("Value");
controllingArea.setHigh("Value");
PropertyInfo item = new PropertyInfo();
item.setType(controllingArea.getClass());
item.setName("item");
item.setValue(controllingArea);
SoapObject object1 = new SoapObject("","IControllingarea");
object1.addProperty(item);
request.addSoapObject(object1);
PropertyInfo maxNoOfHits = new PropertyInfo();
maxNoOfHits.setValue(txtMaxNoHitsSearch.getText().toString());
maxNoOfHits.setName("IMaxnoofhits");
maxNoOfHits.setType(PropertyInfo.INTEGER_CLASS);
request.addProperty(maxNoOfHits);
Best regards.

KSOAP2 Handling complex response (vector)

I'm struggeling on getting a complex type (list) out of my response for three days now, but always getting a ClassCastException
D/SOAPEnvelope(1552): Error: java.lang.ClassCastException: org.ksoap2.serialization.SoapObject cannot be cast to com.example.webservice.ResponsiblepartyGetResponse
I read several linked pages / tutorials so often that I almost can tell them by mind, including these four very helpful pages:
http://seesharpgears.blogspot.de/2010/10/web-service-that-returns-array-of.html
http://code.google.com/p/ksoap2-android/wiki/CodingTipsAndTricks#sending/receiving_array_of_complex_types_or_primitives
ksoap2 Receive Array of complex objects via SOAP
How to parse this Web service response in Android?
and many more, but I still don't get it :(
I hope I'll give you all the input you need to show me my mistake and give me a hint to fix it. The webservice is already successfully implemented in a rich client application and I have to build an android app now using the same webservice.
My first step is to handle a "responsibleparty_get"-Response.
My response looks (with a limit to 3, but can be more/less) like this. Note: There are two additional properties of the "responsiblePartyFacades" that are just null for these responses (see below in the JAVADOC).
responsibleparty_getResponse{
responsiblePartyFacades=anyType{
id=1;
name=hans;
discriminator=person;
admin=false;
};
responsiblePartyFacades=anyType{
id=2;
name=dieter;
discriminator=person;
admin=false;
};
responsiblePartyFacades=anyType{
id=3;
name=stefan;
discriminator=person;
admin=false;
};
}
The related XML looks like this (got out of SoapUI):
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:responsibleparty_getResponse xmlns:ns2="http://ws.my-url.com/">
<responsiblePartyFacades>
<id>1</id>
<name>hans</name>
<discriminator>person</discriminator>
<admin>false</admin>
</responsiblePartyFacades>
<responsiblePartyFacades>
<id>2</id>
<name>dieter</name>
<discriminator>person</discriminator>
<admin>false</admin>
</responsiblePartyFacades>
<responsiblePartyFacades>
<id>3</id>
<name>stefan</name>
<discriminator>person</discriminator>
<admin>false</admin>
</responsiblePartyFacades>
</ns2:responsibleparty_getResponse>
</S:Body>
</S:Envelope>
From our JAVADOC (out of the rich client) the responsiblePartyFacades looks the same:
* <complexType name="responsiblePartyFacade">
* <complexContent>
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* <sequence>
* <element name="id" type="{http://www.w3.org/2001/XMLSchema}int" minOccurs="0"/>
* <element name="name" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="discriminator" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
* <element name="admin" type="{http://www.w3.org/2001/XMLSchema}boolean" minOccurs="0"/>
* <element name="children" type="{http://ws.my-url.com/}pairIntBoolFacade" maxOccurs="unbounded" minOccurs="0"/>
* <element name="plantcomponents" type="{http://www.w3.org/2001/XMLSchema}int" maxOccurs="unbounded" minOccurs="0"/>
* </sequence>
* </restriction>
* </complexContent>
* </complexType>
So far, so nice.
I wrote these classes to handle the reponse:
ResponsiblepartyGetResponse
public class ResponsiblepartyGetResponse extends Vector<ResponsiblePartyFacade> implements KvmSerializable {
private static final long serialVersionUID = -8065084038519643055L;
#Override
public Object getProperty(int index) {
return this.get(index);
}
#Override
public int getPropertyCount() {
return this.size();
}
#Override
public void getPropertyInfo(int index, Hashtable properties, PropertyInfo info) {
info.name = "ResponsiblePartyFacades";
info.type = new ResponsiblePartyFacade().getClass();
}
#Override
public void setProperty(int index, Object value) {
// add ResponsiblePartyFacade to vector
this.add((ResponsiblePartyFacade) value);
}
}
ResponsiblePartyFacade: For now i comment out the vecor-items as they are not in the response, because I throught it might work (as there are several blogs on the web saying ksoap2 vector does not work).
public final class ResponsiblePartyFacade implements KvmSerializable {
private Integer id;
private String name;
private String discriminator;
private Boolean admin;
// private List<PairIntBoolFacade> children; // not used
// private List<Integer> plantcomponents; // not used
public ResponsiblePartyFacade() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDiscriminator() {
return discriminator;
}
public void setDiscriminator(String discriminator) {
this.discriminator = discriminator;
}
public Boolean getAdmin() {
return admin;
}
public void setAdmin(Boolean admin) {
this.admin = admin;
}
/*
public List<PairIntBoolFacade> getChildren() {
if (children == null) {
children = new ArrayList<PairIntBoolFacade>();
}
return children;
}
public void setChildren(List<PairIntBoolFacade> children) {
this.children = children;
}
public List<Integer> getPlantcomponents() {
if (plantcomponents == null) {
plantcomponents = new ArrayList<Integer>();
}
return plantcomponents;
}
public void setPlantcomponents(List<Integer> plantcomponents) {
this.plantcomponents = plantcomponents;
}
*/
public int getPropertyCount() {
return 4;
}
public Object getProperty(int __index) {
switch(__index) {
case 0: return id;
case 1: return name;
case 2: return discriminator;
case 3: return admin;
//case 4: return children;
//case 5: return plantcomponents;
}
return null;
}
public void setProperty(int __index, Object value) {
switch(__index) {
case 0: id = Integer.parseInt(value.toString()); break;
case 1: name = value.toString(); break;
case 2: discriminator = value.toString(); break;
case 3: admin = Boolean.parseBoolean(value.toString()); break;
//case 4: children = (List) __obj; break;
//case 5: plantcomponents = (List) __obj; break;
}
}
public void getPropertyInfo(int __index, Hashtable __table, PropertyInfo __info) {
switch(__index) {
case 0:
__info.name = "id";
__info.type = Integer.class; break;
case 1:
__info.name = "name";
__info.type = String.class; break;
case 2:
__info.name = "discriminator";
__info.type = String.class; break;
case 3:
__info.name = "admin";
__info.type = Boolean.class; break;
/*
case 4:
__info.name = "children";
__info.type = PropertyInfo.VECTOR_CLASS;
case 5:
__info.name = "plantcomponents";
__info.type = PropertyInfo.VECTOR_CLASS;
*/
}
}
}
Here is my webservice call:
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
// For testing I only want to have 3 results
request.addProperty("limit", "3");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
// add mapping
// ResponsiblepartyGetResponse got namespace in XML
envelope.addMapping(NAMESPACE, "ResponsiblepartyGetResponse", new ResponsiblepartyGetResponse().getClass());
// ResponsiblePartyFacades doesn't have namespace. I also tried to add namespace, but same result
envelope.addMapping("", "ResponsiblePartyFacades", new ResponsiblePartyFacade().getClass());
ResponsiblepartyGetResponse result = new ResponsiblepartyGetResponse();
try {
AuthTransportSE androidHttpTransport = new AuthTransportSE(URL, USERNAME, PASSWORD);
androidHttpTransport.debug = true;
androidHttpTransport.call(SOAP_ACTION, envelope);
// this shows me my result as a string, see above
System.out.println(envelope.bodyIn.toString());
// Trying to case the response -> Exception
result = (ResponsiblepartyGetResponse) envelope.bodyIn;
} catch (Exception e){
Log.d("SOAPEnvelope", "Error: "+e.toString());
}
return result;
As in some tutorials shown I also tried to parse the response manually. But for this the response has to be casted to "SoapObject" like this
SoapObject response = (SoapObject)envelope.getResponse();
When I do this I get the following exception:
05-11 07:09:56.389: D/SOAPEnvelope(2209): Error: java.lang.ClassCastException: java.util.Vector cannot be cast to org.ksoap2.serialization.SoapObject
05-11 07:09:56.402: D/SOAPEnvelope(2209): java.lang.ArrayIndexOutOfBoundsException: length=0; index=0
Can anybody give me a hint?
After despairing one more day I found a soultion that goes back to "misco" in java.lang.ClassCastException: org.ksoap2.serialization.SoapObject
I don't try to cast the Response anymore, but building the List myself by hand:
androidHttpTransport.call(SOAP_ACTION, envelope);
ArrayList<ResponsiblePartyFacades> returnlist = new ArrayList<ResponsiblePartyFacades>();
java.util.Vector<SoapObject> rs = (java.util.Vector<SoapObject>) envelope.getResponse();
if (rs != null)
{
for (SoapObject cs : rs)
{
ResponsiblePartyFacades rp = new ResponsiblePartyFacades();
rp.setId(Integer.parseInt(cs.getProperty(0).toString()));
rp.setName(cs.getProperty(1).toString());
rp.setDiscriminator(cs.getProperty(2).toString());
rp.setAdmin(Boolean.parseBoolean(cs.getProperty(3).toString()));
Log.d("WS", "ID = "+rp.getId() +" name = "+rp.getName()+" disc = "+rp.getDiscriminator()+" admin = "+rp.getAdmin().toString() );
returnlist.add(rp);
}
}
here is my solution. It works for me. Instead of using Vector, get the value of SoapObject response.
SoapObject response = (SoapObject) envelope.getResponse();
int count = response.getPropertyCount();
Log.i("count", Integer.toString(count));
for (int i = 0; i < count; i++) {
int id = Integer.parseInt(response
.getPropertyAsString("id"));
Log.i("id", Integer.toString(id));
String name = (response.getPropertyAsString("name"));
Log.i("name", name);
String discriminator = (response
.getPropertyAsString("discriminator"));
Log.i("discriminator", discriminator);
//add this value to List
}
public ArrayList<CadernetaTO> buscarTodasAsCadernetas() {
ArrayList<CadernetaTO> lista = new ArrayList<CadernetaTO>();
SoapObject buscarTodasAsCadernetas = new SoapObject(NAMESPACE, BUSCAR_TODOS);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.setOutputSoapObject(buscarTodasAsCadernetas);
envelope.implicitTypes = true;
HttpTransportSE http = new HttpTransportSE(URL);
try {
http.call(URL + "/" + BUSCAR_TODOS,envelope);
Vector<SoapObject> resposta = (Vector<SoapObject>) envelope.getResponse();
Log.i("entrou no Vector", "Vector");
for (SoapObject soapObject : resposta) {
Log.i("entrou no for", "msg");
CadernetaTO cadern = new CadernetaTO();
Log.i("entrou no to", "CadernetaTO");
cadern.setIdCaderneta(Integer.parseInt(soapObject.getProperty("idCaderneta").toString()));
Log.i("ggigfjjg", "passou linha 1");
cadern.setDose(soapObject.getProperty("dose").toString());
Log.i("ggigfjjg", "passou linha 2");
cadern.setLote(soapObject.getProperty("lote").toString());
Log.i("ggigfjjg", "passou linha 3");
cadern.setData_aplicacao(soapObject.getProperty("data_aplicacao").toString());
Log.i("ggigfjjg", "passou linha 4");
cadern.setSituacao(soapObject.getProperty("situacao").toString());
Log.i("ggigfjjg", "passou linha 5");
cadern.setFkCrianca_idCrianca(Integer.parseInt(soapObject.getProperty("fkCrianca_idCrianca").toString()));
Log.i("ggigfjjg", "passou linha 6");
cadern.setFkVacina_idVacina(Integer.parseInt(soapObject.getProperty("fkVacina_idVacina").toString()));
Log.i("ggigfjjg", "passou linha 7");
lista.add(cadern);
Log.i("testando", cadern.getSituacao() + cadern.getDose() + cadern.getIdCaderneta());
//http.getServiceConnection().setRequestProperty("Connection", "close");
System.setProperty("http.keepAlive", "false");
}

How to send/receive a custom object from Android to .NET using kSOAP?

So, I am a newbie in mobile development and interoperability. I am developing a Android application that comunnicates send a Contact object to a remove server that is running a .NET Web Service (via kSOAP). But there is a 500 error in the server and I really don't know how to map it because it is running remotely and my host plan doesn't allow me to debug remotely. I believe it is an error in the interpretation of the Java object in the ASP.NET Web Service, I don't know if it is necessary to deserialize the object and how to do it. I hope that a more experienced developer could help me. I already used primitive objects (string, int and others) and it worked like a charm but I really prefer to work with my models.
The Android Application - Call of the Web Service:
public int webServiceMethodRegisterUser(String... paramss)
{
String resultData;
try {
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
Contact c = new Contact(paramss[0], paramss[1]);
c._email = paramss[0];
c._password = paramss[1];
c._cellphonesim = paramss[2];
c._simoperator = paramss[3];
PropertyInfo pi = new PropertyInfo();
pi.setName("contact");
pi.setValue(c);
pi.setType(c.getClass());
request.addProperty(pi);
//request.addProperty("useremail", paramss[0]);
//request.addProperty("userpass", paramss[1]);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet=true;
envelope.setOutputSoapObject(request);
envelope.addMapping(NAMESPACE, "Contact" , new Contact().getClass());
//Marshal floatMarshal = new Marshal();
//floatMarshal.register(envelope);
//Marshal oi = new ();
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
Object result=(Object)envelope.getResponse();
//To get the data.
resultData= result.toString();
publishProgress(resultData);
return Integer.parseInt(resultData);
} catch (Exception e) {
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
throw new RuntimeException(e1.toString());
}
throw new RuntimeException(e.toString());
}
}
Custom Object in Java
package com.example.ivi;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import org.ksoap2.serialization.KvmSerializable;
import org.ksoap2.serialization.MarshalDate;
import org.ksoap2.serialization.PropertyInfo;
public class Contact implements KvmSerializable {
// private variables
int _id;
String _email;
String _password;
String _simoperator;
String _cellphonesim;
String _sn_facebook;
String _sn_linkedin;
String _sn_googleplus;
String _sn_orkut;
String _sn_twitter;
Date _last_refresh;
Date _register_date;
public Contact(int id, String email, String password, String simoperator,
String cellphonesim, String facebook, String linkedin,
String googleplus, String orkut, String twitter, Date refreshuser,
Date userregister) {
_id = id;
_email = email;
_password = password;
_simoperator = simoperator;
_cellphonesim = cellphonesim;
_sn_facebook = facebook;
_sn_linkedin = linkedin;
_sn_googleplus = googleplus;
_sn_orkut = orkut;
_sn_twitter = twitter;
_last_refresh = refreshuser;
_register_date = userregister;
}
public Contact() {
}
// constructor
public Contact(int id, String email, String password) {
this._id = id;
this._email = email;
this._password = password;
}
// constructor
public Contact(String email, String password) {
this._email = email;
this._password = password;
}
#Override
public Object getProperty(int arg0) {
switch (arg0) {
case 0:
return _id;
case 1:
return _email;
case 2:
return _password;
case 3:
return _simoperator;
case 4:
return _cellphonesim;
case 5:
return _sn_facebook;
case 6:
return _sn_linkedin;
case 7:
return _sn_googleplus;
case 8:
return _sn_orkut;
case 9:
return _sn_twitter;
case 10:
return _last_refresh;
case 11:
return _register_date;
}
return null;
}
#Override
public int getPropertyCount() {
// TODO Auto-generated method stub
return 12;
}
#Override
public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
switch (index) {
case 0:
info.type = PropertyInfo.INTEGER_CLASS;
info.name = "UserId";
break;
case 1:
info.type = PropertyInfo.STRING_CLASS;
info.name = "UserEmail";
break;
case 2:
info.type = PropertyInfo.STRING_CLASS;
info.name = "UserPassword";
break;
case 3:
info.type = PropertyInfo.STRING_CLASS;
info.name = "UserSimOperator";
break;
case 4:
info.type = PropertyInfo.STRING_CLASS;
info.name = "UserCellPhoneSim";
break;
case 5:
info.type = PropertyInfo.STRING_CLASS;
info.name = "UserFacebook";
break;
case 6:
info.type = PropertyInfo.STRING_CLASS;
info.name = "UserLinkedin";
break;
case 7:
info.type = PropertyInfo.STRING_CLASS;
info.name = "UserGoogleplus";
break;
case 8:
info.type = PropertyInfo.STRING_CLASS;
info.name = "UserOrkut";
break;
case 9:
info.type = PropertyInfo.STRING_CLASS;
info.name = "UserTwitter";
break;
case 10:
info.type = MarshalDate.DATE_CLASS;
;
info.name = "UserLastRefresh";
break;
case 11:
info.type = MarshalDate.DATE_CLASS;
;
info.name = "UserRegisterDate";
break;
}
}
#Override
public void setProperty(int index, Object value) {
SimpleDateFormat formatter = new SimpleDateFormat("dd-MMM-yyyy");
switch (index) {
case 0:
_id = Integer.parseInt(value.toString());
break;
case 1:
_email = value.toString();
break;
case 2:
_password = value.toString();
break;
case 3:
_simoperator = value.toString();
break;
case 4:
_cellphonesim = value.toString();
break;
case 5:
_sn_facebook = value.toString();
break;
case 6:
_sn_linkedin = value.toString();
break;
case 7:
_sn_googleplus = value.toString();
break;
case 8:
_sn_orkut = value.toString();
break;
case 9:
_sn_twitter = value.toString();
break;
case 10:
try {
_last_refresh = formatter.parse(value.toString());
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
case 11:
try {
_register_date = formatter.parse(value.toString());
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
}
}
. NET Web Service
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Xml.Serialization;
namespace WebServiceIvi
{
[WebService(Namespace = "http://www.ividomain.somee.com/Service1")]
[WebServiceBinding(ConformsTo = WsiProfiles.None)]
[System.ComponentModel.ToolboxItem(false)]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public int registerUser(Contact contato)
{
string connString = CONNECTION_STRING;
SqlConnection con = new SqlConnection(connString);
SqlCommand cmdSQL = con.CreateCommand();
try
{
con.Open();
cmdSQL.CommandText = String.Format("INSERT INTO [databaseivi].[dbo].[UsersIvi] ([Useremail],[Userpass],[Userxml],[Usersince]) VALUES('{0}','{1}',null ,getDate())", contato.UserEmail, contato.UserPassword);
int result = cmdSQL.ExecuteNonQuery();
con.Close();
return result;
}
catch (SqlException e)
{
foreach (SqlError error in e.Errors)
{
return error.Number;
}
return 0;
}
}
}
}
The Custom Object in C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WebServiceIvi
{
public class Contact
{
public Contact(int id, String email, String password, String simoperator, String cellphonesim, String facebook, String linkedin, String googleplus, String orkut, String twitter, DateTime refreshuser, DateTime userregister )
{
_id = id;
_email = email;
_password = password;
_simoperator = simoperator;
_cellphonesim = cellphonesim;
_sn_facebook = facebook;
_sn_linkedin = linkedin;
_sn_googleplus = googleplus;
_sn_orkut = orkut;
_sn_twitter = twitter;
_last_refresh = refreshuser;
_register_date = userregister;
}
public Contact()
{
}
int _id;
String _email;
String _password;
String _simoperator;
String _cellphonesim;
String _sn_facebook;
String _sn_linkedin;
String _sn_googleplus;
String _sn_orkut;
String _sn_twitter;
DateTime _last_refresh;
DateTime _register_date;
public int UserId
{
set { _id = value; }
get
{
if (_id <= 0) return _id;
else return 0;
}
}
public string UserEmail
{
set { _email = value; }
get
{
if (_email != null) return _email.ToString();
else return string.Empty;
}
}
public string UserPassword
{
set { _password = value; }
get
{
if (_password != null) return _password.ToString();
else return string.Empty;
}
}
public string UserSimOperator
{
set { _simoperator = value; }
get
{
if (_simoperator != null) return _simoperator.ToString();
else return string.Empty;
}
}
public string UserCellPhoneSim
{
set { _cellphonesim = value; }
get
{
if (_cellphonesim != null) return _cellphonesim.ToString();
else return string.Empty;
}
}
public string UserFacebook
{
set { _sn_facebook = value; }
get
{
if (_sn_facebook != null) return _sn_facebook.ToString();
else return string.Empty;
}
}
public string UserLinkedin
{
set { _sn_linkedin = value; }
get
{
if (_sn_linkedin != null) return _sn_linkedin.ToString();
else return string.Empty;
}
}
public string UserGoogleplus
{
set { _sn_googleplus = value; }
get
{
if (_sn_googleplus != null) return _sn_googleplus.ToString();
else return string.Empty;
}
}
public string UserOrkut
{
set { _sn_orkut = value; }
get
{
if (_sn_orkut != null) return _sn_orkut.ToString();
else return string.Empty;
}
}
public string UserTwitter
{
set { _sn_twitter = value; }
get
{
if (_sn_twitter != null) return _sn_twitter.ToString();
else return string.Empty;
}
}
public DateTime UserLastRefresh
{
set { _last_refresh = value; }
get
{
if (_last_refresh != null) return DateTime.Parse(_last_refresh.ToString());
else return DateTime.MinValue;
}
}
public DateTime UserRegisterDate
{
set { _register_date = value; }
get
{
if (_register_date != null) return DateTime.Parse(_register_date.ToString());
else return DateTime.MinValue;
}
}
}
}
The SOAP Request XML:
POST /Service1.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://www.ividomain.somee.com/Service1/registerUser"
<?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>
<registerUser xmlns="http://www.ividomain.somee.com/Service1">
<contato>
<UserId>int</UserId>
<UserEmail>string</UserEmail>
<UserPassword>string</UserPassword>
<UserSimOperator>string</UserSimOperator>
<UserCellPhoneSim>string</UserCellPhoneSim>
<UserFacebook>string</UserFacebook>
<UserLinkedin>string</UserLinkedin>
<UserGoogleplus>string</UserGoogleplus>
<UserOrkut>string</UserOrkut>
<UserTwitter>string</UserTwitter>
<UserLastRefresh>dateTime</UserLastRefresh>
<UserRegisterDate>dateTime</UserRegisterDate>
</contato>
</registerUser>
</soap:Body>
</soap:Envelope>
I've been stuck in this for a while and didn't found any implementation and deserialization of a java model in .NET. I hope someone out there helps me! =D
ThiagoMello, I had this error days ago and solve it generting java class from this site:
http://www.wsdl2code.com/Pages/Home.aspx
With this classes my code works fine! Try it.
Hope this helps.
Joan.

Parsing complex soap response

I'm building my first application in android which consumes a wcf service.I'm using ksoap2 to parse the response.The response is actually an array of objects defined in C#.I did this following this really helpful guide.Now my problem is that I need to consume a wcf service which returns again an array of objects in C# but this time some properties of these objects are other objects.So my question is how can I map the inner objects so that i can parse their properties?
In case I was unclear, I need to parse an object like this:
public class OutterObject {
private InnerObject1 io1;
private InnerObject2 io2;
}
Hope I was clear enough
Ok this is my simplified code i can't post all of it just the portion i think is at fault
SoapObject Request = new SoapObject(NAMESPACE, METHOD_NAME);
Request.addProperty("connString",args.get(0));
Request.addProperty("ClCode", args.get(1));
Request.addProperty("TeCode", args.get(2));
Request.addProperty("CourseDate", args.get(3));
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
envelope.addMapping(namespace, "SRV_WeekProgramm",newSRV_WeekProgramm().getClass());
envelope.addMapping(namespace, "Course", new Course().getClass());
envelope.addMapping(namespace, "StudentHours", new StudentHours().getClass());
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
Course response = (Course)envelope.bodyIn; //this is where it crashes
and this is the thrown exception: java.lang.ClassCastException: org.ksoap2.serialization.SoapObject cannot be cast to connectionInitializer.Course
Here is an example that worked for me.
This is response message type from web service
<message name="loginUserResponse">
<part name="code" type="xsd:int"/>
<part name="desc" type="xsd:string"/>
<part name="user" type="tns:user"/>
</message>
The method loginUser definition
<operation name="loginUser">
<documentation>Login user.</documentation>
<input message="tns:loginUserRequest"/>
<output message="tns:loginUserResponse"/>
</operation>
Class UserResponse (Outter) contains User property:
public class UserResponse implements KvmSerializable {
public int code;
public String desc;
public User user;
public Object getProperty(int arg0) {
switch (arg0) {
case 0:
return code;
case 1:
return desc;
case 2:
return user;
default:
break;
}
return null;
}
public int getPropertyCount() {
return 3;
}
public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
switch (index) {
case 0:
info.type = PropertyInfo.STRING_CLASS;
info.name = "code";
break;
case 1:
info.type = PropertyInfo.STRING_CLASS;
info.name = "desc";
break;
case 2:
info.type = User.class;
info.name = "user";
break;
default:
break;
}
}
public void setProperty(int index, Object value) {
switch (index) {
case 0:
this.code = Integer.parseInt(value.toString());
break;
case 1:
this.desc = value.toString();
break;
case 2:
this.user = (User) value;
default:
break;
}
}
}
And the User class (Inner)
public class User implements KvmSerializable {
public int user_id;
public String username;
public String email;
public String password;
public User() {
}
public Object getProperty(int index) {
switch (index) {
case 0:
return user_id;
case 1:
return username;
case 2:
return email;
case 3:
return password;
default:
return null;
}
}
public int getPropertyCount() {
return 4;
}
public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) {
switch (index) {
case 0:
info.type = PropertyInfo.INTEGER_CLASS;
info.name = "user_id";
break;
case 1:
info.type = PropertyInfo.STRING_CLASS;
info.name = "username";
break;
case 2:
info.type = PropertyInfo.STRING_CLASS;
info.name = "email";
break;
case 3:
info.type = PropertyInfo.STRING_CLASS;
info.name = "password";
break;
default:
break;
}
}
public void setProperty(int index, Object value) {
if(null == value)
value = "";
switch (index) {
case 0:
user_id = Integer.parseInt(value.toString());
break;
case 1:
username = value.toString();
break;
case 2:
email = value.toString();
break;
case 3:
password = value.toString();
break;
}
}
This is important: make sure you register the keys for both outter class and inner class.
envelope.addMapping(NAMESPACE, "loginUserResponse", UserResponse.class);
envelope.addMapping(NAMESPACE, "user", User.class);
Finally, you can get the result by casting:
HttpTransportSE androidHttpTransport = new HttpTransportSE(SERVER_URL); //open the requisition
androidHttpTransport.call(SOAP_ACTION, envelope);// call
UserResponse response = (UserResponse)envelope.bodyIn;
Hope this help!

Server receives null when sending complex type from android client to wcf service

I am using ksoap2 library for connecting to a wcf web service. When I try to send primitive types, server gets these values and send a correct response. However, if I try to send a complex type ( an object that is a subtype of KVMSerilizable ) the server receives null.
Below is the class definition of the object that I want to send.
import java.util.Hashtable;
import org.ksoap2.serialization.KvmSerializable;
import org.ksoap2.serialization.PropertyInfo;
public class TwoIntegerWrapper implements KvmSerializable {
private int Num1;
private int Num2;
public TwoIntegerWrapper() {
super();
}
TwoIntegerWrapper(int number1, int number2) {
super();
this.Num1 = number1;
this.Num2 = number2;
}
public int getNumber1() {
return Num1;
}
public void setNumber1(int number1) {
this.Num1 = number1;
}
public int getNumber2() {
return Num2;
}
public void setNumber2(int number2) {
this.Num2 = number2;
}
public Object getProperty(int propertyNumber) {
Object property = null;
switch (propertyNumber) {
case 0:
property = this.Num1;
break;
case 1:
property = this.Num2;
break;
}
return property;
}
public int getPropertyCount() {
return 2;
}
public void getPropertyInfo(int propertyNumber, Hashtable arg1,
PropertyInfo propertyInfo) {
switch (propertyNumber) {
case 0:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "Num1";
break;
case 1:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "Num2";
break;
}
}
public void setProperty(int propertyNumber, Object data) {
switch (propertyNumber) {
case 0:
this.Num1 = Integer.parseInt(data.toString());
break;
case 1:
this.Num2 = Integer.parseInt(data.toString());
break;
}
}
}
And here is how I call web service.
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
PropertyInfo property = new PropertyInfo();
TwoIntegerWrapper tiw = new TwoIntegerWrapper(num1Value, num2Value);
property.setName("TwoIntegerWrapper");
property.setType(tiw.getClass());
property.setValue(tiw);
request.addProperty(property);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
envelope.addMapping(NAMESPACE, tiw.getClass().getSimpleName(), TwoIntegerWrapper.class);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.debug = true;
try {
androidHttpTransport.call(Add_SOAP_ACTION, envelope);
Log.d(logtag + " request dump", androidHttpTransport.requestDump);
Log.d(logtag + " response dump", androidHttpTransport.responseDump);
SoapPrimitive sp = (SoapPrimitive) envelope.getResponse();
result = Integer.parseInt(sp.toString());
}
What are the possible reasons?
One common issue for this is that, assuming you are sending XML on the wire, that the XML is in the wrong namespace. In that case the WCF deserializer will decide there is nothing that it knows about in the XML and return null
I would suggest to inspect the request and respone using Fiddler.
Enable Tracing on your WCF Service and see what is the message that comes up on the channel by inspecting the trace files.
ok your class which implements kvmserializable is accurate based on xsd2.
However the methods (message) that you have for AddNumbers2,AddNumbers3 have first AN ELEMENT which HAS an element type complex type, for example:
<xs:element name="AddNumbers2">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="obj" nillable="true" type="q1:TwoIntegerWrapper"/>
</xs:sequence>
</xs:complexType>
</xs:element>
So what you should do is :
property.setName("AddNumbers2");//not TwoIntegerWrapper, coz the main property is AddNumbers2
property.setType(tiw.getClass());
property.setValue(tiw);
request.addProperty(property);
I found the solution by changing getPropertyInfo function of TwoIntegerWrapper class. I also set namespaces for each property in this class. The new implementation is the following:
public void getPropertyInfo(int propertyNumber, Hashtable arg1,
PropertyInfo propertyInfo) {
switch (propertyNumber) {
case 0:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "Num1";
propertyInfo.setNamespace(TWO_INTEGER_WRAPPER_NAMESPACE);
break;
case 1:
propertyInfo.type = PropertyInfo.INTEGER_CLASS;
propertyInfo.name = "Num2";
propertyInfo.setNamespace(TWO_INTEGER_WRAPPER_NAMESPACE);
break;
}
}
Even if I remove mapping from the envelope, it works. I could not understand why it is so, but it works. I appreciate if someone explains the reason. Wsdl file, xsd0, xsd1 and xsd2 files are in the link http://www.ceng.metu.edu.tr/~e1559897/
By the way, I also changed
property.setName("TwoIntegerWrapper");
to
property.setName("obj");

Categories

Resources