• 认识WCF


    WCF

    一、什么是WCF?

    1、Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口。它是.NET框架的一部分,由 .NET Framework[1] 3.0 开始引入,与 Windows Presentation Foundation及 Windows Workflow Foundation并行为新一代 Windows 操作系统以及 WinFX 的三个重大应用程序开发类库。

    2、很久以前,有一家小商店,靠卖些水果过日子。竞争是如此激烈,为了生存,他们不得不自己进货,把货堆到自己的房间内,如果顾客需要,他们有时还不得不给顾客送货,总而言之,他们将所有该干的活都干了,只为了能赚到点生活费,这就是艰辛的人生。

    一个web程序或者一个winform程序,简单模式的程序,我们通常都如那个水果店的老板一样,把所有的功能都集中到这个程序里,在简单的状况下,这很好。

    水果店生意越来越好,老板的资金慢慢雄厚了,他注意到了卖其他东西比卖水果更赚钱,比如说家电、服装。于是,老板一口气又开了几家店。生意规模越来越大,钱也越赚越多,老板心花怒放。然而好景不长,亚洲金融风暴来袭,利润率急剧下降。老板忧心忡忡,既然外部开源不太可能,那就看看内部能不能节流了。老板考察一番,注意到,为了销售,每个店都配置了一个仓库,每个店都配置了一帮送货的人马,这,是不是太浪费了。于是,老板将所有的仓库撤销,成立了一个总仓库,不管是水果,家店,服装,都可以存储到这个仓库。管理一个仓库的费用比管理N个仓库的费用显然是要少很多的。然后,每个店的送货人员都辞掉,另外成立一个运输公司,专门负责送货,不过水果还是家店还是服装,装到纸箱后,他们都是一个样。经过这么一折腾,成本一下就降了下来,而且还便于管理了,真是一举两得,老板又绽放了笑容。

    当程序涉及的范围越来越大时,也许就要考虑将服务分离出去。WCF是应对分布式开发的,就如水果店老板,生意大了后,他就是个分布式的了,这边一家水果店,那边一家服装店,他们之间有区别,卖的东西不同,也有共性,都是卖东西,不管是哪家店,他们都需要仓库,都需要送货。这时,你就可以单独成立公司,只提供这两种服务。如果写成程序,那么就如同你开发了一个运输的WCF,把这个服务放在服务器上,这样不管是谁,是Web程序也好,是Winform程序也好,只要接口对应,理解你的服务内容条款(服务契约),都可以要求你这个服务模块提供标准的服务。(来源于http://zhidao.baidu.com/question/148197639.html)

    3、WCF 是一个分布式应用的开发框架,属于特定的技术,或者平台。既不是标准也不是规范。
    Web Service:严格来说是行业标准,也就是Web Service 规范,也称作WS-*规范,既不是框架,也不是技术。

    4、Visual Studio 2008及以后的版本才有wcf的功能。

    二、怎么使用WCF?

    一、定义服务契约

    在这个实例中,我们创建一个简单的服务来管理员工的基本信息。至于实例程序的结构,我们依然采用熟悉的包含三个项目(Service.Interface、Service和Client)的解决方案。如下所示的是定义在Service.Interface中用于表示员工的Employee类的定义,它是一个数据契约。

       1: [DataContract(Namespace="http://www.artech.com/")]
       2: public class Employee
       3: {
       4:     [DataMember]
       5:     public string Id { get; set; }
       6:  
       7:     [DataMember]
       8:     public string Name { get; set; }
       9:  
      10:     [DataMember]
      11:     public string Department { get; set; }
      12:  
      13:     [DataMember]
      14:     public string Grade { get; set; }
      15:  
      16:     public override string ToString()
      17:     {
      18:         return string.Format("ID: {0,-5}姓名: {1, -5}级别: {2, -4} 部门: {3}",Id, Name, Grade, Department);
      19:     }
      20: }

    接下来我们定义了如下一个表示服务契约的接口IEmployeesService。和基于SOAP的服务契约定义不同,我们无需在相应的操作方法上面应用OperationContractAttribute特性,但是应用在接口/类上的ServiceContractAttribute特性仍是必需的。在这里替换OperationContractAttribute特性的分别是WebGetAttributeWebInvokeAttribute,它们均定义在System.ServiceModel.Web程序集中。

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

    契约接口IEmployeesService中定义了5个操作,分别用于实现针对员工数据的获取、添加、修改和删除。按照REST设计原则,我们将被操作的员工信息体现为某种网络资源,而操作类型最好与相应的HTTP方法相匹配。在操作方法中针对资源的操作类型与HTTP方法之间的匹配是通过应用在它们上面的WebGetAttribute和WebInvokeAttribute特性来体现。

    WebGetAttribute针对GET方法,而其他的HTTP方法则通过WebInvokeAttribute的Method属性来体现。在IEmployeesService中,两个用于获取员工信息GetAll和Get方法均应用了WebGetAttribute特性,而其他的Create、Update和Delete方法在应用了WebInvokeAttribute特性,并且其Method属性被分别设置为PUT、POST和DELETE。

    WebGetAttribute和WebInvokeAttribute和均具有相同的属性UriTemplate,该属性用于定义作为最终操作URI的模板。我们不仅可以通过UriTemplate属性为操作指定一个相对于终结点地址的静态路径,还可以通过占位符实现路径中的动态部分与参数之间的映射。

    同样以定义在契约接口IEmployeesService中的5个操作方法为例,如果终结点地址为http://127.0.0.1:3721/employees,由于用于返回所有员工列表的GetAll操作的UriTemplate被设置“All”,所以其地址为http://127.0.0.1:3721/employees。用于返回指定员工ID的Get操作的UriTemplate被设置成“{id}”,意味着我们直接在表示请求地址的URI中指定员工的ID,而它会自动映射为该操作方法的参数id。用于删除某个指定员工的Delete操作具有相同的UriTemplate设置,而用于创建添加新员工和修改现有员工信息的Create和Update操作,由于作为参数的Employee对象具有ID属性,所以直接采用终结点地址。

    二、创建/寄宿服务

    在控制台程序Service中我们定义了如下一个实现了契约接口IEmployeesService的服务类型EmployeesService。简单 起见,我们直接通过一个静态字段employees表示存储的员工列表,该静态字段在初始化的工作中被添加了两个ID分别为001和002的Employee对象。针对员工信息的获取、添加、修改和删除的操作均在此列表中进行。

       1: public class EmployeesService : IEmployees
       2: {
       3:     private static IList<Employee> employees = new List<Employee>
       4:     {
       5:         new Employee{ Id = "001", Name="张三", Department="开发部", Grade = "G7"},    
       6:         new Employee{ Id = "002", Name="李四", Department="人事部", Grade = "G6"}
       7:     };
       8:     public Employee Get(string id)
       9:     {
      10:         Employee employee = employees.FirstOrDefault(e => e.Id == id);
      11:         if (null == employee)
      12:         {
      13:             WebOperationContext.Current.OutgoingResponse.StatusCode = 
      14:             HttpStatusCode.NotFound;
      15:         }
      16:         return employee;
      17:     }
      18:  
      19:     public void Create(Employee employee)
      20:     {
      21:         employees.Add(employee);
      22:     }
      23:  
      24:     public void Update(Employee employee)
      25:     {
      26:         this.Delete(employee.Id);
      27:         employees.Add(employee);
      28:     }
      29:  
      30:     public void Delete(string id)
      31:     {
      32:         Employee employee = this.Get(id);
      33:         if (null != employee)
      34:         {
      35:             employees.Remove(employee);
      36:         }
      37:     }
      38:  
      39:     public IEnumerable<Employee> GetAll()
      40:     {
      41:         return employees;
      42:     }
      43: }

    值得一提的是,不论是用于获取某个指定ID的员工信息的Get方法,还是用于修改和删除员工记录的Update和Delete方法,当指定ID的员工不存在时都通过WebOperationContext表示当前Web操作上下文的对象将回复状态设置为NotFound(即404 Not Found),这体现了我们的服务是基于Web的。

    接下来我们通过自我寄宿的方式对上面定义的EmployeesService服务进行寄宿,下面是相应的配置。我们为寄宿的服务添加了唯一一个终结点,并简单地指定了其ABC三要素。和我们之前配置的终结点不同的是,在这里我们采用的绑定类型为WebHttpBinding。

       1: <configuration>
       2:     <system.serviceModel>
       3:     <services>
       4:         <service name="Artech.WcfServices.Service.EmployeesService">
       5:         <endpoint address="http://127.0.0.1:3721/employees" 
       6:                   binding="webHttpBinding"
       7:                   contract="Artech.WcfServices.Service.Interface.IEmployees"/>
       8:         </service>
       9:     </services>
      10:     </system.serviceModel>
      11: </configuration>

    最终我们通过如下的程序进行服务的寄宿。之前我们总是使用基于服务类型创建的ServiceHost进行服务寄宿,在这里我们使用的是ServiceHost它的子类WebServiceHost

       1: using (WebServiceHost host = new WebServiceHost(typeof(EmployeesService)))
       2: {
       3:     host.Open();
       4:     Console.Read();
       5: }
    
    

    三、进行服务调用

    由于我们寄宿的服务完全是基于Web的,所以和普通的Web站点没有本质的区别。由于EmployeesService服务的GetAll和Get操作支持HTTP-GET请求,所以我们完全可以在浏览器中针对操作的地址发起请求,而返回的数据可以直接显示在浏览器上。下图所示的是通过浏览器调用GetAll操作(http://127.0.0.1:3721/employees/all)得到的结果,我们可以看到所有员工的列表以XML的形式返回。

    image

    我们也可以通过浏览器调用Get操作并直接通过在地址中指定员工的ID(http://127.0.0.1:3721/employees/001)并得到以XML表示的基于相应员工的信息。下图所示XML正式ID为001的Employee对象序列化后的结果。如果在请求地址中指定一个不存在的ID(比如http://127.0.0.1:3721/employees/003),由于Get方法中指定了回复状态为NotFound,我们会得到类似于访问资源不存在的错误信息,就像访问一个不存在的Web页面一样。

    image

    上面我们演示了通过浏览器以HTTP-GET方式请求操作地址的方式从而直接将返回结果呈现出来,现在我们来演示如何使用通过ChannelFactory<TChannel>创建的服务代理进行服务调用。我们首先在作为客户端应用程序的Client项目中创建一个App.config,并定义如下的配置。

       1: <configuration>
       2:   <system.serviceModel>
       3:     <behaviors>
       4:       <endpointBehaviors>
       5:         <behavior name="webBehavior">
       6:           <webHttp />
       7:         </behavior>
       8:       </endpointBehaviors>      
       9:     </behaviors>
      10:     <client>
      11:       <endpoint name="employeeService"
      12:         address="http://127.0.0.1:3721/employees" 
      13:         behaviorConfiguration="webBehavior"
      14:         binding="webHttpBinding" 
      15:         contract="Artech.WcfServices.Service.Interface.IEmployees"/>
      16:     </client>
      17:   </system.serviceModel>
      18: </configuration>

    如上面的配置片断所示,我们定义了一个与服务端相匹配的客户端终结点,该终结点上应用了一个WebHttpBehavior终结点行为。WebHttpBehavior可以说是整个Web HTTP编程模型的核心,绝大部分针对Web的支持都是通过该行为实现的。实际上服务端终结点通过WebServiceHost应用了这个终结点行为。

       1: using(ChannelFactory<IEmployees> channelFactory = new ChannelFactory<IEmployees>("employeeService"))
       2: {
       3:     IEmployees proxy = channelFactory.CreateChannel();
       4:  
       5:     Console.WriteLine("所有员工列表:");
       6:     Array.ForEach<Employee>(proxy.GetAll().ToArray(),employee=>Console.WriteLine(employee));
       7:  
       8:     Console.WriteLine("
    添加一个新员工(003):");
       9:     proxy.Create(new Employee
      10:     {
      11:         Id              = "003",
      12:         Name            = "王五",
      13:         Grade           = "G9",
      14:         Department      = "行政部"
      15:     });
      16:     Array.ForEach<Employee>(proxy.GetAll().ToArray(),employee => Console.WriteLine(employee));
      17:  
      18:     Console.WriteLine("
    修改员工(003)信息:");
      19:     proxy.Update(new Employee
      20:     {
      21:         Id              = "003",
      22:         Name            = "王五",
      23:         Grade           = "G11",
      24:         Department      = "销售部"
      25:     });
      26:     Array.ForEach<Employee>(proxy.GetAll().ToArray(), employee => Console.WriteLine(employee));
      27:     Console.WriteLine("
    删除员工(003)信息:");
      28:  
      29:     proxy.Delete("003");
      30:     Array.ForEach<Employee>(proxy.GetAll().ToArray(), employee => Console.WriteLine(employee));        
      31: }

    服务调用程序如上所示,我们模拟了员工的添加、修改和删除。程序之后会在客户端控制台产生如下的输出。

    所有员工列表:

       1: 所有员工列表:
       2: ID: 001  姓名: 张三   级别: G7   部门: 开发部
       3: ID: 002  姓名: 李四   级别: G6   部门: 人事部
       4:  
       5: 添加一个新员工(003):
       6: ID: 001  姓名: 张三   级别: G7   部门: 开发部
       7: ID: 002  姓名: 李四   级别: G6   部门: 人事部
       8: ID: 003  姓名: 王五   级别: G9   部门: 行政部
       9:  
      10: 修改员工(003)信息:
      11: ID: 001  姓名: 张三   级别: G7   部门: 开发部
      12: ID: 002  姓名: 李四   级别: G6   部门: 人事部
      13: ID: 003  姓名: 王五   级别: G11  部门: 销售部
      14:  
      15: 删除员工(003)信息:
      16: ID: 001  姓名: 张三   级别: G7   部门: 开发部
      17: ID: 002  姓名: 李四   级别: G6   部门: 人事部

    从编程角度来看,我们采用与SOAP服务完全一样的服务调用方式,那么如何反映出服务调用基于Web的本质呢?首先,之前我们能够通过浏览器访问GetAll和Get两个操作可以证明这两个服务操作是基于HTTP-GET的,返回的数据直接以单纯的XML返回,并没有封装成SOAP。为了证明Create、Update和Delete也是完全基于Web的,我们可以通过Fiddler来分析HTTP请求的内容。

    如下所示的三段XML片断分别对应着针对上述三个服务操作调用的HTTP请求消息,从这我们可以看出它们就是单纯的针对PUT、POST和DELETE方法的HTTP请求,而传输给服务端的数据直接作为消息的主体,并没有封装成SOAP消息。

       1: Create:
       2: PUT http://jinnan-pc:3721/employees/ HTTP/1.1
       3: Content-Type: application/xml; charset=utf-8
       4: Host: jinnan-pc:3721
       5: Content-Length: 187
       6: Expect: 100-continue
       7: Accept-Encoding: gzip, deflate
       8:  
       9: <Employee xmlns="http://www.artech.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Department>销售部</Department><Grade>G11</Grade><Id>003</Id><Name>王五</Name></Employee>
      10:  
      11: Update:
      12: POST http://jinnan-pc:3721/employees/ HTTP/1.1
      13: Content-Type: application/xml; charset=utf-8
      14: Host: jinnan-pc:3721
      15: Content-Length: 186
      16: Expect: 100-continue
      17: Accept-Encoding: gzip, deflate
      18:  
      19: <Employee xmlns="http://www.artech.com/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><Department>行政部</Department><Grade>G9</Grade><Id>003</Id><Name>王五</Name></Employee>
      20:  
      21: Delete:
      22: DELETE http://jinnan-pc:3721/employees/003 HTTP/1.1
      23: Content-Type: application/xml; charset=utf-8
      24: Host: jinnan-pc:3721
      25: Content-Length: 80
      26: Expect: 100-continue
      27: Accept-Encoding: gzip, deflate
    (来源于http://www.cnblogs.com/artech/archive/2012/02/04/wcf-rest-sample.html)
  • 相关阅读:
    PAT B1027 打印沙漏 (20 分)
    PAT B1025 反转链表 (25 分)
    PAT B1022 D进制的A+B (20 分)
    PAT B1018 锤子剪刀布 (20 分)
    PAT B1017 A除以B (20 分)
    PAT B1015 德才论 (25 分)
    PAT B1013 数素数 (20 分)
    PAT B1010 一元多项式求导 (25 分)
    HDU 1405 The Last Practice
    HDU 1165 Eddy's research II
  • 原文地址:https://www.cnblogs.com/aweifly/p/3459377.html
Copyright © 2020-2023  润新知