Consuming a localhost WCF service using kSOAP2 in emulator

BreakingBrad picture BreakingBrad · Jun 30, 2011 · Viewed 8.2k times · Source

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.

Answer

BreakingBrad picture BreakingBrad · Jul 22, 2011

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:

  1. Exit Visual Studio and open it using Administrative rights (I am using Windows 7).
  2. With my project open I viewed the project properties.
  3. On the "Web" tab I changed the "Servers" section's radio button to "Use Local IIS Web server", entered "http://localhost/Sample" for my Project URL and clicked the "Create Virtual Directory" button.

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());
        }
    }
}