AppFabric 服务总线发现.docx
- 文档编号:10799869
- 上传时间:2023-02-23
- 格式:DOCX
- 页数:33
- 大小:29.13KB
AppFabric 服务总线发现.docx
《AppFabric 服务总线发现.docx》由会员分享,可在线阅读,更多相关《AppFabric 服务总线发现.docx(33页珍藏版)》请在冰豆网上搜索。
AppFabric服务总线发现
AppFabric服务总线发现
JuvalLowy
下载代码示例
在2010年1月的文章“通过发现查找新WCF”(中,我介绍了WindowsCommunicationFoundation(WCF)4很有价值的发现功能。
WCF发现本质上是一种面向Intranet的技术,因为地址信息是无法通过Internet进行广播的。
不过好在,使用动态地址以及分离地址轴上的客户端和服务同样适用于依靠服务总线接收客户端调用的服务。
幸运的是,您可以使用事件中继绑定替换用户数据报协议(UDP)多播请求并为发现和公告做准备。
这样,您可以将可发现服务的易于部署和服务总线的无阻碍连接这两种优势结合起来。
本文介绍我编写的一个用于支持服务总线发现(使其等效于WCF中内置的发现支持)的小框架,以及我的一组帮助程序类。
它还可以用作运行您自己的发现机制的示例。
AppFabric服务总线背景知识
如果您不熟悉AppFabric服务总线,可以阅读以下几篇过去的文章:
∙“使用.NET服务总线”(2009年4月)
∙“服务总线缓冲区”(2010年5月)
解决方案体系结构
对于WCF的内置发现功能,存在用于发现交换的标准约定。
遗憾的是,这些约定被定义为内部约定。
自定义发现机制的第一步就是定义用于发现请求和回调的约定。
我定义的IServiceBusDiscovery约定如下所示:
1. [ServiceContract]
2.public interface IServiceBusDiscovery
3.{
4. [OperationContract(IsOneWay = true)]
5. void OnDiscoveryRequest(string contractName,string contractNamespace,
6. Uri[] scopesToMatch,Uri replayAddress);
7.}
8.
发现端点支持单一操作IServiceBusDiscovery。
使用OnDiscoveryRequest,客户端可以发现支持某个特定约定的服务端点,就像使用常规WCF那样。
另外,客户端还可以传入一组要匹配的可选作用域。
服务应通过事件中继绑定支持发现端点。
客户端对支持发现端点的服务发出请求,请求这些服务回调客户端提供的回复地址。
服务使用如下定义的IServiceBusDiscoveryCallback回调客户端:
1. [ServiceContract]
2.public interface IServiceBusDiscoveryCallback
3.{
4. [OperationContract(IsOneWay = true)]
5. void DiscoveryResponse(Uri address,string contractName,
6. string contractNamespace, Uri[] scopes);
7.}
8.
客户端提供一个支持IServiceBusDiscoveryCallback的端点,其地址是OnDiscoveryRequest的replayAddress参数。
所用的绑定应当是尽可能接近单播的单向中继绑定。
图1显示了发现顺序。
图1服务总线发现
图1中的第一步是客户端在支持IServiceBusDiscovery的发现端点引发一个发现请求事件。
在事件绑定的作用下,所有可发现服务都会收到此事件。
如果某个服务支持请求的约定,它会通过服务总线回调该客户端(图1中的步骤2)。
客户端收到该服务端点(或多个端点)的地址后,便会继续调用该服务,就像使用常规服务总线调用那样(图1中的步骤3)。
可发现的主机
很显然,支持这样一种发现机制(尤其是针对服务的发现)需要进行大量工作。
使用如下定义的DiscoverableServiceHost类,我得以封装这些工作:
1. public class DiscoverableServiceHost :
ServiceHost,...
2. {
3. public const string DiscoveryPath = "DiscoveryRequests";
4.
5. protected string Namespace {get;}
6.
7. public Uri DiscoveryAddress {get;set;}
8.
9. public NetEventRelayBinding DiscoveryRequestBinding {get;set;}
10.
11. public NetOnewayRelayBinding DiscoveryResponseBinding {get;set;}
12.
13. public DiscoverableServiceHost(object singletonInstance,
14. params Uri[] baseAddresses);
15. public DiscoverableServiceHost(Type serviceType,
16. params Uri[] baseAddresses);
17.}
18.
除发现外,DiscoverableServiceHost还始终将服务端点发布到服务总线注册表。
要实现像使用常规WCF发现那样的发现功能,必须添加一个发现行为和一个WCF发现端点。
这是为了避免再添加其他控制开关,并确保在某一位置有一个一致配置,用于打开或关闭所有发现模式。
DiscoverableServiceHost的使用方法与所有其他依靠服务总线的服务相同:
1. Uri baseAddress =
2. new Uri("sb:
//MyServiceNamespace.servicebus.windows.
3. net/MyService/");
4.
5.ServiceHost host = new DiscoverableServiceHost(typeof(MyService),baseAddress);
6.
7.// Address is dynamic
8.host.AddServiceEndpoint(typeof(IMyContract),new NetTcpRelayBinding(),
9. Guid.NewGuid().ToString());
10.
11.// A host extension method to pass creds to behavior
12.host.SetServiceBusCredentials(...);
13.
14.host.Open();
15.
请注意,使用发现功能时,服务地址可以是完全动态的。
图2提供了DiscoverableServiceHost相关元素的部分实现。
图2实现DiscoverableServiceHost(部分)
1. public class DiscoverableServiceHost :
ServiceHost,...
2. {
3. Uri m_DiscoveryAddress;
4. ServiceHost m_DiscoveryHost;
5.
6. // Extracts the service namespace out of the endpoints or base addresses
7. protected string Namespace
8. {
9. get
10. {...}
11. }
12.
13. bool IsDiscoverable
14. {
15. get
16. {
17. if(Description.Behaviors.Find
= null)
18. {
19. return Description.Endpoints.Any(endpoint =>
20. endpoint is DiscoveryEndpoint);
21. }
22. return false;
23. }
24. }
25.
26. public Uri DiscoveryAddress
27. {
28. get
29. {
30. if(m_DiscoveryAddress == null)
31. {
32. m_DiscoveryAddress =
33. ServiceBusEnvironment.CreateServiceUri("sb",Namespace,DiscoveryPath);
34. }
35. return m_DiscoveryAddress;
36. }
37. set
38. {
39. m_DiscoveryAddress = value;
40. }
41. }
42.
43. public DiscoverableServiceHost(Type serviceType,params Uri[]
44. baseAddresses) :
base(serviceType,baseAddresses)
45. {}
46.
47. void EnableDiscovery()
48. {
49. // Launch the service to monitor discovery requests
50. DiscoveryRequestService discoveryService =
51. new DiscoveryRequestService(Description.Endpoints.ToArray());
52.
53. discoveryService.DiscoveryResponseBinding = DiscoveryResponseBinding;
54.
55. m_DiscoveryHost = new ServiceHost(discoveryService);
56.
57. m_DiscoveryHost.AddServiceEndpoint(typeof(IServiceBusDiscovery),
58. DiscoveryRequestBinding, DiscoveryAddress.AbsoluteUri);
59.
60. m_DiscoveryHost.Open();
61. }
62.
63. protected override void OnOpening()
64. {
65. if(IsDiscoverable)
66. {
67. EnableDiscovery();
68. }
69.
70. base.OnOpening();
71. }
72. protected override void OnClosed()
73. {
74. if(m_DiscoveryHost !
= null)
75. {
76. m_DiscoveryHost.Close();
77. }
78.
79. base.OnClosed();
80. }
81.
82. [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,...]
83. class DiscoveryRequestService :
IServiceBusDiscovery
84. {
85. public DiscoveryRequestService(ServiceEndpoint[] endpoints);
86.
87. public NetOnewayRelayBinding DiscoveryResponseBinding
88. {get;set;}
89. }
90.}
91.
只有服务有发现行为并且至少有一个发现端点时,DiscoverableServiceHost的帮助程序属性IsDiscoverable才会返回true。
DiscoverableServiceHost会覆盖ServiceHost的OnOpening方法。
如果服务可发现,OnOpening会调用EnableDiscovery方法。
EnableDiscovery是DiscoverableServiceHost的核心。
它为名为DiscoveryRequestService的私有单例类创建内部主机(请参见图3)。
图3DiscoveryRequestService类(部分)
1. public class DiscoverableServiceHost :
ServiceHost
2.{
3. [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
4. UseSynchronizationContext = false)]
5. class DiscoveryRequestService :
IServiceBusDiscovery
6. {
7. readonly ServiceEndpoint[] Endpoints;
8.
9. public NetOnewayRelayBinding DiscoveryResponseBinding
10. {get;set;}
11.
12. public DiscoveryRequestService(ServiceEndpoint[] endpoints)
13. {
14. Endpoints = endpoints;
15. }
16.
17. void IServiceBusDiscovery.OnDiscoveryRequest(string contractName,
18. string contractNamespace, Uri[] scopesToMatch, Uri responseAddress)
19. {
20. ChannelFactory
21. new ChannelFactory
22. DiscoveryResponseBinding, new EndpointAddress(responseAddress));
23.
24. IServiceBusDiscoveryCallback callback = factory.CreateChannel();
25.
26. foreach(ServiceEndpoint endpoint in Endpoints)
27. {
28. if(endpoint.Contract.Name == contractName &&
29. endpoint.Contract.Namespace == contractNamespace)
30. {
31. Uri[] scopes = DiscoveryHelper.LookupScopes(endpoint);
32.
33. if(scopesToMatch !
= null)
34. {
35. bool scopesMatched = true;
36. foreach(Uri scope in scopesToMatch)
37. {
38. if(scopes.Any(uri => uri.AbsoluteUri == scope.AbsoluteUri)
39. == false)
40. {
41. scopesMatched = false;
42. break;
43. }
44. }
45. if(scopesMatched == false)
46. {
47. continue;
48. }
49. }
50. callback.DiscoveryResponse(endpoint.Address.Uri,contractName,
51. contractNamespace,scopes);
52. }
53. }
54. (callback as ICommunicationObject).Close();
55. }
56. }
57.}
58.
59.public static class DiscoveryHelper
60.{
61. static Uri[] LookupScopes(ServiceEndpoint endpoint)
62. {
63. Uri[] scopes = new Uri[]{};
64. EndpointDiscoveryBehavior behavior =
65. endpoint.Behaviors.Find
66. if(behavior !
= null)
67. {
68. if(behavior.Scopes.Count > 0)
69. {
70. scopes = behavior.Scopes.ToArray();
71. }
72. }
73. return scopes;
74. }
75. // More members
76.}
77.
DiscoveryRequestService的构造函数接受需要监视其发现请求的服务端点(主要是DiscoverableServiceHost的端点)。
随后EnableDiscovery将一个实现IServiceBusDiscovery的端点添加到主机,因为DiscoveryRequestService实际响应的是来自客户端的发现请求。
该发现端点的地址默认为服务命名空间下的URI“DiscoveryRequests”。
但在打开DiscoverableServiceHost之前,您可以使用DiscoveryAddress属性将此地址更改为任何其他URI。
关闭DiscoverableServiceHost也会关闭发现端点的主机。
图3列出了DiscoveryRequestService的实现。
OnDiscoveryRequest首先创建一个代理,用于回调请求发现的客户端。
所用的绑定是普通NetOnewayRelayBinding,但您可以通过设置DiscoveryResponseBinding属性对此进行控制。
请注意,DiscoverableServiceHost有一个专门针对此用途的属性。
随后,OnDiscoveryRequest对提供给构造函数的端点集合进行迭代。
对于每个端点,它会检查约定是否与发现请求中所请求的约定匹配。
如果约定相匹配,OnDiscoveryRequest将查找与该端点关联的作用域,并验证这些作用域是否与发现请求中的可选作用域匹配。
最后,OnDiscoveryRequest使用该端点的地址、约定和作用域回调客户端。
发现客户端
我针对客户端编写了帮助程序类ServiceBusDiscoveryClient,其定义如下:
1. public class ServiceBusDiscoveryClient :
ClientBase
2. {
3. protected Uri ResponseAddress
4. {get;}
5.
6. public ServiceBusDiscoveryClient(string serviceNamespace,string secret);
7.
8. public ServiceBusDiscoveryClient(string endpointName);
9. public ServiceBusDiscoveryClient(NetOnewayRelayBinding binding,
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- AppFabric 服务总线发现 服务 总线 发现
