WCF实现REST
2012-10-09 17:46
176 查看
REST
表述性状态转移(Representational State Transfer,REST),不是一种标准,而是一种软件架构风格。
基于REST的服务与基于SOAP的服务相比,性能、效率和易用性上都更高,而SOAP协议非常的复杂和不透明。REST受到越来越多的Web服务供应商欢迎。目前大部分供应商,如yahoo、google、Amazon等都提供REST风格的服务。
REST的主要原则是:
1.网络上的所有事物都可被抽象为资源;
2.每个资源都有一个唯一的资源标识符URI;
3.使用标准方法操作资源;
4.所有的操作都是无状态的;
5.通过缓存来提高性能。
REST是基于Http协议的,任何对资源的操作行为都是通过Http协议来实现。Http把对一个资源的操作限制在4个方法以内:GET、POST、PUT和DELETE,这正是对资源CRUD操作的实现。
REST的资源表述形式可以是XML、HTML、JSON,或者其他任意的形式,这取决于服务提供商和消费服务的用户。
但是REST不是万能的。操作无状态也会带来巨大的安全问题,如何授权和验证用户?如果要求每次请求都包含完整的身份和验证信息,又如何避免信息泄漏?复杂的功能挑战架构的易用性,这就需要在性能与功能间权衡,究竟该用REST还是SOAP。
WebHttpBinding
WebHttpBinding允许开发人员通过 HTTP 请求(这些请求使用“Plain
old XML”(POX) 样式消息,而不是使用基于 SOAP 的消息)来公开 Web 服务,可以很便利的实现REST。
与其他绑定不同的是:必须使用WebHttpBehavior对服务的终结点进行配置。还要求使用WebGetAttribute或WebInvokeAttribute属性将各个服务操作映射到 URI,同时定义调用和返回结果的消息格式。
服务契约
先定义服务契约。
这里提供两个方法,分别采用GET和POST方式访问。
我们可以看到,与普通WCF服务契约不同的是,需要额外用WebGet或者WebInvoke指定REST访问的方式。另外还要指定消息包装样式和消息格式,默认的消息请求和响应格式为XML,若选择JSON需要显式声明。
UriTemplate用来将方法映射到具体的Uri上,但如果不指定映射,将映射到默认的Uri。比如采用Get访问的GetUser方法,默认映射是:/GetUser?Name={Name}&Position={Position}。
IContract
服务端
这里最简单的实现GetUser和CreateUser两个方法的逻辑,关注点不在这里。
Service类
服务端的配置文件中只有一个特别处,必须使用WebHttpBehavior对服务的终结点进行配置。
Web.Config
客户端
为了强调REST的通用性,客户端不用WCF的形式调用服务,而是用另外两种通用的方式:
一是用C#编程直接HTTP访问,消息格式我们选XML;
二是用jquery实现GET和POST访问,消息格式我们选JSON。
先实现C#方式,我们封装一个Client类,实现HTTP的GET和POST方式。
Client类
下面是主函数,按顺序调用两个接口,并显示返回值。需要注意XML约定的命名空间:
Client
Main函数
结果:
接下来实现javascript方式。
这里采用jquery访问REST服务,为了javascript操作数据的便利,消息格式选择JSON,可以忽略数据契约的命名空间。不过需要服务契约做一点修改,显式指定请求或响应消息的格式,例如:
Html代码:
js
client代码
结果:
表述性状态转移(Representational State Transfer,REST),不是一种标准,而是一种软件架构风格。
基于REST的服务与基于SOAP的服务相比,性能、效率和易用性上都更高,而SOAP协议非常的复杂和不透明。REST受到越来越多的Web服务供应商欢迎。目前大部分供应商,如yahoo、google、Amazon等都提供REST风格的服务。
REST的主要原则是:
1.网络上的所有事物都可被抽象为资源;
2.每个资源都有一个唯一的资源标识符URI;
3.使用标准方法操作资源;
4.所有的操作都是无状态的;
5.通过缓存来提高性能。
REST是基于Http协议的,任何对资源的操作行为都是通过Http协议来实现。Http把对一个资源的操作限制在4个方法以内:GET、POST、PUT和DELETE,这正是对资源CRUD操作的实现。
REST的资源表述形式可以是XML、HTML、JSON,或者其他任意的形式,这取决于服务提供商和消费服务的用户。
但是REST不是万能的。操作无状态也会带来巨大的安全问题,如何授权和验证用户?如果要求每次请求都包含完整的身份和验证信息,又如何避免信息泄漏?复杂的功能挑战架构的易用性,这就需要在性能与功能间权衡,究竟该用REST还是SOAP。
WebHttpBinding
WebHttpBinding允许开发人员通过 HTTP 请求(这些请求使用“Plain
old XML”(POX) 样式消息,而不是使用基于 SOAP 的消息)来公开 Web 服务,可以很便利的实现REST。
与其他绑定不同的是:必须使用WebHttpBehavior对服务的终结点进行配置。还要求使用WebGetAttribute或WebInvokeAttribute属性将各个服务操作映射到 URI,同时定义调用和返回结果的消息格式。
服务契约
先定义服务契约。
这里提供两个方法,分别采用GET和POST方式访问。
我们可以看到,与普通WCF服务契约不同的是,需要额外用WebGet或者WebInvoke指定REST访问的方式。另外还要指定消息包装样式和消息格式,默认的消息请求和响应格式为XML,若选择JSON需要显式声明。
UriTemplate用来将方法映射到具体的Uri上,但如果不指定映射,将映射到默认的Uri。比如采用Get访问的GetUser方法,默认映射是:/GetUser?Name={Name}&Position={Position}。
IContract
1 namespace Rest.Contract 2 { 3 [DataContractFormat] 4 [ServiceContract] 5 public interface ITest 6 { 7 //[WebGet(UriTemplate = "/User/Get/{Name}/{Position}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)] 8 [WebGet(UriTemplate = "/User/Get/{Name}/{Position}", BodyStyle = WebMessageBodyStyle.Bare)] 9 [OperationContract] 10 List<User> GetUser(string Name, string Position); 11 12 //[WebInvoke(Method = "POST", UriTemplate = "/User/Create", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)] 13 [WebInvoke(Method = "POST", UriTemplate = "/User/Create", BodyStyle = WebMessageBodyStyle.Bare)] 14 [OperationContract] 15 Result CreateUser(User u); 16 } 17 18 [DataContract(Namespace = "http://rest-server/datacontract/user")] 19 public class User 20 { 21 [DataMember] 22 public long ID { get; set; } 23 24 [DataMember] 25 public string Name { get; set; } 26 27 [DataMember] 28 public int Sex { get; set; } 29 30 [DataMember] 31 public string Position { get; set; } 32 33 [DataMember] 34 public string Email { get; set; } 35 } 36 37 [DataContract(Namespace = "http://rest-server/datacontract/result")] 38 public class Result 39 { 40 [DataMember] 41 public string Value { get; set; } 42 } 43 44 } 45
服务端
这里最简单的实现GetUser和CreateUser两个方法的逻辑,关注点不在这里。
Service类
1 namespace Rest.Service 2 { 3 public class Test : ITest 4 { 5 /// <summary> 6 /// GET 7 /// </summary> 8 /// <param name="Name"></param> 9 /// <param name="Position"></param> 10 /// <returns></returns> 11 public List<User> GetUser(string Name, string Position) 12 { 13 List<User> userList = List.Where(u => u.Name == Name && u.Position == Position).ToList(); 14 15 return userList; 16 } 17 18 /// <summary> 19 /// POST 20 /// </summary> 21 /// <param name="u"></param> 22 /// <returns></returns> 23 public Result CreateUser(User u) 24 { 25 Result result = new Result(); 26 27 if (!List.Any(user => user.ID == u.ID)) 28 List.Add(u); 29 30 result.Value = u.ID.ToString(); 31 32 return result; 33 } 34 35 /// <summary> 36 /// 测试数据 37 /// </summary> 38 private static List<User> List 39 { 40 get 41 { 42 List<User> list = new List<User>{ 43 new User{ 44 ID = 19735, 45 Name = "wuhong", 46 Sex = 1, 47 Position = "engineer", 48 Email = "star_2345@qq.com" 49 } 50 }; 51 52 return list; 53 } 54 } 55 } 56 } 57
服务端的配置文件中只有一个特别处,必须使用WebHttpBehavior对服务的终结点进行配置。
Web.Config
1 <system.serviceModel> 2 <bindings> 3 <webHttpBinding> 4 <binding name="webBinding"> 5 </binding> 6 </webHttpBinding> 7 </bindings> 8 <services> 9 <service name="Rest.Service.Test" behaviorConfiguration="testServiceBehavior"> 10 <endpoint address="" behaviorConfiguration="webBehavior" 11 binding="webHttpBinding" bindingConfiguration="webBinding" contract="Wuhong.Rest.Contract.ITest"> 12 </endpoint> 13 </service> 14 </services> 15 <behaviors> 16 <endpointBehaviors> 17 <behavior name="webBehavior"> 18 <!--这里必须设置--> 19 <webHttp /> 20 </behavior> 21 </endpointBehaviors> 22 <serviceBehaviors> 23 <behavior name="testServiceBehavior"> 24 </behavior> 25 </serviceBehaviors> 26 </behaviors> 27 </system.serviceModel> 28
客户端
为了强调REST的通用性,客户端不用WCF的形式调用服务,而是用另外两种通用的方式:
一是用C#编程直接HTTP访问,消息格式我们选XML;
二是用jquery实现GET和POST访问,消息格式我们选JSON。
先实现C#方式,我们封装一个Client类,实现HTTP的GET和POST方式。
Client类
1 namespace Rest.Client 2 { 3 public class RestClient 4 { 5 /// <summary> 6 /// 构造函数 7 /// </summary> 8 /// <param name="baseUrl"></param> 9 public RestClient(string baseUri) 10 { 11 this.BaseUri = baseUri; 12 } 13 14 /// <summary> 15 /// 基地址 16 /// </summary> 17 private string BaseUri; 18 19 /// <summary> 20 /// Post调用 21 /// </summary> 22 /// <param name="data"></param> 23 /// <param name="uri"></param> 24 /// <returns></returns> 25 public string Post(string data, string uri) 26 { 27 //Web访问对象 28 string serviceUrl = string.Format("{0}/{1}", this.BaseUri, uri); 29 HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl); 30 31 //转成网络流 32 byte[] buf = UnicodeEncoding.UTF8.GetBytes(data); 33 34 //设置 35 myRequest.Method = "POST"; 36 myRequest.ContentLength = buf.Length; 37 myRequest.ContentType = "text/html"; 38 39 // 发送请求 40 Stream newStream = myRequest.GetRequestStream(); 41 newStream.Write(buf, 0, buf.Length); 42 newStream.Close(); 43 44 // 获得接口返回值 45 HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse(); 46 StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8); 47 48 string ReturnXml = HttpUtility.HtmlDecode(reader.ReadToEnd()); 49 50 reader.Close(); 51 myResponse.Close(); 52 53 return ReturnXml; 54 } 55 56 /// <summary> 57 /// Get调用 58 /// </summary> 59 /// <param name="uri"></param> 60 /// <returns></returns> 61 public string Get(string uri) 62 { 63 //Web访问对象 64 string serviceUrl = string.Format("{0}/{1}", this.BaseUri, uri); 65 HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl); 66 67 // 获得接口返回值 68 HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse(); 69 StreamReader reader = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8); 70 71 string ReturnXml = HttpUtility.UrlDecode(reader.ReadToEnd()); 72 73 reader.Close(); 74 myResponse.Close(); 75 76 return ReturnXml; 77 } 78 79 } 80 } 81
下面是主函数,按顺序调用两个接口,并显示返回值。需要注意XML约定的命名空间:
Client
Main函数
1 namespace Rest.Client 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 //初始化 8 RestClient client = new RestClient(ClientConfiguration.ServiceUrl); 9 10 //Get 11 string uriGet = string.Format("User/Get/{0}/{1}", "wuhong", "engineer"); 12 string retGet = client.Get(uriGet); 13 14 Console.WriteLine(retGet); 15 16 //Post 17 string uriPost = "User/Create"; 18 string data = "<User xmlns=\"http://rest-server/datacontract/user\"><ID>19735</ID><Name>wuhong</Name><Sex>1</Sex><Position>engineer</Position><Email>star_2345@qq.com</Email></User>"; 19 20 string retPost = client.Post(data, uriPost); 21 22 Console.WriteLine(retPost); 23 24 Console.ReadLine(); 25 } 26 } 27 28 } 29
结果:
接下来实现javascript方式。
这里采用jquery访问REST服务,为了javascript操作数据的便利,消息格式选择JSON,可以忽略数据契约的命名空间。不过需要服务契约做一点修改,显式指定请求或响应消息的格式,例如:
1 [WebInvoke(Method = "POST", UriTemplate = "User/Create", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
Html代码:
js
client代码
1 <html> 2 <head> 3 <script src="jquery-1.3.2.min.js" type="text/javascript"></script> 4 <script type="text/javascript"> 5 function HttpGet() { 6 $.get( http://doxt-wuhong/Wuhong.Rest.Web/TestService.svc/User/Get/wuhong/engineer , 7 function(data) { 8 $("#TextGet").val(data); 9 }); 10 } 11 function HttpPost() { 12 var str = "{ \"Email\": \"star_2345@qq.com\", \"ID\": 19735, \"Name\": \"wuhong\", \"Position\": \"engineer\", \"Sex\": 1 }"; 13 $.ajax({ 14 type: "POST", 15 contentType: "application/json", 16 url: http://doxt-wuhong/Wuhong.Rest.Web/TestService.svc/User/Create, 17 data: str, 18 success: function(data) { 19 $("#TextPost").val(data); 20 } 21 }); 22 } 23 </script> 24 <style type="text/css"> 25 #TextGet 26 { 27 width: 700px; 28 } 29 #TextPost 30 { 31 width: 700px; 32 } 33 </style> 34 </head> 35 <body> 36 <input id="ButtonGet" type="button" value="GET" onclick="HttpGet()" /> 37 <input id="TextGet" type="text" /> 38 <p/> 39 <input id="ButtonPost" type="button" value="POST" onclick="HttpPost()" /> 40 <input id="TextPost" type="text" /> 41 </body> 42 </html> 43
结果:
相关文章推荐
- WCF REST简单应用 编程初始化 help页面实现
- WCF Web API 轻松实现 REST
- WCF实现REST服务
- WCF学习之旅—实现REST服务(二十二)
- 写在WCF实现RESTFul Web Service之前(二):REST基本概念
- WCF REST Service: InstanceContextMode.PerCall 不管用,无法实现并发
- WCF实现REST服务
- 深入浅出WCF——通过WCF实现REST
- WCF学习之旅—实现支持REST客户端应用(二十四)
- 【REST】在 WCF RESTfull service 中实现自己的身份验证方式
- WCF Web API 轻松实现 REST
- WCF实现REST服务
- WCF Rest Service使用Unity实现依赖注入
- WCF学习之旅—实现支持REST服务端应用(二十三)
- WCFRestFull空框架,套上业务逻辑实现就可以用了
- [WCF REST] 通过ASP.NET Output Caching实现声明式缓存
- [WCF REST] 通过ASP.NET Output Caching实现声明式缓存
- WCF实现RESTFul Web Service(二):REST基本概念
- WCF实现REST服务
- 六步实现Rest风格的API