【开篇】

  一直使用.net开发一些基本的web应用,现在需要往移动开发上扩展,自然需要学习微软重金打造的SOA框架WCF,所以打算将自己的学习笔记做成一个系列,方便日后查看,另外方便接受大家的意见、建议,以助于自身能力提升。

【资源】

  在开始学习之前,先备齐货:

 【SOA特点】

  • 服务是自治的:服务可以独立地进行部署及实施版本策略和安全策略;
  • 依赖于开放的标准:便于统一
  • 支持跨平台
  • 鼓励创建可组合的服务:可以用原子服务组合、编排成新的聚合服务;//这是否同前面的“自治”相矛盾?
  • 鼓励服务复用
  • 强调松耦合:通过“契约”实现客户端对服务的调用,契约匹配即可,不论服务是否改动

 【WCF特点】

  WCF是Windows平台下各种分布式技术的整合,包含所有以前的分布式通信技术,提供一套统一的API

     //下面这段摘自MSDN——begin

  • 服务导向

    松耦合关系意味着只要符合基本协定,则在任何平台上创建的任何客户端均可连接到所有服务。

  • 互操作性

    互操作性和集成

  • 多种消息模式

    协定

  • 服务元数据

    元数据.

  • 数据协定

    使用数据协定

  • 安全性

    Windows Communication Foundation 安全性.

  • 多种传输和编码方式

    Windows Communication Foundation 中的传输

  • 可靠的排队消息

    队列和可靠会话

  • 持久性消息

    工作流服务.

  • 事务

    事务

  • AJAX 和 REST 支持

    WCF 此外可以进行扩展以支持特定的XML格式,如 ATOM(流行的 RSS 标准),甚至非 XML 格式,例如,JavaScript 对象表示法 (JSON)。

  • 可扩展性

    扩展 WCF

  //上面这段摘自MSDN——end

   看了上面的介绍,给人的感觉就是WCF和牛X,学会它,就能掌握.net复合型应用的精髓。包含的多,自然就难了,咱先从简单的开始。

【入门实例】

  可以参考msdn的入门示例:http://msdn.microsoft.com/zh-cn/library/ms751519.aspx

      我这参考《WCF全面解析》中的第一个示例:

  1. 步骤一:构建项目(解决方案)

      WCF系列001——WCF概述

  如上图,新建一个解决方案,在其中新建4个项目

  1)Service.Interface:定义服务契约(Service Contract),添加引用:System.ServiceModel。项目类型:C#类库

  2)Service:定义服务类,实现Service.Interface中的契约接口,添加引用:Service.Interface项目。项目类型:C#类库

  3)Hosting:服务器应用程序,添加引用:System.ServiceModel、Service.Interface项目、Service项目。项目类型:C#控制台,解决方案启动项目

  4)Client:客户端应用程序,添加引用:System.ServiceModel。项目类型:C#控制台

  2.步骤二:创建服务契约Service.Interface(服务接口)

  服务接口自然是服务的抽象,在WCF中,将服务接口称为“契约”,建立“契约”的方式和定义接口的一样:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.ServiceModel;
 7 
 8 namespace WCFBegin.Service.Interface
 9 {
10     [ServiceContract(Name="CalculatorService",
11                      Namespace="http://www.chutianshu.com")]
12     public interface ICalculator
13     {
14         [OperationContract]
15         double Add(double x, double y);
16         [OperationContract]
17         double Subtract(double x, double y);
18         [OperationContract]
19         double Multiply(double x, double y);
20         [OperationContract]
21         double Divide(double x, double y);
22     }
23 }

  3.步骤三:创建服务

  实现契约(服务接口),和普通类实现接口方法一样

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WCFBegin.Service.Interface;

namespace WCFBegin.Service
{
    public class CalculatorService:ICalculator
    {
        #region ICalculator 成员

        double ICalculator.Add(double x, double y)
        {
            return x + y;
        }

        double ICalculator.Subtract(double x, double y)
        {
            return x - y;
        }

        double ICalculator.Multiply(double x, double y)
        {
            return x * y;
        }

        double ICalculator.Divide(double x, double y)
        {
            return x / y;
        }

        #endregion
    }
}

  4.步骤四:通过自我寄宿的方式寄宿服务(自己编写主机程序发布服务)

  当服务契约(接口)和服务类创建好后,要有一种方式把服务发布出来,这里常用有两种方法:

  1)通过自我寄宿的方式:

    自行创建HOST端,通过自己创建的主机程序发布服务。这里的步骤四就是使用这种方法。

    [服务寄宿]:为服务制定一个宿主的过程。

    [终结点(Endpoint)]:WCF采用基于Endpoint的通信手段。Endpoint=ABC

      • Adrress(地址):地址决定了服务的位置;
      • Binding(绑定):绑定实现通信的细节——网络传输、消息编码,以及其他为实现某种功能(比如传输安全、可靠消息传输、事务等)对消息进行相应处理;
      • Contract(契约):对服务操作的抽象,也是对消息交换模式及消息结构的定义。          

  Hosting(自我寄宿主机)的实现方法有三种:

    i.)通过代码:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.ServiceModel;
 7 using System.ServiceModel.Description;
 8 using WCFBegin.Service.Interface;
 9 using WCFBegin.Service;
10 
11 namespace WCFBegin.Hosting
12 {
13     class Program
14     {
15         static void Main(string[] args)
16         {
17             using(ServiceHost host=new ServiceHost(typeof(CalculatorService)))
18             {
19                 host.AddServiceEndpoint(typeof(ICalculator),new WSHttpBinding(),"http://127.0.0.1:3721/calculatorservice");
20                 if(host.Description.Behaviors.Find<ServiceMetadataBehavior>()==null)
21                 {
22                     ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
23                     behavior.HttpGetEnabled = true;
24                     behavior.HttpGetUrl = new Uri("http://127.0.0.1:3721/calculatorservice/metadata");
25                     host.Description.Behaviors.Add(behavior);
26                 }
27                 host.Opened += delegate
28                 {
29                     Console.WriteLine("CalculatorService 已经启动,按任意键终止服务!");
30                 };
31                 host.Open();
32                 Console.Read();
33             }
34         }
35     }
36 }

    ii.)在正式WCF开发时,一般采用配置,而不是编程的方式进行Endpoint的添加和服务行为的定义。上面代码中添加Endpoint和定义服务行为的代码可以替换为:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <configuration>
 3     <system.serviceModel>
 4         <behaviors>
 5             <serviceBehaviors>
 6                 <behavior name="metadataBehavior">
 7                     <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:3721/calculatorservice/metadata"/>
 8                 </behavior>
 9             </serviceBehaviors>
10         </behaviors>
11         <services>
12             <service name="WCFBegin.Service.CalculatorService" behaviorConfiguration="metadataBehavior">
13                 <endpoint address="http://127.0.0.1:3721/calculatorservice" binding="basicHttpBinding"
14                     bindingConfiguration="" contract="WCFBegin.Service.Interface.ICalculator" />
15             </service>
16         </services>
17     </system.serviceModel>
18 </configuration>

     上面的放在Hosting项目的App.config里。

     iii.)刚开始,也可以使用WCF服务配置编辑器来配置App.config中的代码

     [工具]菜单--[WCF服务配置编辑器],选中Service项目中生成的dll文件,创建服务,根据向导可以自动生成App.config,再将其覆盖Hosting项目中原有的即可

      如果使用ii)和iii)中的方式设置了App.config,就可以将i)中的代码缩减为:

     static void Main(string[] args)
        {
            using(ServiceHost host=new ServiceHost(typeof(CalculatorService)))
            {
                host.Opened += delegate
                {
                    Console.WriteLine("CalculatorService 已经启动,按任意键终止服务!");
                };
                host.Open();
                Console.Read();
            }
        }

  完成以上的操作后,就可以编译,如果正常通过,在浏览器中输入http://127.0.0.1:3721/calculatorservice/metadata,就可以看到以WSDL形式表示的服务元数据了。

  2)通过IIS寄宿服务:

    将服务寄宿在IIS上,通过IIS发布服务,放在步骤六中介绍

  5.步骤五:创建客户端程序来调用服务

  为Client项目添加服务引用,地址为服务元数据的地址:http://127.0.0.1:3721/calculatorservice/metadata,“转到”后,给个命名空间CalculatorService就可以用了。

  *注意:添加服务时,服务必须保持运行状态,即需要打开Hosting.exe

  WCF原理复杂,使用简单,刚才的操作会由VS自动生成一系列用于服务调用的代码和配置。(所以有人说.net不适合学习,只适合使用)。

  添加服务引用后,用于客户端调用的服务契约接口CalculatorService会被生成出来。

  真正被客户端用于服务调用的是一个叫做CalculatorServiceClient的类,派生自System.ServiceModel.ClientBase<CalculatorService>。

  CalculatorServiceClient类同样实现了契约接口,并通过调用从基类继承的Channel属性的相应方法实现了4个运算操作方法。

  Client代码:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using WCFBegin.Client.CalculatorServices;
 7 
 8 
 9 namespace WCFBegin.Client
10 {
11     class Program
12     {
13         static void Main(string[] args)
14         {
15             using (CalculatorServiceClient proxy = new CalculatorServiceClient())
16             {
17                 Console.WriteLine("x+y={2} when x={0} and y={1}.",1,2,proxy.Add(1,2));
18                 Console.WriteLine("x-y={2} when x={0} and y={1}.", 1, 2, proxy.Subtract(1, 2));
19                 Console.WriteLine("x*y={2} when x={0} and y={1}.", 1, 2, proxy.Multiply(1, 2));
20                 Console.WriteLine("x/y={2} when x={0} and y={1}.", 1, 2, proxy.Divide(1, 2));
21                 Console.Read();
22             }
23         }
24     }
25 }

  6.步骤六:通过IIS寄宿服务

  在步骤三中,我们使用的是自我寄宿,这里介绍IIS寄宿:

  1)创建.svc文件

  基于IIS的服务寄宿要求相应的WCF服务具有相应的.svc文件,将其部署到IIS站点中即可提供WCF服务。

  .svc文件:

  直接在Service项目根目录中添加一个文本文件,重命名为CalculatorService.svc,代码为:

<%@ServiceHost Service="WCFBegin.Service.CalculatorService" %>

  2)创建Web应用

  以Service项目为根目录创建一个Web应用,并添加Web.config文件,添加代码:

 1 <configuration>
 2   <system.serviceModel>
 3     <behaviors>
 4       <serviceBehaviors>
 5         <behavior name="metadataBehavior">
 6           <serviceMetadata httpGetEnabled="true"/>
 7         </behavior>
 8       </serviceBehaviors>
 9     </behaviors>
10     <services>
11       <service name="WCFBegin.Service.CalculatorService" behaviorConfiguration="metadataBehavior">
12         <endpoint binding="basicHttpBinding" bindingConfiguration="" contract="WCFBegin.Service.Interface.ICalculator"/>
13       </service>
14     </services>
15 </configuration>

  由于服务调用是通过访问服务对应的.svc文件来实现的,.svc文件地址对客户端来说就是服务Endpoint的address,所以将Config中的address都删除。

  为Web项目添加引用,可以更改Service项目属性,将编译输出目录设置为\bin,再重新生成一次即可。

  这时,就可以通过http://localhost:800/calculatorservice.svc?wsdl(这是我的地址,自己的根据各自IIS配置不同而不同),来得到服务元数据的WSDL文件。

  客户端只需要修改Endpoint的地址,从而转向对寄宿在IIS下的CalculatorService的访问:

 1 <configuration>
 2     <system.serviceModel>
 3         <behaviors>
 4             <serviceBehaviors>
 5                 <behavior name="metadataBehavior">
 6                     <serviceMetadata httpGetEnabled="true" httpGetUrl="http://127.0.0.1:3721/calculatorservice/metadata"/>
 7                 </behavior>
 8             </serviceBehaviors>
 9         </behaviors>
10         <services>
11             <service name="WCFBegin.Service.CalculatorService" behaviorConfiguration="metadataBehavior">
12                 <endpoint address="http://127.0.0.1:3721/calculatorservice" binding="basicHttpBinding"
13                     bindingConfiguration="" contract="WCFBegin.Service.Interface.ICalculator" />
14             </service>
15         </services>
16     </system.serviceModel>
17 </configuration>

【总结】

  第一篇介绍了WCF的基本概念,和一个简单的WCF实例,可以看出WCF使用起来简单,但是本身结构原理较为复杂。

  很多东西都是系统自动生成的,对其运行原理和技术细节还很模糊,需要在下面的学习中进一步了解。

相关文章: