WCF服务契约的重载与继承详解

17 篇文章 0 订阅

本章主要介绍WCF服务契约的重载与继承,以及设计和分离服务契约的一般原则。

2. 服务契约重载

  基于 WSDL 的操作不支持操作重载,但可以使用 OperationContract 特性的 Name 属性,为操作指定别名,手动地启用操作重载。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.Overloading.Host
{
     [ServiceContract]
     public  interface  IContract
     {
         [OperationContract(Name = "say1" )]
         string  say();
 
         [OperationContract(Name = "say2" )]
         string  say( string  str);
     }
}

  客户端导入契约并生成代理时,导入的操作就会包含定义的别名,也可以在客户端使用导入契约的 Name 属性,指定别名并重载方法,使它与导入的操作名保持一致。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.Overloading.Client
{
     [ServiceContract]
     public  interface  IContract
     {
         [OperationContract(Name = "say1" )]
         string  say();
 
         [OperationContract(Name = "say2" )]
         string  say( string  str);
     }
}
 
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.Overloading.Client
{
     public  class  ClientProxy : ClientBase<IContract>, IContract
     {
         public  ClientProxy()
         { }
 
         public  ClientProxy( string  configurationName) :
             base (configurationName)
         { }
 
         public  string  say()
         {
             return  base .Channel.say();
         }
 
         public  string  say( string  str)
         {
             return  base .Channel.say(str);
         }
     }
}

 

3. 服务契约的继承

  服务契约接口支持继承功能,我们定义一个契约层级,Human为第一级,Man和Woman分别继承Huamn,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.InheritanceReworked.Host
{
     [ServiceContract]
     public  interface  IHuman
     {
         [OperationContract]
         string  HumanSay();
     }
 
     [ServiceContract]
     public  interface  IMan : IHuman
     {
         [OperationContract]
         string  ManSay();
     }
 
     [ServiceContract]
     public  interface  IWoman : IHuman
     {
         [OperationContract]
         string  WomanSay();
     }
}

  在WCF中,一个契约对应一个服务,一个服务对应一个宿主,一个宿主对应多个终结点。上例中定义了三个契约,所以可为每一个契约实现一个服务。在WCF服务契约层级关系中,一个服务类能实现整个契约层级。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.InheritanceReworked.Host
{
     public  class  ManService : IMan
     {
         public  string  HumanSay()
         {
             return  " 我是人,我会思考!" ;
         }
 
         public  string  ManSay()
         {
             return  "我是男人,我力气比较大!" ;
         }
     }
 
     public  class  WomanService : IWoman
     {
         public  string  HumanSay()
         {
             return  " 我是人,我会思考!" ;
         }
 
         public  string  WomanSay()
         {
             return  "我是女人,我爱漂亮!" ;
         }
     }
}

  客户端服务契约的定义,既可以用取消契约层级的方式实现,也可以用恢复契约层级的方式实现。取消契约层级的方式使用 OperationContract 特性中的 Action 与 ResponseAction 属性,使导入的接口定义保留原来定义每个操作的契约名。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[ServiceContract]
public  interface  IScientificCalculator
{
     [OperationContract(Action = ".../ISimpleCalculator/Add" , ReplyAction = ".../ISimpleCalculator/AddResponse" )]
     int  Add( int  arg1, int  arg2);
 
     [OperationContract(Action = ".../IScientificCalculator/Multiply" , ReplyAction = ".../IScientificCalculator/MultiplyResponse" )]
     int  Multiply( int  arg1, int  arg2);
}
 
public  partial  class  ScientificCalculatorClient : ClientBase<IScientificCalculator>, IScientificCalculator
{
     public  int  Add( int  arg1, int  arg2)
     {...}
     public  int  Multiply( int  arg1, int  arg2)
     {...}
}

  使用恢复契约层级的方式,如下所示:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.InheritanceReworked.Client
{
     [ServiceContract]
     public  interface  IHuman
     {
         [OperationContract]
         string  HumanSay();
     }
 
     [ServiceContract]
     public  interface  IMan : IHuman
     {
         [OperationContract]
         string  ManSay();
     }
 
     [ServiceContract]
     public  interface  IWoman : IHuman
     {
         [OperationContract]
         string  WomanSay();
     }
}
 
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.InheritanceReworked.Client
{
     public  class  HumanProxy : ClientBase<IHuman>, IHuman
     {
         public  HumanProxy()
         { }
 
         public  HumanProxy( string  configurationName) :
             base (configurationName)
         { }
 
         public  string  HumanSay()
         {
             return  base .Channel.HumanSay();
         }
 
     }
}
 
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.InheritanceReworked.Client
{
     public  class  ManProxy : ClientBase<IMan>, IMan
     {
         public  ManProxy()
         { }
 
         public  ManProxy( string  configurationName) :
             base (configurationName)
         { }
 
         public  string  HumanSay()
         {
             return  base .Channel.HumanSay();
         }
 
         public  string  ManSay()
         {
             return  base .Channel.ManSay();
         }
     }
}
 
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.InheritanceReworked.Client
{
     public  class  WomanProxy : ClientBase<IWoman>, IWoman
     {
         public  WomanProxy()
         { }
 
         public  WomanProxy( string  configurationName) :
             base (configurationName)
         { }
 
         public  string  HumanSay()
         {
             return  base .Channel.HumanSay();
         }
 
         public  string  WomanSay()
         {
             return  base .Channel.WomanSay();
         }
     }
}


4. 客户端服务契约代理链(Proxy Chaining)

  如果服务契约层级过多,在客户端实现服务契约层级就会显得冗余且复杂,可以使用服务契约代理链(Proxy Chaining)来解决该问题。服务契约代理链为代理建立了 IS-A 关系(继承关系),保证了代码的重用。实现方法:将最顶层的基契约代理直接继承于ClientBase<T>,T为最底层的子接口类型。所有的其他代理则直接继承于它们的上一级代理,同时实现各自的契约接口。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.InheritanceProxyChaining.Client
{
     [ServiceContract]
     public  interface  IAnimal
     {
         [OperationContract]
         string  AnimalSay();
     }
 
     [ServiceContract]
     public  interface  IDog : IAnimal
     {
         [OperationContract]
         string  DogSay();
     }
}
 
using  System;
using  System.ServiceModel;
namespace  WCF.Chapter2.InheritanceProxyChaining.Client
{
     public  class  AnimalClientProxy : ClientBase<IDog>, IAnimal
     {
         public  string  AnimalSay()
         {
             return  base .Channel.AnimalSay();
         }
     }
 
     public  class  DogClientProxy : AnimalClientProxy, IDog
     {
         public  string  DogSay()
         {
             return  base .Channel.DogSay();
         }
     }
}

 

5. 设计和分离服务契约的一般原则

  一个服务契约是逻辑相关的操作的组合。所谓的“逻辑相关”通常指特定的领域逻辑。我们可以将服务契约想象成实体的不同表现。在需求分析之后,一旦识别出实体支持的所有操作,就需要将它们分配给契约。这称为服务契约的分解(Service Contract Factoring)。分解服务契约时,通常需要考虑可重用元素(Reusable Element)。在面向服务的应用程序中,一个可重用的基本单元就是服务契约。合理的契约分解可以实现深度特化、松散耦合、精细调整以及契约的重用。这些优势有助于改善整个系统。总的来说,契约分解的目的就是使契约包含的操作尽可能少。

  设计面向服务的系统时,需要平衡两个影响系统的因素。一个是实现服务契约的代价,一个则是将服务契约合并或集成为一个高内聚应用程序的代价。如果我们定义了太多的细粒度服务契约,虽然它们易于实现,但集成它们的代价未免太高。另一方面,如果我们仅定义了几个复杂而又庞大的服务契约,虽然集成的代价可能会降低,但却制约了契约的实现。如下图所示:

总结服务契约分解的规则和方法如下:

  • 避免设计只具有一个操作的服务契约。一个服务契约体现了实体的特征,如果服务只有一个操作,则过于单调,没有实际的意义。此时,就应该检查它是否使用了太多的参数?它的粒度是否过粗,因此需要分解为多个操作?是否需要将该操作转移到已有的服务契约中?
  • 服务契约成员的最佳数量应介于 3 到 5 之间。如果设计的服务契约包含了多个操作,例如 6 到 9 个,仍然可能工作良好。但是,我们需要判断这些操作是否会因为过度分解而需要合并。如果服务契约定义了 12 个甚至更多的操作,毫无疑问,我们需要将这些操作分解到单独的服务契约中,或者为它们建立契约层级。
  • 避免定义准属性操作(Property -Like Operation)
    ?
    1
    2
    [OperationContract]
    long  GetVetClinicNumber();
    服务契约允许客户端在调用抽象操作时,不用关心具体的实现细节。准属性操作由于无法封装状态的管理,因此在封装性的表现上差强人意。在服务端,我们可以封装读写变量值的业务逻辑,但在理想状态下,我们却不应该干涉客户端对属性的使用。客户端应该只负责调用操作,而由服务去管理服务对象的状态。这种交互方式应该被表示为 DoSomething()样式。
  • 1. 源码下载


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值