WCF实现REST服务

此生再无相见时 提交于 2019-12-30 22:07:46

 

  • REST
  •       表述性状态转移(Representational State Transfer,REST),不是一种标准,而是一种软件架构风格。

          基于REST的服务与基于SOAP的服务相比,性能、效率和易用性上都更高,而SOAP协议非常的复杂和不透明。REST受到越来越多的Web服务供应商欢迎。目前大部分供应商,如yahoogoogleAmazon等都提供REST风格的服务。

     

          REST的主要原则是:

     1.网络上的所有事物都可被抽象为资源;

     2.每个资源都有一个唯一的资源标识符URI;

     3.使用标准方法操作资源;

     4.所有的操作都是无状态的;

     5.通过缓存来提高性能。

      

        REST是基于Http协议的,任何对资源的操作行为都是通过Http协议来实现。Http把对一个资源的操作限制在4个方法以内:GET、POST、PUTDELETE,这正是对资源CRUD操作的实现。

        REST的资源表述形式可以是XMLHTMLJSON,或者其他任意的形式,这取决于服务提供商和消费服务的用户。

         

        但是REST不是万能的。操作无状态也会带来巨大的安全问题,如何授权和验证用户?如果要求每次请求都包含完整的身份和验证信息,又如何避免信息泄漏?复杂的功能挑战架构的易用性,这就需要在性能与功能间权衡,究竟该用REST还是SOAP。

      

  • WebHttpBinding
  •       WebHttpBinding允许开发人员通过 HTTP 请求(这些请求使用“Plain old XML”(POX) 样式消息,而不是使用基于 SOAP 的消息)来公开 Web 服务,可以很便利的实现REST

          与其他绑定不同的是:必须使用WebHttpBehavior对服务的终结点进行配置。还要求使用WebGetAttributeWebInvokeAttribute属性将各个服务操作映射到 URI,同时定义调用和返回结果的消息格式。

           

  • 服务契约
  •       先定义服务契约。

          这里提供两个方法,分别采用GETPOST方式访问。

          我们可以看到,与普通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 User20     {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 Result39     {40         [DataMember]41         public string Value { get; set; }42     }43 44 }45  

         

  • 服务端
  •       这里最简单的实现GetUserCreateUser两个方法的逻辑,关注点不在这里。

     

    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         /// POST20         /// </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> List39         {40             get41             {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实现GETPOST访问,消息格式我们选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             //Get11              string uriGet = string.Format("User/Get/{0}/{1}", "wuhong", "engineer");12             string retGet = client.Get(uriGet);13 14             Console.WriteLine(retGet);15 16             //Post17              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             #TextGet26             {27                 width: 700px;28             }29             #TextPost30             {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  

     

       结果:

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!