您的位置:首页 > 其它

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



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




结果:




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: