博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WCF实现REST服务
阅读量:6691 次
发布时间:2019-06-25

本文共 8606 字,大约阅读时间需要 28 分钟。

 

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}。

 

 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  }

 

服务端

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

 

 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  }

 

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

 

 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
>

 

客户端

     为了强调REST的通用性,客户端不用WCF的形式调用服务,而是用另外两种通用的方式:

     一是用C#编程直接HTTP访问,消息格式我们选XML

       二是用jquery实现GETPOST访问,消息格式我们选JSON。

 

       先实现C#方式,我们封装一个Client类,实现HTTP的GET和POST方式

 

 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  }

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

 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  }

接下来实现javascript方式。

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

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

Html代码:

 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
>

  结果:

转载于:https://www.cnblogs.com/root7/archive/2012/02/28/2371912.html

你可能感兴趣的文章
15.汉字的繁简转换 C#
查看>>
Confluence 6 如何考虑设置一个空间的主页
查看>>
hadoop命令执行hbase应用jar包时的环境变量加载问题
查看>>
AndroidTV 网络机顶盒 Wi-Fi设置
查看>>
CentOS 6.8 编译安装MySQL5.5.32 (二 多实例)
查看>>
bat等大公司常考java多线程面试题
查看>>
为centos 5.5 x86设置双网卡bonding
查看>>
在 Xcode 里编译运行 Python 代码
查看>>
什么是License
查看>>
Android 无闪烁启动画面程序源码
查看>>
用 PHP 读取文件的正确方法
查看>>
Authentication and Integration 第三篇:Oracle LDAP介绍
查看>>
我的友情链接
查看>>
[精讲-5]BitLocker
查看>>
gitlab bitnami 安装
查看>>
awk常用注意事项--awk如何引用外部变量
查看>>
mysql5.7制作rpm包spec文件
查看>>
mysq基础笔记(sql语句)
查看>>
XenMobile学习文章总结
查看>>
Android开发者的混淆使用手册
查看>>