本文转自:http://hi.baidu.com/iytwcrfaukbbcuq/item/366263e2ebc1612e4ddcaffe
原文:http://fszlin.dymetis.com/post/2010/05/10/Comsuming-WCF-Services-With-Android.aspx
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
namespace
HttpWcfWeb
{
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public
class
MainActivity
extends
Activity {
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
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.
1
|
<
uses-permission
android:name
=
"android.permission.INTERNET"
/>
|