zoukankan      html  css  js  c++  java
  • WCF实现REST服务

    REST

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

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

        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

    namespace Rest.Contract
    {
     [DataContractFormat]
     [ServiceContract]
     public interface ITest
     {
     //[WebGet(UriTemplate = "/User/Get/{Name}/{Position}", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
       [WebGet(UriTemplate = "/User/Get/{Name}/{Position}", BodyStyle = WebMessageBodyStyle.Bare)]
     [OperationContract]
     List<User> GetUser(string Name, string Position);
     
    //[WebInvoke(Method = "POST", UriTemplate = "/User/Create", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
       [WebInvoke(Method = "POST", UriTemplate = "/User/Create", BodyStyle = WebMessageBodyStyle.Bare)]
      [OperationContract]
     Result CreateUser(User u);
     }
     
    [DataContract(Namespace "http://rest-server/datacontract/user")]
     public class User
     {
     [DataMember]
     public long ID { getset; }
     
     [DataMember] 
     public string Name { getset; }
     
     [DataMember]
     public int Sex { getset; }
     
     [DataMember]
     public string Position { getset; }
     
     [DataMember]
     public string Email { getset; }
     }
     
     [DataContract(Namespace "http://rest-server/datacontract/result")]
     public class Result
     {
     [DataMember]
     public string Value { getset; }
     }
     
     }

    服务端

          这里最简单的实现GetUser和CreateUser两个方法的逻辑,关注点不在这里。

    Service类

    namespace Rest.Service
    {
    public class Test : ITest
    {
    /// <summary>
    /// GET
    /// </summary>
     /// <param name="Name"></param>
    /// <param name="Position"></param>
    /// <returns></returns>
      public List<User> GetUser(string Name, string Position)
    {
    List<User> userList = List.Where(u => u.Name == Name && u.Position == Position).ToList();
    
    return userList;
    }
    
    /// <summary>
    /// POST
     /// </summary>
    /// <param name="u"></param>
     /// <returns></returns>
       public Result CreateUser(User u)
     {
     Result result new Result();
     
     if (!List.Any(user => user.ID == u.ID))
     List.Add(u);
     
     result.Value = u.ID.ToString();
    
     return result;
     }
     
     /// <summary>
     /// 测试数据
     /// </summary>
       private static List<User> List
     {
     get
    {
     List<User> list = new List<User>{
     new User{
     ID 19735,
     Name "wuhong",
     Sex 1,
     Position "engineer",
     Email "star_2345@qq.com"
     }
     };
     
     return list;
     }
     }
     }
     }

    服务端的配置文件中只有一个特别处,必须使用WebHttpBehavior对服务的终结点进行配置。

    Web.Config

    <system.serviceModel>
    <bindings>
    <webHttpBinding>
    <binding name="webBinding">
    </binding>
    </webHttpBinding>
    </bindings>
     <services>
    <service name="Rest.Service.Test" behaviorConfiguration="testServiceBehavior">
     <endpoint address="" behaviorConfiguration="webBehavior" 
     binding="webHttpBinding" bindingConfiguration="webBinding" contract="Wuhong.Rest.Contract.ITest">
    </endpoint>
    </service>
    </services>
    <behaviors>
    <endpointBehaviors>
    <behavior name="webBehavior">
    <!--这里必须设置-->
    <webHttp />
     </behavior>
    </endpointBehaviors>
     <serviceBehaviors>
     <behavior name="testServiceBehavior">
     </behavior>
     </serviceBehaviors>
     </behaviors>
     </system.serviceModel>

    客户端 
    为了强调REST的通用性,客户端不用WCF的形式调用服务,而是用另外两种通用的方式: 
    一是用C#编程直接HTTP访问,消息格式我们选XML;

    二是用jquery实现GET和POST访问,消息格式我们选JSON。
    先实现C#方式,我们封装一个Client类,实现HTTP的GET和POST方式。

    namespace Rest.Client
     {
     public class RestClient
     {
     /// <summary>
     /// 构造函数
     /// </summary>
     /// <param name="baseUrl"></param>
       public RestClient(string baseUri)
    {
    his.BaseUri = baseUri;
    }
    
    /// <summary>
    /// 基地址
    /// </summary>
     private string BaseUri;
    
    /// <summary>
    /// Post调用
    /// </summary>
    /// <param name="data"></param>
    /// <param name="uri"></param>
    /// <returns></returns>
      public string Post(string data, string uri)
    {
    //Web访问对象
       string serviceUrl = string.Format("{0}/{1}"this.BaseUri, uri);
    HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
     
     //转成网络流
       byte[] buf = UnicodeEncoding.UTF8.GetBytes(data);
     
     //设置
       myRequest.Method = "POST";
     myRequest.ContentLength = buf.Length;
     myRequest.ContentType "text/html";
     
     // 发送请求
       Stream newStream = myRequest.GetRequestStream();
     newStream.Write(buf, 0, buf.Length);
     newStream.Close();
     
     // 获得接口返回值
       HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
     StreamReader reader new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
     
     string ReturnXml = HttpUtility.HtmlDecode(reader.ReadToEnd());
     
     reader.Close();
     myResponse.Close();
     
     return ReturnXml;
     }
     
     /// <summary>
     /// Get调用
     /// </summary>
     /// <param name="uri"></param>
     /// <returns></returns>
       public string Get(string uri)
     {
     //Web访问对象
       string serviceUrl = string.Format("{0}/{1}"this.BaseUri, uri);
     HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
     
     // 获得接口返回值
       HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
     StreamReader reader new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
    
     string ReturnXml = HttpUtility.UrlDecode(reader.ReadToEnd());
     
    reader.Close();
     myResponse.Close();
    
     return ReturnXml;
     }
     
     }
     }
    Client类

    下面是主函数,按顺序调用两个接口,并显示返回值。需要注意XML约定的命名空间:

    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  
    Client Main函数

    接下来实现javascript方式。

          这里采jquery访问REST服务,为了javascript操作数据的便利,消息格式选择JSON,可以忽略数据契约的命名空间。不过需要服务契约做一点修改,显式指定请求或响应消息的格式,例如: 

    1 [WebInvoke(Method = "POST", UriTemplate = "User/Create", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]

       

          Html代码: 

    <html>
    <head>
    <script src="jquery-1.3.2.min.js" type="text/javascript"></script>
    <script type="text/javascript">
    function HttpGet() {
    $.get( http://doxt-wuhong/Wuhong.Rest.Web/TestService.svc/User/Get/wuhong/engineer ,
     function(data) {
     $("#TextGet").val(data);
     });
    }
     function HttpPost() {
     var str = "{ "Email": "star_2345@qq.com", "ID": 19735, "Name": "wuhong", "Position": "engineer", "Sex": 1 }";
     $.ajax({
     type: "POST",
    contentType: "application/json",
    url:  http://doxt-wuhong/Wuhong.Rest.Web/TestService.svc/User/Create,
    data: str,
    success: function(data) {
    $("#TextPost").val(data);
    }
    });
    }
    </script>
    <style type="text/css">
    #TextGet
    {
    width: 700px;
    }
    #TextPost
    {
    width: 700px;
    }
    </style>
    </head>
    <body>
    <input id="ButtonGet" type="button" value="GET" onclick="HttpGet()" />
    <input id="TextGet" type="text" />
    <p/> 
    <input id="ButtonPost" type="button" value="POST" onclick="HttpPost()" />
     <input id="TextPost" type="text" />
    </body>
      </html>
    Html代码
  • 相关阅读:
    HDU 5302(Connect the Graph- 构造)
    Redis 集群
    HDFS集中式缓存管理(Centralized Cache Management)
    JavaScript语言基础12
    【IOS】启动画面
    小贝_mysql优化学习
    hdu2099 整除的位数(暴力)
    Receiver type ‘X’ for instance message is a forward declaration
    动态游标(比如表名作为參数)以及动态SQL分析
    mongodb与SQL相应关系表
  • 原文地址:https://www.cnblogs.com/fer-team/p/7919233.html
Copyright © 2011-2022 走看看