WCF分布式开发步步为赢(6):WCF服务契约继承与分解设计

上一节我们学习了WCF分布式开发步步为赢(5)服务契约与操作重载部分。今天我们来继续学习WCF服务契约继承和服务分解设计相关的知识点。WCF服务契约继承有何优势和缺点?实际项目里契约设计有什么原则和依据?面向对象的设计经验有何值得借鉴的地方?这里我们会一一给出详细的介绍。本文首先介绍的是WCF服务中契约继承的一些概念、例子代码分析,其次来讲解服务契约的设计问题。首先介绍的也是进行服务设计的必要性,服务设计的原则,示例代码分析。最后是全文的总结部分。结构如下:【1】OO面向对象设计原则,【2】服务契约继承,【3】服务契约分解概念,【4】服务契约分解原则,【5】服务契约分解代码分析,【6】总结。

【1】面向对象设计原则OO:

    这里我们有必要先回顾一下面向对象的经典的设计原则。这些设计原则对我们WCF服务契约的设计来说有重要的参考价值。服务契约实际利用了接口来定义实现,语法类似,WCF框架也是基于现有的语言体系,对此扩展了编程模型,比如增加了属性设置机制等。如果你曾经接触过OO面向对象的这些概念,那么这些设计原则理解起来不会困难。很多编程书籍里都会有介绍,设计模式相关书籍里会有比较详细的介绍。这里介绍几个主要的概念,为下文的继承和设计WCF服务契约部分作铺垫:

<1>单一职责原则(SRP): 一个类应该仅有一个引起它变化的原因。

<2>开放封闭原则(OCP): 类模块应该是可扩展的,但是不可修改(对扩展开放,对更改封闭)。

<3>Liskov 替换原则(LSP): 子类必须能够替换它们的基类。

<4> 依赖倒置原则(DIP): 高层模块不应该依赖于低层模块,二者都应该依赖于抽象。 抽象不应该依赖于实现细节,实现细节应该依赖于抽象。

<5>接口隔离原则(ISP): 不应该强迫客户程序依赖于它们不用的方法。

【2】服务契约继承:

服务契约的定义和接口定义类似,接口可以继承与多个接口。但是WCF契约属性是不支持继承的。由于WCF框架自身的问题,不支持契约属性的继承,因此这给我们服务契约属性的声明和使用却有不少限制。在使用契约继承属性的过程中腰注意服务端契约的属性继承问题,此外就是客户端添加服务引用后,无法还原服务端契约层级的关系,所有的操作契约由一个契约类封装。因此实际编程我们要兼顾到两个方面的情况。

【2.1】服务端契约层级:

接口支持继承。但ServiceContract特性不支持继承的,我们查看其实现代码可以知道Inherited = false,即不支持继承,部分代码如下:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, Inherited = false, AllowMultiple = false)]
    public sealed class ServiceContractAttribute : Attribute
    {
        
    }

因此在定义多层服务契约接口的时候,我们必须在每层接口上标记ServiceContract属性,以支持WCF服务契约属性。

示例代码如下:

//契约属性不支持继承,如果需要继承契约属性,接口标志契约属性,定义一个交通工具基接口契约
    [ServiceContract(Namespace = "http://www.cnblogs.com/frank_xl/")]
    interface IVehicle
    {

}
    //接口继承关系不支持ServiceContract继承
    [ServiceContract(Namespace = "http://www.cnblogs.com/frank_xl/")]
    interface ITruck : IVehicle
    {
    }

货车服务类能够实现整个WCF契约层级接口,我们这里实现了Run跑和Carry运输货物的契约,代码如下:

//货车服务类实现货车服务契约
    public class WCFServiceTruck : ITruck
    {
        //实现接口定义的方法
        public string Run()
        {
            Console.WriteLine("Hello! ,This an inherite demo");
            return "Hello! Truck is running  ";
        }
        //实现接口定义的方法
        public string Carry()
        {
            Console.WriteLine("Hello! ,This an inherite demo");
            return "Hello! Truck is carrying  ";
        }

}

宿主可以为契约层级最底层的接口公开一个单独的终结点,配置文件设置代码如下:

<service behaviorConfiguration="WCFService.WCFServiceBehavior" name="WCFService.WCFServiceTruck">
        <endpoint
           address="http://localhost:9003/WCFServiceTruck"
           binding="wsHttpBinding"
           contract="WCFService.ITruck">
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:9003/"/>
          </baseAddresses>
        </host>
      </service>

【2.2】客户端契约层级:

客户端添加服务端数据引用,导入一个服务终结点的元数据时,反序列化生成的客户端契约将不再维持原来的层级关系。一个单独的契约,名称为终结点公布的契约名。含了层级中继承相关所有接口定义的操作契约。OperationContract特性中的Action与ResponseAction属性,可以保留原来定义每个操作的契约名。我们要想恢复服务端契约继承的层级关系,客户端可以手工修改代理以及导入契约的定义,恢复契约层级。手动恢复方式其实带给我们很多灵活性,但是也增加了工作量和复杂度。实际项目里一般接触不多,这里就不详细介绍,需要的话可以查阅相关的资料。

【2.2】服务契约分解概念:

下面我们继续讲解服务契约设计的一些概念知识。其实服务契约的设计在WCF分布式应用项目中属于比较重要的部分。服务契约的设计和实现相对来多比较复杂,除了注意已有的设计原则之外还要注意WCF契约相关的特性。面向服务分析与设计的属于一个较新的领域。实际的服务分析和设计我们还是借助于已有的经验和原则,来指我们更好地设计服务契约。这也是本节给出一个面向对象重要设计原则的原因。

因为WCF服务契约的定义借助现有的编程语言如C#,契约设计实际首先就是对服务接口的设计。我们应该如何设计服务接口?如何知道服务接口中应该定义哪些操作?每个接口又应该包含多少操作?等等都是我们必须考虑的问题。Service Contract Factoring就是要考虑服务接口的分解问题。在面向服务的应用程序中,可重用的基本单元就是服务接口。因此如何设计服务接口就是重中之重。

【4】服务契约分解原则:

这里我们设计服务接口时候即遵循单一职责和接口隔离等原则,又要考虑系统的开发成本。合理的接口是专业的、松耦合的、规则化和可重用的接口。这些优势同样有利于整个系统的松耦合和可重用等特性。总的来说,契约分解的目的就是使接口包含的更少操作。

如果我们定义了太多的细粒度服务接口,虽然它们易于实现,但集成它们的代价太高。如果我们仅定义了一个复杂的服务接口,虽然集成的成本会降低,但却接口的实现和可维护性较差。我们设计面向服务的系统时,需要平衡两个影响系统的因素,接口成本和集成成本。参见下图。

系统服务的代价为实现的代价与集成的代价的综合。上图显示了最小代价与服务接口规模和数量之间的关系。设计良好的系统应该在系统集成成本和契约接口设计实现成本之间作何平衡点,达到系统整体开发成本的降低。

【5】服务契约分解代码分析:

这里我们来讲解一个简单的服务契约设计的例子。这里我们还继续使用交通车为例子进行讲解。

我们首先定义一个接口交通工具IVehicle,定义了如下:

[ServiceContract(Namespace = "http://www.cnblogs.com/frank_xl/")]
    interface IVehicle
    {
        //操作契约,跑,开的契约
        [OperationContract]
        string Run();
        //操作契约,拉人、载人的契约
        [OperationContract]
        string Take();
        //操作契约,运输货物的契约
        [OperationContract]
        string Carry();
    }

这里的交通工具接口,分别定义了跑,拉人和载货三种操作。放在一个接口中。这就违反了接口设计中的主要的原则ISP接口隔离原则。我们不应该强迫服务继承他们不需要的操作。接口隔离原则ISP:使用多个专门的接口比使用单一的接口要好。从服务设计的角度来说:一个类对另外一个类的依赖性应当是建立在最小的接口上的。如果服务类只需要某一些方法的话,那么就应服务类可以继承相应的接口实现这些需要的方法,而不要实现不需要的方法。继承接口意味着作出承诺,服务类必须实现,也就是所谓的契约的概念。

因此,我们将服务契约分解为接口层级的方式,通过接口分解和继承,实现操作的分离。这里可以重新定义两个接口货车ITruck和小轿车ICar,分别定义自己的拉货Carry();和载人Take()的操作,当服务类需要实现拉货操作的时候就继承避免了接口设计的职责的混淆。代码如下:

//契约属性不支持继承,如果需要继承契约属性,接口标志契约属性,定义一个交通工具基接口契约
    [ServiceContract(Namespace = "http://www.cnblogs.com/frank_xl/")]
    interface IVehicle
    {
        //操作契约,跑,开的契约
        [OperationContract]
        string Run();
    }
    //接口继承关系不支持ServiceContract继承
    [ServiceContract(Namespace = "http://www.cnblogs.com/frank_xl/")]
    interface ITruck : IVehicle
    {
        //操作契约,运输货物的契约
        [OperationContract]
        string Carry();
    }
    //接口继承关系不支持ServiceContract继承
    [ServiceContract(Namespace = "http://www.cnblogs.com/frank_xl/")]
    interface ICar : IVehicle
    {
        //操作契约,拉人、载人的契约
        [OperationContract]
        string Take();
    }

【6】总结:

以上就是对WCF服务继承和分解设计相关知识的介绍,下面简要做下介绍:

<1>:本文开始讲解了OO面向对象的设计原则,作为经典的面相对象的设计经验,也是设计模式文章里的重要的知识点,对WCF服务设计有主要的参考价值,比如SRP单一职责、ISP接口隔离等原则;

<2>:我们应该避免设计过多或者过少的接口,应该考虑系统的服务接口定义实现的复杂度和系统服务集成的成本。综合起来权衡,取得一个平衡点。服务契约成员的最佳数量(根据经验总结,仅代表本人观点)应介于3到5之间。开发者在制订WCF编码规范时,应该指定一个上限值(例如20)。无论在何种情况,都不能超过该值。

另外避免定义类属性操作(Property-Like Operation)这样的定义十分类似C#的属性访问器,例如:

[OperationContract]
string GetCarNumber();

我们不应该干涉客户端属性访问,客户端在调用抽象操作时,不用关心具体的实现细节,只负责调用操作,而由服务去管理服务对象的状态。

<3>:WCF服务设计原则只是一些参考原则,对实际的开发工作起知道作用。包括前面叙述的面相对象的经典的设计原则和设计模式的宝贵经验。实际项目中需要结合自身的实际情况,实时调整和设计服务契约接口的设计,以期设计去更加合理和高效的服务契约。最后是本文的参考代码:Files/frank_xl/WCFServiceFactoringFrankXuLei.rar,下一节我们继续学习WCF数据契约的知识,请继续关注~。

参考资料:

1.《Programming WCF Services 》,By Juval Lowy;

2.面向对象设计模式与原则,http://hi.baidu.com/dapengchu/blog/item/0521e6d965525dee38012f5c.html

时间: 2024-08-25 02:51:53

WCF分布式开发步步为赢(6):WCF服务契约继承与分解设计的相关文章

WCF分布式开发步步为赢(13):WCF服务离线操作与消息队列MSMQ

之前曾经写过一个关于MSMQ消息队列的文章:WCF分布式开发必备知识(1):MSMQ消息队列 ,当时的目的也是用它来作为学习WCF 消息队列MSMQ编程的基础文章.在那篇文章里,我们详细介绍了MSMQ消息队列的基本概念.安装.部署.开发.调试等相关问题.今天我们来学习WCF分布式开发步步为赢(13):WCF服务离线操作与消息队列MSMQ.在WCF框架下使用MSMQ消息队列服务编程.  这里我会给出一个使用WCF MSMQ实现离线请求的DEMO示例程序. 全文结构是:[1]MSMQ基本概念[2]W

WCF分布式开发步步为赢(7):WCF数据契约与序列化

本节继续学习WCF分布式开发步步为赢(7):WCF数据契约与序列化.数据契约是WCF应用程序开发中一个重要的概念,毫无疑问实现客户端与服务端数据契约的传递中序列化是非常重要的步骤.那么序列化是什么?为什么会有序列化机制?或者说它是为了解决什么问题?作用是什么?现有的.NET 序列化机制和WCF序列化机制有什么不同?我们在本节文章里都会详细介绍.本节结构:[0]数据契约[1]序列化基本概念[2].NET 序列化机制[3]WCF序列化机制[4]代码实现与分析[5]总结. 下面我们正式进入今天的学习阶

WCF分布式开发步步为赢(3)WCF服务元数据交换、配置及编程开发

今天我们继续WCF分布式开发步步为赢(3)WCF服务元数据交换.配置及编程开发的学习.经过前面两节的学习,我们了解WCF分布式开发的相关的基本的概念和自定义宿主托管服务的完整的开发和配置过程.今天我们来详细学习WCF服务元数据交换的相关内容.WCF服务元数据究竟是什么?为什么WCF服务要暴露元数据交换节点?这些和以前的Web Service有什么关系?WCF服务元数据交换的方式有那些?我们如何实现WCF服务元数据交换,本节我们会详细讲解.全文结构如下:[1]WCF服务元数据的基本概念.[2]WC

WCF分布式开发步步为赢(4):WCF服务可靠性传输配置与编程开发

今天继续WCF分布式开发步步为赢系列的第4节:WCF服务可靠性传输配置与编程开发.这个章节,我们要介绍什么是WCF服务的可靠性传输,随便介绍网络协议的概念,Web Service为什么不支持可靠性传出,具体的WCF绑定协议和可靠性的关系,实现可靠性传输有什么方式,以及配置和开发的详细实现代码分析部分.[1]可靠性传输[2]配置方式实现可靠性传输[3]编程方式实现可靠性传输[4]编程实现必备有序传递[5]结果分析和总结. 下面进入正式的内容: [1]可靠性传输: [1.0]网络协议基础知识: 这里

WCF分布式开发步步为赢(12):WCF事务机制(Transaction)和分布式事务编程

今天我们继续学习WCF分布式开发步步为赢系列的12节:WCF事务机制(Transaction)和分布式事务编程.众所周知,应用系统开发过程中,事务是一个重要的概念.它是保证数据与服务可靠性的重要机制. 作为面向服务应用的开发平台,WCF也提供了对事物编程模型的支持..NET 2.0提供的System.Transactions类来开发事务应用程序.同样WCF也支持事务特性,WCF事务机制是什么,它与微软已有的技术如Microsoft 分布式事务协调器 (MSDTC)有何关系?与Enterpise

WCF分布式开发步步为赢(11):WCF流处理(Streaming)机制

WSE3.0框架提供了数据优化传输机制,WSE3.0构建Web服务安全(4):MTOM消息传输优化和文件上传.下载 疑问里进行了介绍.WCF同样也提供了流操作来支持大数据对象的传输和处理优化机制,今天我们WCF分布式开发步步为赢系列的(4):使用流操作(Streaming Operations)优化传输.本节会详细介绍流操作的相关概念.编程实现过程,以及实际开发过程中需要主要的一些问题.本节结构:[1]流处理的概念[2]流处理的特点[3]示例代码分析[4]总结.最后上传本文的示例代码. Stre

WCF分布式开发步步为赢(14):WCF安全编程--基本概念

WCF安全机制是个非常复杂的问题,因为涉及的知识点较多,所以今天这个文章,会分析进行WCF安全开发应该了解的哪些知识点.如何查看资料.为了更好地理解WCF安全相关知识,我把WCF安全机制主要知识点整理为图表.本章以介绍WCF安全机制的基础概念为主.  要学习WCF安全编程,你应该学习什么首先掌握什么基础知识?很多时候会因为缺乏系统的安全概念,在进行WCF安全编程开发的时候,遇到很多问题,比如所证书,这个概念相信很多初学者第一次接触的时候花费了很多时间.我当时在做WSE安全开发的时候就查阅了很多资

WCF分布式开发步步为赢(5)服务契约与操作重载

继上一节WCF分布式开发步步为赢系列的(4):WCF服务可靠性传输配置与编程开发,本节我们继续学习WCF分布式开发步步为赢的第(5)节:服务契约与操作重载.这里我们首先讲解OOP面向对象的编程中方法重载,重载的意义,WCF服务编程开发如何实现操作重载,随后是代码分析部分,给出了服务端服务契约定义和实现操作重载的注意的问题和实现过程,然后详细介绍了客户端实现操作重载的方式.最后是本文的总结部分.本节的结构是:[1]重载概念[2]操作重载[3]代码实现分析[4]运行结果[5]总结 [1]重载概念:

WCF分布式开发步步为赢(15):错误契约(FaultContract)与异常处理(ExceptionHandle)

今天学习WCF分布式开发步步为赢系列的15节:错误契约(FaultContract)与异常处理(ExceptionHandle).本节内容作为WCF分布式开发的一个重要知识点,无论在学习还是项目中都应该有所了解.此前也和多位学习爱好者讨论过WCF异常处理的相关知识.这里就系统整理一下,共大家参考.同时也是对<WCF分布式开发步步为赢>系列文章的完善和补充.   本节主要涉及的知识点就是:[1].NET异常处理[2]WCF异常处理[3]错误契约[4]WCF异常处理扩展[5]示例代码分析,最后是[