[翻译]实例:在Android调用WCF服务

原文:http://fszlin.dymetis.com/post/2010/05/10/Comsuming-WCF-Services-With-Android.aspx

 

在移动设备中,使用XML传输可能会消耗更多的资源,Android没有提供任何组件来直接调用WCF,但是我们可以通过第三方的包(例如:org.apache.http,org.json)来相对简单的调用REST形式的WCF服务。

本文将演示如何创建REST形式的WCF服务和在Android上如何调用服务。

第一步,创建一个包含两个GET操作和一个POST操作的Service Contract。由于是通过JSON对象传输数据,这里需要指定Request和Response的数据格式为JSON。为了支持多个参数,还需要设置BodyStyle为WrappedRequest。

 

 1 namespace HttpWcfWeb
2 {
3 [ServiceContract(Namespace = "http://services.example.com")]
4 public interface IVehicleService
5 {
6 [OperationContract]
7 [WebGet(
8 UriTemplate = "GetPlates",
9 BodyStyle = WebMessageBodyStyle.WrappedRequest,
10 ResponseFormat = WebMessageFormat.Json,
11 RequestFormat = WebMessageFormat.Json)]
12 IList<string> GetPlates();
13
14 [OperationContract]
15 [WebGet(UriTemplate = "GetVehicle/{plate}",
16 BodyStyle = WebMessageBodyStyle.WrappedRequest,
17 ResponseFormat = WebMessageFormat.Json,
18 RequestFormat = WebMessageFormat.Json)]
19 Vehicle GetVehicle(string plate);
20
21 [OperationContract]
22 [WebInvoke(
23 Method = "POST",
24 UriTemplate = "SaveVehicle",
25 BodyStyle = WebMessageBodyStyle.WrappedRequest,
26 ResponseFormat = WebMessageFormat.Json,
27 RequestFormat = WebMessageFormat.Json)]
28 void SaveVehicle(Vehicle vehicle);
29 }
30 }

下一步,定义一个用于数据传输的对象,这个对象很简单。

 1 namespace HttpWcfWeb
2 {
3 [DataContract]
4 public class Vehicle
5 {
6 [DataMember(Name = "year")]
7 public int Year
8 {
9 get;
10 set;
11 }
12
13 [DataMember(Name = "plate")]
14 public string Plate
15 {
16 get;
17 set;
18 }
19
20 [DataMember(Name = "make")]
21 public string Make
22 {
23 get;
24 set;
25 }
26
27 [DataMember(Name = "model")]
28 public string Model
29 {
30 get;
31 set;
32 }
33 }
34 }

现在,我们修改web.config文件,发布WCF服务。

<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>

由于VS内置的开发服务器只能处理来自本机的请求,所以需要把服务部署到IIS。

另外,如果你在URL中使用主机名(比如:机器名)的话,你也许还需要在设备或模拟器中设置DNS,这样才可以解析主机名。方法是,进入“系统设置(Setting)”->无线网络设置(Wireless Control)->网络接入点,选择正在使用的那一个,填写代理和端口。

 image

现在,我需要创建Android客户端来调用WCF服务。

image[1]_3

在启动过程中,活动(Activity)调用IVehicleService.GetPlates方法填充Spinner。

当Load Vehicle按钮点击时,通过调用IVehicleService.GetVehicle方法得到Vehicle对象并填充到EditText中。

点击Save按钮时,将数据包装并提交到IVehicleService.SaveVehicle方法。

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



在数据保存或者Activity被恢复(resumed)的时候会调用refreshVehicles方法,它向WCF服务发送一个Get请求,得到一个由JSON字符串表达的数据对象。

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

onLoadVehicleClick 方法处理Load Vehicle 点击事件,和refreshVehicles 方法相似,它发送一个GET请求到WCF服务,通过plate number得到一个vehicle对象,但区别在于,它在结果处理中使用了JSONObject 转换,就像直接从WCF服务中拿到的vehicle对象一样。

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

当Save按钮点击时,调用onSaveVehicleClick 方法。这个方法中简单的将所有的文本字段的值放入一个JSONObject对象,然后提交(POST)给WCF服务。注意所有的数据包装进了一个叫vehicle的对象,WCF收到后,会将其作为名称为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();
}
}

最后,在AndroidManifest.xml中添加Internet的访问权限。

<uses-permission android:name="android.permission.INTERNET" />

DEMO可以运行。

android application

posted @ 2011-12-16 17:16  一味  阅读(14646)  评论(9编辑  收藏  举报