zoukankan      html  css  js  c++  java
  • WCF随录(2)—构建WCF的服务架构

         在前面我们简单的介绍了WCF的由来及在SOA系统中所处的重要地位。但需要向大家说明的是,SOA绝对不光只是WCF,SOA是一个复杂庞大的系统架构。而WCF只是它的一个技术开发平台。 企业部署SOA重在通过一定的投入进行组织的深刻变革以获得最大的利益。而并不关心是否用WCF来开发。真正需要注重它的则是技术人员。但肯定的是脱离了企业应用的技术实现是没有任何意义的。

         闲话不多说,还是让我们回到代码上来吧。这里我们完成一个简单的案例,在这个系统中,使用WCF来发布一个服务,用来完成摄氏温度的转换。为了实现这个架构,我们首先需要创建一个新的Soluting。

         这里我们使用VS2008,要创建WCF项目有多种方法,例如,可以在“新建项目”中选择“WCF服务库”。

         点击“确定”,IDE将为你完成一个基础的WCF架构模板,其架构如下:

         其中IService1为一个接口层,它定义服务端和客户端共同继承的接口,并通过Attribute将其转换为契约(契约的概念后面会详细讲到)。Service1为服务层,通过继承接口层的契约向外界提供服务。这样创建WCF项目非常简便,但有一问题,它创建的架构是在同一个项目中使用Class文件进行分层。这不适合企业级应用的需要。因此,我们选择自己创建WCF架构。

         1)新建一个“类库”解决方案,方案的名称改为MyWCF,项目名称为MyWCF.Contract,类名称改为IContract

         2)首先为改项目添加System.ServiceModel的引用。

         3)在IContract.cs文件中,首先引用System.ServiceModel的命名空间。然后将namespace改为MyWCF.Contract。最后将主class改为interface。代码入下:

    using System;
    using System.ServiceModel;

    namespace MyWCF.Contract
    {
        [ServiceContract]
        
    public interface IContract
        {
            
    /// <summary>
            
    /// 温度转换
            
    /// </summary>
            
    /// <param name="celsius">摄氏温度</param>
            
    /// <returns>转换结果,华氏温度</returns>
            [OperationContract]
            
    float GetFahrenheit(float celsius);
        }

    }

         

      其中ServiceContract Attribute为接口服务契约,表示此接口能被作为WCF的契约,OperationContract Attribute为方法契约。使用Attribute申明的方式,使得契约的设计更为方便,结构也更加清晰。

      这里我们还需要对契约的概念做一个简单说明,以利于大家理解前面讲的概念。在SOA架构中, 契约是一个非常重要的概念。SOA的核心是服务,既然是服务就要牵涉到两方,服务方和被服务方。就好比电信局向大家提供电话通讯服务,为了保障服务的顺利和安全,电信局(服务方)需要大家签订一个服务条款,约定电信局提供服务的形式,内容等信息,也约定了被服务方的权利和义务。签订了此协议后,服务双方都需要遵守这份合同条款。这个服务条款,就可以被理解成契约。被服务方要想接受服务方提供的服务,就必须和服务方遵守相同的契约。当然,WCF的契约远不只这么简单,在后面我们还会进行详细的介绍。

      4)理解了契约的概念,我们再回头看刚才的程序。在上面的程序中,契约被表现为了一个接口和相关的方法,并使用不同的Attribute将其指定为契约。有了这个契约后,我们就可以在其基础上来创建服务了。因此接下来需要一个服务层,我们在解决方案中再添加一个类库项目,取名为MyWCF.Service。并在项目中添加System.ServiceModel的引用(具体添加方法见上面的操作)和对MyWCF.Contract项目的引用,如下图。

          

         5)有了对契约的引用后,服务就可以继承契约的接口了,代码如下:

    using System;
    using System.ServiceModel;
    using MyWCF.Contract;

    namespace MyWCF.Service
    {
        
    /// <summary>
        
    /// 继承契约的服务
        
    /// </summary>
        public class TemperatureService : IContract
        {
            
    /// <summary>
            
    /// 稳定转换的方法
            
    /// </summary>
            
    /// <param name="celsius">摄氏温度</param>
            
    /// <returns>返回华氏温度</returns>
            public float GetFahrenheit(float celsius)
            {
                
    //将摄氏度转换为华氏度的公式“F=1.8(C)+32”
                celsius = celsius * 1.8F//执行乘法
                return celsius + 32//执行加法
            }
        }
    }

         

         5)契约已签署,服务已设计完成,接下来需要一个发布服务的平台,这里我们建立一个ConsoleApplication作为服务的载体,在WCF中,称为对服务的“寄存”。

         这里我们顺便要提到一些新的概念,以便你对寄存过程的理解。前面我们讲到过,寄存实际上是用来发布服务。有了服务后,用户就可以通过这个服务进行通讯了。但你要和服务端通讯,就必须有一个通讯的渠道,好比你与电信签署了通讯协议,但最后通讯过程完全还是由电信局来控制。而这个通讯过程对于用户来说则是完全封闭的,用户也不需要去关系通讯的细节,反正只要拿起电话,拨通号码,能和对方通话就行了。但对于开发人员来说,就必须考虑到如何通讯,于是WCF为你提供了这样一个对象Endpoint,它负责服务端和客户端通讯的细节。

         既然涉及到通讯的细节,就需要考虑到几个东西,首先是地址Address,就好比我们的拨号号码。在Endpoint中,地址用uri对象表示。比如Uri uri = new Uri(http://localhost:8080/MyWCF); 表示地址在本机的8080端口上的MyWCF项目中。

         其次是Binding,这个概念在WCF中十分重要。因为除地址外,通讯还需要重要考虑的就是通讯所使用的协议、编码方式,已经安全性等内容。对于其它开发架构来说,要设置好这些内容是一件非常麻烦的事情,要考虑的东西很多。但对于WCF来说就再简单不过了,这些所有的东西只需要用一个已设置好的对象来指明就行了,因为WCF已为我们提供了一整套用于应付各种通讯的对象,这个在后面我们还会单独介绍。这里我们用BasicHttpBinding对象,这个对象表示使用HTTP协议,没有任何安全设置,消息都以明文传送,对客户端也不进行验证。

         最后一个是契约Contract,前面我们已经提到过,它用来描述服务提供的各种操作。看到这里,细心的朋友已经可以看出一个小技巧。就是Endpoint中的三要素取其每项的第一个字母,合起来就是ABC,呵呵,不知是凑巧还是故意这样设置,不过也倒方便我们记忆了。

         设置好Endpoint,实际上已能够进行通讯了,但要发布服务,还差一个东西,就是行为Behavior。行为的作用是把服务通过WSDL对外暴露对服务的Metadata描述。这句话很绕口,还是举个例子,我们在打10086充电话费时,首先会听到一个语音提示,说听到提示音后请按键选择服务项目,1为普通话,2为英语。按1进入后又会说为手机充值请按1,查询本手机花费请按2...... OK,这下你清楚了吧。行为好比提供一个服务清单,供你选择,如果没有它,即使服务发布出来了,你也无法知道该选择什么。当然,行为还有一些其它功能,这里我们不详述,还是留到后面去深入理解。

         6)好了,理解了这些,我们又可以继续项目的开发了,我们把上面刚添加的控制台项目的名称定为MyWCF.Hosting,在该项目中,需引用前面的两个项目,System.ServiceModel命名空间和System.ServiceModel.Description命名空间,其代码如下:

    Hosting

          7)全部代码写完后,一个WCF的服务端实际上已经被建立起来了,这时候已经可以发布项目了。我们把MyWCF.Hosting项目定为启动项目,编译运行后得到如下画面。

         这表面服务已经在运行过程中了。我们可以测试这个服务,还记得前面设置的Uri吗,现在就可以通过这个Uri来访问服务页面。打开你的浏览器,将Uri的地址输入到里面并回车,会出现下面的页面。

         因为图太大,这里我们只截取了一部分。可以看到,我们在MyWCF.Service中定义的服务此时已被显示出来。并且可以通过svcutil.exe工具来创建客户端所需的信息。

         对于创建WCF服务,我们需要重点理解架构为何如此安排,再来看看VS2008中项目的架构。

         这个架构中,首先是把服务与契约分离。因为契约是服务端和客户端都需要遵循的,分离出来有助于降低耦合度。而服务端与提供服务的寄存方也单独分离开,这样,寄存方就不局限于单一的某种平台,可以是ConsoleApplication,也可以是WinForm,或是WebForm,当服务发生变化时,寄存方也不会受到耦合的影响。另外,在WCF的架构中,要求服务是自治的,每一个服务之间不应受到牵连,也是采用这种架构的主要原因。

         配置Endpoint和Behavior是一件较为繁琐的工作,特别是当服务器的Uri发生变化时(在网络环境下,这会较为非常频繁),难免要涉及到代码的修改。而WCF正是为了解决这些配置问题而生,利用.NET自身的优势,微软将这件工作变得非常简单。所有的工作都可以在配置文件中完成,这时候,我们只需要在MyWCF.Hosting项目中添加一个App.config文件,代码如下:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      
    <system.serviceModel>
        
    <services>
          
    <service name="MyWCF.Service.TemperatureService" behaviorConfiguration="behavior">
            
    <host>
              
    <baseAddresses>
                
    <add baseAddress="http://localhost:8080/MyWCF"/>
              
    </baseAddresses>
            
    </host>
            
    <endpoint address="" binding="basicHttpBinding" contract="MyWCF.Contract.IContract"></endpoint>
          
    </service>
        
    </services>
        
    <behaviors>
          
    <serviceBehaviors>
            
    <behavior name="behavior">
              
    <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
            
    </behavior>
          
    </serviceBehaviors>
        
    </behaviors>
      
    </system.serviceModel>
    </configuration>

         可以看到,在配置文件中,Uri、Endpoint和Behavior都被配置好了,这时候MyWCF.Hosting的代码变得异常简单:

    Hosting

         

         配置好后,当服务启动时,自动到config文件中读取相应的配置。程序的结构被进一步简化,服务被彻底的从应用层分离开,完全具备了自治的特性。当你再看到这里时,是不是觉得整体系如此简单,清晰,这就是WCF来的深度体验。

  • 相关阅读:
    现代C语言程序设计之数据存储
    Linux系统运维与架构设计之文件管理
    Linux系统运维与架构设计之系统基本使用
    Linux系统运维与架构设计之搭建运维环境
    Linux系统运维与架构设计之Linux概述
    Linux系统运维与架构设计技术栈
    架构师成长之道-C语言基础之C语言概述
    K3/Cloud树形单据体的rowId赋值
    K3违反内码唯一键约束
    K3修改字段名
  • 原文地址:https://www.cnblogs.com/jinqi79731/p/1384178.html
Copyright © 2011-2022 走看看