I have rammed my head against this wall for a couple of days now so any help is very appreciated.
A bit of background, first. I am a seasoned WindowsMobile developer moving into Android so I am therefore a noob in Java, Android, and even WCF. I have done a lot of research on how to consume WCF apps in Android using kSOAP2 but no matter what I do the best I can come up with is a socket error in Android because of a time out.
First, I created a web service application in Visual Studio 2008 that requires no parameters and simply responds with a string value. The web service code is as follows:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
namespace Sample
{
[WebService(Namespace = "http://sample.com/")]
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string SayHello()
{
return "Hello, Android. From your friend, WCF";
}
}
}
For this web service I did not adjust any other settings or make any modifications to the Web.config file.
When I run the service it opens up my browser and points to the following url:
http://localhost:61554/Service1.asmx
Next, I jumped into Eclipse and created a simple Android project to consume the WCF service. For starters I changed the AndroidManifest.xml file and added this statement to it:
<uses-permission android:name="android.permission.INTERNET" />
Now for the code from my Android class that is supposed to do the heavy lifting:
package com.sample;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import org.ksoap2.*;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.*;
public class Sample extends Activity {
TextView result;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
result = (TextView)findViewById(R.id.textViewResult);
try {
SoapObject Request = new SoapObject("http://sample.com/", "SayHello");
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(Request);
HttpTransportSE androidHttpTransport = new HttpTransportSE("http://192.168.1.72:61554/Service1.asmx");
androidHttpTransport.call("http://192.168.1.72:61554/SayHello", envelope);
SoapObject response = (SoapObject)envelope.getResponse();
String resultValue = response.getProperty(0).toString();
result.setText(resultValue);
}
catch (Exception e) {
result.setText(e.getMessage());
}
}
}
The line of code that is giving me the error is:
androidHttpTransport.call("http://192.168.1.72:61554/SayHello", envelope);
When run in the emulator the code gets to that line, pauses for a minute or two, and then falls into the catch block with a time out exception.
Any ideas on what I might be missing here? The help is appreciated.
Okay, I FINALLY figured out my problem(s). Several factors were at play which you would expect for someone new to these technologies. Hopefully my mistakes will save others some time.
The first problem I had was a parameter error in my code. The line
androidHttpTransport.call("http://192.168.1.72:61554/SayHello", envelope);
was incorrect in that it should have listed the namespace for my web service followed by the method name. So I changed that line to this:
androidHttpTransport.call("http://sample.com/SayHello", envelope);
After this change I still had the line throw an exception but now I was getting a different exception which was at least a moral victory. The new exception said this:
expected START_TAG{http://schemas.xmlsoap.org/soap/envelope/} Envelope(position:START_TAG<html>@1:6 in java.io.InputStreamReader@d3el2cc4)
This message is rampant on the internet but none of the solutions I found worked for me. After lots of trial and error I found my particular problem. My web service is created in Visual Studio 2008 and I am testing it simply by running it inside Visual Studio and then trying to consume it from my Android emulator. It turns out that there is a security setting in the VS2008 "sandbox" IIS that rejects any requests beyond the local PC -- and apparently the emulator is not considered the local PC.
To correct that issue I took the following steps in Visual Studio 2008:
After completing these steps I ran my web service again, launched my Android app in the emulator and finally got by the line that has been throwing an exception all along. This time, however, the next line threw an exception. Another moral victory and a step closer. This new exception was:
org.ksoap2.serialization.SoapPrimitive
A quick Google search solved this one for me. The lines
SoapObject response = (SoapObject)envelope.getResponse();
String resultValue = response.getProperty(0).toString();
in my original code needed to be changed to this:
SoapPrimitive response = (SoapPrimitive)envelope.getResponse();
String resultValue = response.toString();
After that change I had a working application.
Final working code
Web service (created in Visual Studio 2008 and running on local IIS web server as configured in project properties)
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
namespace Sample {
[WebService(Namespace = "http://sample.com/")]
public class Service1 : System.Web.Services.WebService {
[WebMethod]
public string SayHello() {
return "Hello, Android. From your friend, WCF";
}
}
}
Android class
package com.sample;
import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;
import org.ksoap2.*;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.*;
import org.ksoap2.serialization.SoapPrimitive;
public class Sample extends Activity {
TextView result;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
result = (TextView)findViewById(R.id.textViewResult);
final String SOAP_ACTION = "http://sample.com/SayHello";
final String METHOD_NAME = "SayHello";
final String NAMESPACE = "http://sample.com/";
final String URL = "http://192.168.1.72/Sample/Service1.asmx";
try {
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);
SoapPrimitive response = (SoapPrimitive)envelope.getResponse();
String resultValue = response.toString();
result.setText(resultValue);
}
catch (Exception e) {
result.setText(e.getMessage());
}
}
}