• 快速入门系列--WCF--03RESTFUL服务与示例


    之前介绍了基于SOAP的Web服务,接下来将介绍基于REST的轻量级的Web服务。

    REST(Representational State Transfer)与技术无关,代表一种软件架构风格,可以成为ROA面向资源的架构,之前Web服务的架构风格主要是SOAP和XML-RPC。REST从资源的角度来观察整个网络,分布在各处的资源有URI来标识,而客户端通过URI来获取资源的表征,获得这些表征使得应用程序转变了状态。作者是这样解释的,"设计良好的网络应用表现为一系列的网页,这些网页可以看做是虚拟的状态机,用户选择这些链接导致下一网页传输给客户端展现给使用的人,而这正代表了状态的改变"。一般来说,REST是建立在HTTP、URI、XML、JSON等概念的基础之上的,其特点是:一切数据都是资源,所有的资源均可被你唯一标识,采用统一而简单的接口,基于表征的通信,无状态服务调用。

    在Web Http编程模型中,包含的主要的类型有:WebHttpBinding, WebHttpBehavior, WebGetAttribute/WebInvokeAttribute和WebServiceHost等。其中值得一提的是WebHttpSecurityMode:None表示请求未使用任何安全性;Transport表示请求使用传输级安全;TransportCredentialOnly表示仅提供基于HTTP客户端身份验证。这儿可以看到由于WebHttpBinding不是基于SOAP协议,因此WS-*协议簇均无法使用。在消息内容上,可以通过设置相关属性进行,例如RequestFormat=WebMessageFormat.Xml,ResponseFormat=WebMessageFormat.Json,BodyStyle=WebMessgaeBodyStyle.Bare。

    对于SOAP协议来说,操作的选择是通过<Action>来决定的,而在这儿时通过UriTemplate属性表示的一个URI模板来决定的,常见的路由例子如接下来的,/filename.{ext}/, /{filename}.jpg/, /{filename}.{ext}/, /{a}.{b}someLiteral{c}{d}/等多种通配符方式,和ASP.NET一样由一个通过注册一个静态的路由表,之后通过路由表来路由请求。

    接下来,介绍几个比较有趣的概念,分别是输出缓存、条件获取和更新。前者由于涉及到ASP.NET的CacheProfile的使用,需要使用ASP.NET的兼容模式,不太推荐,可以考虑使用其他的缓存方式进行缓存,比如Redis。后者涉及一个http协议中的请求头ETag,通过对其的判断来决定内容是否已经被更新,比较有实际意思,例子的代码如下。

    Interface

     1 namespace Sory.CoreFramework.Interface
     2 {
     3 [ServiceContract(Namespace = "http://www.sory.com")]
     4 public interface IEmployees
     5 {
     6 [WebGet(UriTemplate="all")]
     7 IEnumerable<Employee> GetAll();
     8  
     9 [WebGet(UriTemplate = "{id}")]
    10 Employee Get (String id);
    11 
    12 [WebInvoke(UriTemplate = "/", Method = "POST")]
    13 void Create(Employee employee);
    14 
    15 [WebInvoke(UriTemplate = "/", Method = "PUT")]
    16 void Update(Employee employee);
    17 
    18 [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
    19 void Delete(string id);
    20 }
    21 }
    View Code

    Service的实现

     1 public class EmployeesService : IEmployees
     2 {
     3 private static IList<Employee> _employees = new List<Employee>
     4 {
     5 new Employee {Id="001", Name="xiongda", Department="xiaowei", Grade="T13"},
     6 new Employee {Id="002", Name="xionger", Department="xiaowei", Grade="T15"}
     7 };
     8 
     9 public IEnumerable<Interface.Entities.Employee> GetAll()
    10 {
    11 var hashCode = _employees.GetHashCode();
    12 WebOperationContext.Current.IncomingRequest.CheckConditionalRetrieve(hashCode);
    13 WebOperationContext.Current.OutgoingResponse.SetETag(hashCode);
    14 return _employees;
    15 }
    16 
    17 public Interface.Entities.Employee Get(string id)
    18 {
    19 var employee = _employees.FirstOrDefault(e => e.Id == id);
    20 if (null == employee)
    21 {
    22 //WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
    23 throw new WebFaultException(HttpStatusCode.NotFound);
    24 }
    25 
    26 WebOperationContext.Current.OutgoingResponse.SetETag(employee.GetHashCode());
    27 return employee;
    28 }
    29 
    30 public void Create(Interface.Entities.Employee employee)
    31 {
    32 _employees.Add(employee);
    33 }
    34 
    35 public void Update(Interface.Entities.Employee employee)
    36 {
    37 var existing = _employees.FirstOrDefault(e => e.Id == employee.Id);
    38 if (null == existing)
    39 {
    40 throw new WebFaultException(HttpStatusCode.NotFound);
    41 }
    42 
    43 existing.Name += Guid.NewGuid().ToString();
    44 WebOperationContext.Current.IncomingRequest.CheckConditionalUpdate(existing.GetHashCode());
    45 
    46 Delete(employee.Id);
    47 _employees.Add(employee);
    48 
    49 WebOperationContext.Current.OutgoingResponse.SetETag(employee.GetHashCode());
    50 }
    51  
    52 public void Delete(string id)
    53 {
    54 var employee = this.Get(id);
    55 if (null != employee)
    56 {
    57 _employees.Remove(employee);
    58 }
    59 }
    60 }
    View Code

    Server

     1 public static class ServiceHost
     2 {
     3 public static void Start()
     4 {
     5 using (WebServiceHost host = new WebServiceHost(typeof(EmployeesService)))
     6 {
     7 host.Open();
     8 Console.Read();
     9 }
    10 }
    11 }
    12 配置文件
    13 <system.serviceModel>
    14 <services>
    15 <service name ="Sory.CoreFramework.Service.EmployeesService">
    16 <endpoint address="http://127.0.0.1:3721/employees" binding="webHttpBinding"
    17 contract="Sory.CoreFramework.Interface.IEmployees"/>
    18 </service>
    19 </services>
    20 </system.serviceModel>
    View Code

    Client

     1 public class CheckDemo
     2 {
     3 public static void Test()
     4 {
     5 using (ChannelFactory<IEmployees> channelFactory = new ChannelFactory<IEmployees>("employeeService"))
     6 {
     7 var proxy = channelFactory.CreateChannel();
     8 Array.ForEach<Employee>(proxy.GetAll().ToArray(), emp => Console.WriteLine(emp));
     9 }
    10 }
    11 }
    12 配置文件
    13 <system.serviceModel>
    14 <behaviors>
    15 <endpointBehaviors>
    16 <behavior name="webBehavior">
    17 <webHttp/>
    18 </behavior>
    19 </endpointBehaviors>
    20 </behaviors>
    21 <client>
    22 <endpoint name="employeeService" address="http://127.0.0.1:3721/employees" behaviorConfiguration="webBehavior"
    23 binding="webHttpBinding" contract="Sory.CoreFramework.Interface.IEmployees">
    24 </endpoint>
    25 </client>
    26 </system.serviceModel>
    View Code

    参考资料:

    [1]蒋金楠. WCF全面解析[M]. 上海:电子工业出版社, 2012.

  • 相关阅读:
    推荐一些socket工具,TCP、UDP调试、抓包工具
    IE DIV背景透明,点击事件不响应解决方案
    亚马逊的高管和员工们经常阅读的书目
    今日技术文摘 (2013
    Discuz! X3安装第三方主题出现:对不起,您安装的不是正版应用..的解决方法
    chrome浏览器直接编辑源码功能的开通办法
    书单
    editplus教程
    如何让windows更高效?
    conEmu的使用笔记
  • 原文地址:https://www.cnblogs.com/xiong2ge/p/WCF_Base03.html
Copyright © 2020-2023  润新知