服务契约

《Programming WCF Services》翻译笔记之二

本书的第2章主要讲解了服务契约。内容:“本章首先会讨论如何通过操作重载与契约层级,为两种迥然不同的编程模型建立关联。然后,本章会介绍一些简单而又强大的设计和分离服务契约的技术与指导原则。在本章末尾,还演示了如何通过编程方式在运行时实现与契约元数据的交互。”

操作重载

C++与C#均支持操作的重载,但在WCF的编程模型中,却并不支持这种技术。坦白说,在WCF的编程模型,对于面向对象的支持都是比较弱的,包括后面要介绍的继承体系与多态,都存在许多问题。因此,在服务端我们不能定义这样的服务契约:

[ServiceContract]
interface ICalculator
{
   [OperationContract]
    int Add( int arg1, int arg2);

   [OperationContract]
    double Add( double arg1, double arg2);
}

虽然在编译时能够通过,然而一旦在装载宿主时,就会抛出InvalidOperationException异常。以ICalculator契约为例,WCF会认为是零个操作。

解决的办法是利用OperationContract特性的Name属性,例如:

[ServiceContract]
interface ICalculator
{
   [OperationContract(Name = "AddInt")]
    int Add( int arg1, int arg2);

   [OperationContract(Name = "AddDouble")]
    double Add( double arg1, double arg2);
}

不过采用这种方式,存在的问题是生成的代理会将Name属性指定的名称作为代理操作的方法名。这对于编程者而言,并非好的方式。所幸我们可以手动对 生成的代理进行修改,将它修改为与服务契约一致的操作名。由于,此时通过Name指定了操作的别名,因此,避免了装载宿主抛出的异常。

契约的继承

即使父接口标记了[ServiceContract],子接口仍然需要标记[ServiceContract],因为ServiceContractAttribute是不可继承的。服务类对服务契约的实现,与传统的C#编程没有什么区别。例如:

[ServiceContract]
interface ISimpleCalculator
{
   [OperationContract]
    int Add( int arg1, int arg2);
}
[ServiceContract]
interface IScientificCalculator : ISimpleCalculator
{
   [OperationContract]
    int Multiply( int arg1, int arg2);
}
class  MyCalculator : IScientificCalculator
{
    public  int Add( int arg1, int arg2)
    {
       return arg1 + arg2;
    }
    public  int Multiply( int arg1, int arg2)
    {
       return arg1 * arg2;
    }
}

公开终结点的时候,可以对最底层的契约接口公开一个单独的终结点:
<service name="MyCalculator">
   <endpoint>
       <address="http://localhost:8001/MyCalculator/">
       <binding="basicHttpBinding">
       <contract="IScientificCalculator">
   </endpoint>
</service>

客户端在导入如上的服务契约时,会取消服务契约的继承层级,并利用OperationContract特性中的Action与 ReplyAction属性,保留原来定义每个操作的契约名。但为了使客户端编程能够与服务编程保持一致,最好是恢复客户端的契约层级。方法并无什么太玄 妙的地方,无非就是根据服务契约层级对客户端契约进行手工修改。修改后的客户端契约及其代理的定义如下:

[ServiceContract]
public  interface ISimpleCalculator
{
   [OperationContract]
    int Add( int arg1, int arg2);
}
public  partial  class  SimpleCalculatorClient : ClientBase<ISimpleCalculator>,
                                              ISimpleCalculator
{
    public  int Add( int arg1, int arg2)
    {
       return Channel.Add(arg1,arg2);
    }
    //Rest of the proxy
}

[ServiceContract]
public  interface IScientificCalculator : ISimpleCalculator
{
   [OperationContract]
    int Multiply( int arg1, int arg2);
}
public  partial  class  ScientificCalculatorClient :
                           ClientBase<IScientificCalculator>,IScientificCalculator
{
    public  int Add( int arg1, int arg2)
    {
       return Channel.Add(arg1,arg2);
    }
    public  int Multiply( int arg1, int arg2)
    {
       return Channel.Multiply(arg1,arg2);
    }
    //Rest of the proxy
}

作者在书中还提出了所谓的代理链(Proxy Chaining)技术,实质上就是使得分别实现不同层级接口的代理类形成一个IS-A的继承关系。如上的定义,就可以使 ScientificCalculatorClient继承自SimpleCalculatorClient,而不是继承 ClientBase<IScientificCalculator>:

public  partial  class  SimpleCalculatorClient : ClientBase<IScientificCalculator>,
                                              ISimpleCalculator
{
    public  int Add( int arg1, int arg2)
    {
       return Channel.Add(arg1,arg2);
    }
    //Rest of the proxy
}

public  partial  class  ScientificCalculatorClient : SimpleCalculatorClient,
                                                  IScientificCalculator
{
    public  int Multiply( int arg1, int arg2)
    {
       return Channel.Multiply(arg1,arg2);
    }
    //Rest of the proxy
}

只有这样,如下代码才是正确的:

SimpleCalculatorClient proxy1 =  new SimpleCalculatorClient(  );
SimpleCalculatorClient proxy2 =  new ScientificCalculatorClient(  );
ScientificCalculatorClient proxy3 =  new ScientificCalculatorClient(  );

服务契约的分解与设计

契约分离与接口隔离原则(ISP,Interface Segregation Principle)的基本精神是一致的。ISP原则建议使用多个专门的接口,而不是使用单个接口,这样可以防止接口污染,有利于接口重用。契约分解同样 如此,但它还要受到实现契约代价的约束。

书中提供了服务契约的分解准则。“合理的契约分解可以实现深度特化、松散耦合、精细调整以及契约的重用。这些优势有助于改善整个系统。总的来说,契约分解的目的就是使契约包含的操作尽可能少。”

设计面向服务的系统时,需要平衡两个影响系统的因素(参见图2-1)。一个是实现服务契约的代价,一个则是将服务契约合并或集成为一个高内聚应用程序的代价。


图2-1  平衡服务的个数与规模

定义服务契约时,还要注意到书中所谓的准属性操作(Property-Like Operation)的使用。一言以蔽之,就是如果涉及到对对象状态的管理(在C#中一般体现为属性),则这样的操作不宜被公开为服务操作。原因在于:“ 客户端应该只负责调用操作,而由服务去管理服务对象的状态。”

契约查询

要查询契约,首先需要了解元数据的信息,WCF提供了如下的几个辅助类,位于System.ServiceModel.Description命名空间:

public  enum MetadataExchangeClientMode
{
   MetadataExchange,
   HttpGet
}
class  MetadataSet : ...
{... }
public  class  ServiceEndpointCollection : Collection<ServiceEndpoint>
{... }

public  class  MetadataExchangeClient
{
    public MetadataExchangeClient(  );
    public MetadataExchangeClient(Binding mexBinding);
    public MetadataExchangeClient(Uri address, MetadataExchangeClientMode mode);

    public MetadataSet GetMetadata();
    public MetadataSet GetMetadata(EndpointAddress address);
    public MetadataSet GetMetadata(Uri address,MetadataExchangeClientMode mode);
    //More members
}

public  abstract  class  MetadataImporter
{
    public  abstract ServiceEndpointCollection ImportAllEndpoints(  );
    //More members
}
public  class  WsdlImporter : MetadataImporter
{
    public WsdlImporter(MetadataSet metadata);
    //More members
}
public  class  ServiceEndpoint
{
    public EndpointAddress Address
    {get; set; }
    public Binding Binding
    {get; set; }
    public ContractDescription Contract
    {get; }
    //More members
}
public  class  ContractDescription
{
    public  string Name
    {get; set; }
    public  string Namespace
    {get; set; }
    //More members
}

书中提供了元数据的查询方法,同时还实现了一个专门用于操作元数据的MetadataHelper类。

public  static  class  MetadataHelper
{
    public  static  bool QueryContract( string mexAddress,Type contractType);
    public  static  bool QueryContract( string mexAddress, string contractNamespace,  string contractName);
    //More members
}

可以为MetadataHelper类提供我们希望查询的契约类型,或者提供该契约的名称与命名空间:

string address =  "...";
bool contractSupported = MetadataHelper.QueryContract(address, typeof(IMyContract));

 

具体的实现可以参见书中的描述,完整的实现代码可以到作者的网站(http://www.idesign.net)去下载。







本文转自wayfarer51CTO博客,原文链接:http://blog.51cto.com/wayfarer/280115,如需转载请自行联系原作者

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2015.11.30即将出版新书 Programming WCF Services: Design and Build Maintainable Service-Oriented Systems 4th Paperback: 1018 pages Publisher: Media; 4 edition (November 30, 2015) Language: English ISBN-10: 1491944838 ISBN-13: 978-1491944837 Programming WCF Services is the authoritative, bestselling guide to Microsoft’s unified platform for developing modern, service-oriented applications on Windows. Hailed as the definitive treatment of WCF, this guide provides unique insight, rather than documentation, to help you learn the topics and skills you need for building maintainable, extensible, and reusable WCF-based applications. Authors Juval Löwy—one of the world’s top .NET experts—and Michael Montgomery have revised this edition to include the productivity-enhancing features of .NET Framework 4.6, along with the latest WCF ideas and techniques. By teaching you the why and the how of WCF programming, this book will help you master WCF and make you a better software engineer. Learn WCF’s architecture and essential building blocks, including key concepts such as reliability and transport sessions Use built-in features such as service contracts, instance and concurrency management, transactions, queued services, and security Increase the quality of your WCF services by using design options, tips, and best practices in Löwy’s ServiceModelEx framework Understand the rationale behind particular design decisions, and rarely understood aspects of WCF development Learn why Azure Service Fabric is the killer app for modern DevOps

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值