It seems processing XML is too heavy for mobile devices. Android
did not provide any tool to help consuming SOAP web service. But as
Android bundled with org.apache.http and org.json packages, it is
relative simple to consume RESTful WCF services.
The following sections describe the steps to create RESTfule WCF
services and the Android client to consume the services.
First, I created a service contract with two GET and one POST
operations. Since the Android client will transfer data in JSON
objects, I specify JSON as request and response format. In order to
support more than one parameter, I set BodyStyle to
WrappedRequest.
namespace HttpWcfWeb
{
[ServiceContract(Namespace = "http://services.example.com")]
public interface IVehicleService
{
[OperationContract]
[WebGet(
UriTemplate = "GetPlates",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
IList<string> GetPlates();
[OperationContract]
[WebGet(UriTemplate = "GetVehicle/{plate}",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
Vehicle GetVehicle(string plate);
[OperationContract]
[WebInvoke(
Method = "POST",
UriTemplate = "SaveVehicle",
BodyStyle = WebMessageBodyStyle.WrappedRequest,
ResponseFormat = WebMessageFormat.Json,
RequestFormat = WebMessageFormat.Json)]
void SaveVehicle(Vehicle vehicle);
}
}
Next, I defined the composite object will be transferred between
server and Android client. It is simple but enough to prove we will
be able to transfer complex objects.
namespace HttpWcfWeb
{
[DataContract]
public class Vehicle
{
[DataMember(Name = "year")]
public int Year
{
get;
set;
}
[DataMember(Name = "plate")]
public string Plate
{
get;
set;
}
[DataMember(Name = "make")]
public string Make
{
get;
set;
}
[DataMember(Name = "model")]
public string Model
{
get;
set;
}
}
}
Now, expose the WCF service via webHttp behavior in
web.config.
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="httpBehavior">
<webHttp />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
<services>
<service name="HttpWcfWeb.VehicleService">
<endpoint address=""
behaviorConfiguration="httpBehavior"
binding="webHttpBinding"
contract="HttpWcfWeb.IVehicleService" />
</service>
</services>
</system.serviceModel>
It you are using Visual Studio's Development Server to test the
WCF service, you may need to deploy the service to IIS. This is due
to the Development Server only serve request from local machine,
and the Android client won't be able to access the service hosted
on it.
Further, if you are using host name (e.g. computer name) in the
URL of the service, you may have to setup the DNS in you device or
emulator, so that it can resolve the host name. Simply go to
Settings -> Wireless Control -> Mobile Networks -> Access
Point Names, click on the one that is in use, fill in
Proxy and Port with your DNS server.

Now, I have my WCF service ready, and I am going to build the
Android client to consume the WCF service.

During initialization, the Activity will invoke
IVehicleService.GetPlates method to populate the
Spinner. When the Load Vehicle button is clicked,
the vehicle will be loaded from the
IVehicleService.GetVehicle method and the
EditText views will be populated. On the other hand,
Save button will wrap the data entered and post to
IVehicleService.SaveVehicle method.
The code the initialize the UI I created.
public class MainActivity extends Activity {
private final static String SERVICE_URI = "http://lt0.studio.entail.ca:8080/VehicleService.svc";
private Spinner plateSpinner;
private EditText makeEdit;
private EditText plateEdit;
private EditText yearEdit;
private EditText modelEdit;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
plateSpinner = (Spinner)findViewById(R.id.plate_spinner);
makeEdit = (EditText)findViewById(R.id.make_edit);
plateEdit = (EditText)findViewById(R.id.plate_edit);
yearEdit = (EditText)findViewById(R.id.year_edit);
modelEdit = (EditText)findViewById(R.id.model_edit);
}
@Override
public void onResume() {
super.onResume();
// Invoke IVehicleService.GetPlates and populate plateSpinner
refreshVehicles();
}
}
The refreshVehicles method will be invoked when the
activity is resumed or a new vehicle is saved. It send a GET
request to the WCF service and retrieves a list of plates in JSON
string, and the response string is parsed by
JSONArray.
private void refreshVehicles() {
try {
// Send GET request to <service>/GetPlates
HttpGet request = new HttpGet(SERVICE_URI + "/GetPlates");
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
HttpEntity responseEntity = response.getEntity();
// Read response data into buffer
char[] buffer = new char[(int)responseEntity.getContentLength()];
InputStream stream = responseEntity.getContent();
InputStreamReader reader = new InputStreamReader(stream);
reader.read(buffer);
stream.close();
JSONArray plates = new JSONArray(new String(buffer));
// Reset plate spinner
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
for (int i = 0; i < plates.length(); ++i) {
adapter.add(plates.getString(i));
}
plateSpinner.setAdapter(adapter);
} catch (Exception e) {
e.printStackTrace();
}
}
The onLoadVehicleClick method is the event handler for
Load Vehicle button. Just like refreshVehicles
method, It send a GET request to the WCF service and retrieve the
vehicle information by plate number. But instead of
JSONArray, it used JSONObject to parse the
response data, since the WCF service is returning an vehicle
object.
public void onLoadVehicleClick(View button) {
try {
// Send GET request to <service>/GetVehicle/<plate>
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpGet request = new HttpGet(SERVICE_URI + "/GetVehicle/" + plateSpinner.getSelectedItem());
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
HttpResponse response = httpClient.execute(request);
HttpEntity responseEntity = response.getEntity();
// Read response data into buffer
char[] buffer = new char[(int)responseEntity.getContentLength()];
InputStream stream = responseEntity.getContent();
InputStreamReader reader = new InputStreamReader(stream);
reader.read(buffer);
stream.close();
JSONObject vehicle = new JSONObject(new String(buffer));
// Populate text fields
makeEdit.setText(vehicle.getString("make"));
plateEdit.setText(vehicle.getString("plate"));
modelEdit.setText(vehicle.getString("model"));
yearEdit.setText(vehicle.getString("year"));
} catch (Exception e) {
e.printStackTrace();
}
}
When Save button is clicked,
onSaveVehicleClick method will be invoked. It simply
gather all text fields into a JSONObject and post it to
the WCF service. Noticed that the all the data was wrapped into an
object named vehicle, WCF will pass this object as
parameter vehicle.
public void onSaveVehicleClick(View button) {
try {
Editable make = makeEdit.getText();
Editable plate = plateEdit.getText();
Editable model = modelEdit.getText();
Editable year = yearEdit.getText();
boolean isValid = true;
// Data validation goes here
if (isValid) {
// POST request to <service>/SaveVehicle
HttpPost request = new HttpPost(SERVICE_URI + "/SaveVehicle");
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
// Build JSON string
JSONStringer vehicle = new JSONStringer()
.object()
.key("vehicle")
.object()
.key("plate").value(plate)
.key("make").value(make)
.key("model").value(model)
.key("year").value(Integer.parseInt(year.toString()))
.endObject()
.endObject();
StringEntity entity = new StringEntity(vehicle.toString());
request.setEntity(entity);
// Send request to WCF service
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
Log.d("WebInvoke", "Saving : " + response.getStatusLine().getStatusCode());
// Reload plate numbers
refreshVehicles();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Finally, add the internet permission into
AndroidManifest.xml, to allow the sample application
access WCF service.
<uses-permission android:name="android.permission.INTERNET" />
And the demo is ready to go.
