第十一篇:REST调用
上篇写的是Ajax调用WCF,今天写一篇如何以REST方式调用WCF服务。不知道REST是什么的同学,可以去google一下。对某些类型的应用,REST还是相当不错的方式,所以专门写一篇来说明一下开发方法。
老规矩,上代码,直接在代码注释里讲解。
1、服务端:
服务契约,我们定义CRUD4个方法(增查改删),对应HTTP METHOD分别为PUT/GET/POST/DELETE:
using System;
using System.ServiceModel;
using System.ServiceModel.Web; //这个命名空间要求引入System.ServiceModel.Web.dll
namespace Server
{
[ServiceContract(Namespace = "WCF.Demo")]
publicinterface IData
{
//WebInvoke中标明REST的相关属性,以这个方法为例,调用的Url是 ..../Data/key/data,HTTP方法是PUT,响应为Json格式(也可以换成xml)
//这样如果客户端用PUT方法访问 ..../Data/1/100,就会映射到CreateData方法上来,并且传入key=1,data=100
[OperationContract]
[WebInvoke(UriTemplate = "Data/{key}/{data}", Method = "PUT", ResponseFormat = WebMessageFormat.Json)]
void CreateData(string key, string data);
[OperationContract]
[WebInvoke(UriTemplate = "Data/{key}", Method = "GET", ResponseFormat = WebMessageFormat.Json)]
string RetrieveData(string key);
[OperationContract]
[WebInvoke(UriTemplate = "Data/{key}/{data}", Method = "POST", ResponseFormat = WebMessageFormat.Json)]
void UpdateData(string key, string data);
[OperationContract]
[WebInvoke(UriTemplate = "Data/{key}", Method = "DELETE", ResponseFormat = WebMessageFormat.Json)]
void DeleteData(string key);
}
}
然后是实现类,这个简单,没什么可说的。
using System;
using System.Collections.Generic;
using System.ServiceModel;
namespace Server
{
//这个例子中用了Single Instance模式,这样m_DataDict的值才能保留住
[ServiceInstanceContextMode = InstanceContextMode.Single)]
publicclass DataProvider : IData
{
private Dictionary<string, string> m_DataDict = new Dictionary<string, string>();
publicvoid CreateData(string key, string data)
{
m_DataDict[key] = data;
}
publicstring RetrieveData(string key)
{
return m_DataDict.ContainsKey(key) ? m_DataDict[key] : "NOT FOUND";
}
publicvoid UpdateData(string key, string data)
{
m_DataDict[key] = data;
}
publicvoid DeleteData(string key)
{
m_DataDict.Remove(key);
}
}
}
配置文件最关键了,注意里面绿色的注释部分:
<?xmlversion="1.0"encoding="utf-8"?>
<configuration>
<system.serviceModel>
<services>
<servicename="Server.DataProvider">
<!--必须使用webHttpBinding,而且要定义此endpoint的behaviorConfiguration(见后)-->
<endpointaddress=""binding="webHttpBinding"contract="Server.IData"behaviorConfiguration="restBehavior"/>
<host>
<baseAddresses>
<addbaseAddress="http://localhost:8080/wcf"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<!--定义endpoint的behavior,webHttp节点表示启用web方式访问,这对REST是非常关键的-->
<endpointBehaviors>
<behaviorname="restBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
最后发布服务,没什么特殊的,和以前一样:
using System;
using System.ServiceModel;
namespace Server
{
class Program
{
staticvoid Main(string[] args)
{
using(ServiceHost host = new ServiceHost(typeof(Server.DataProvider)))
{
host.Open();
Console.WriteLine("Running ...");
Console.ReadKey();
host.Close();
}
}
}
}
这个服务端没有用IIS做HOST,直接用自己的进程做的宿主(当然了,本质还是http.sys在工作)。
2、客户端
我们这回要用REST形式访问服务端,所以不是普通意义上的WCF客户端了,再也用不着那么麻烦的写配置文件创建Channel或者代理了。
using System;
using System.Net;
namespace Client
{
class Program
{
staticvoid Main(string[] args)
{
//用一个WebClient就可以搞定了
var client = new WebClient();
//以PUT方式访问Data/1/100,会映射到服务端的CreateData("1", "100")
client.UploadString("http://localhost:8080/wcf/Data/1/100", "PUT", string.Empty);
//以GET方式访问Data/1,会映射到服务端的RetrieveData("1"),应该返回"100"
Console.WriteLine(client.DownloadString("http://localhost:8080/wcf/Data/1"));
//以POST方式访问Data/1/200,会映射到服务端的UpdateData("1", "200")
client.UploadString("http://localhost:8080/wcf/Data/1/200", "POST", string.Empty);
//再GET一次,应该返回"200"
Console.WriteLine(client.DownloadString("http://localhost:8080/wcf/Data/1"));
//以DELETE方式访问Data/1,会映射到服务端的DeleteData("1")
client.UploadString("http://localhost:8080/wcf/Data/1", "DELETE", string.Empty);
//再GET一次,应该返回"NOT FOUND"
Console.WriteLine(client.DownloadString("http://localhost:8080/wcf/Data/1"));
}
}
}
OK,运行一下客户端,返回如下,和预期一致:
需要补充一下,如果用IIS做HOST,比如DataService.svc.cs是实现类,一定要在DataService.svc中加上Factory,如下:
<%@ ServiceHost Language="C#" Debug="true" Service="WebServer.DataService" CodeBehind="DataService.svc.cs" Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>
表明不是使用默认的ServiceHostFactory,而是适应WEB HTTP开发的WebServiceHostFactory。