操作重载与契约层级


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

    操作重载

    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( );

本文作者:



相关阅读:
由document.body和document.documentElement想到的
脚本收藏iframe
linux如何修改主机名
Windows下JSP开发环境的配置
MooTools教程(9):输入过滤-字符串
系统默认的MySQL用户名消失的解决方法
js右键菜单效果代码
复制的概述和术语
ASP中FSO的神奇功能 - 权限许可
ASP.NET开发电子商务网站学习经验
创建ASP.NET WEB自定义控件——例程1
ssh超时断开的解决方法
PHP基础教程(5):PHP字符串
【F#2.0系列】使用F#的List
快速导航

Copyright © 2016 phpStudy |