Apply SOA Design Patterns with WCF (1) Configuration Centralization (配置集中管理)

Original (原创) by Teddy’s Knowledge Base

Content (目录)

(1) WCF Configuration Centralization (WCF配置集中管理)

(2) WCF Automatic Deployment (WCF自动化部署)

(3) WCF Automatic Service Locating (WCF自动化服务定位)

(4) WCF Database Paging & Sorting (WCF数据库分页和排序)

(5) WCF Based ASP.NET DataSouce Control (基于WCF的数据源控件)

(6) 1 + 2 + 3 + 4 + 5 = ?

English Version

摘要

本文提供一种使用配置集中管理代替配置文件配置WCF服务的方案。

正文

WCF服务有两种配置方式:配置文件和编程方式。配置文件方式,我们大多都很熟悉了,但是,对于SOA,尤其是企业及的SOA,编程方式的配置管理更有利。最大的好处是,它使得配置中控更容易了。)

为什么要使用配置集中管理?

采用配置文件方式时,所有的服务行为和端点的配置都依赖注入的放在应用配置文件中,对于大多数小范围,数量有限的SOA用例来说是足够了。但是,对企业级的,存在部署在更多连通性各不相同的服务器和服务器群的不同绑定信道的服务这种规模的SOA来说,配置文件方式就太难管理了,服务的部署、监控,版本控制等等的成本,都将变得不可接受。

如何实现配置集中管理?

要实现配置集中管理,第一步是要决定所有的配置存储在哪里,可以放在数据库表,统一的分类文件系统目录或诸如SharePoint和DNN这样的特定的内容管理系统中。

第二步是为服务的提供者和消费者定义一个一致的获取配置的API。一个典型的获取WCF服务端点配置的API可能会象下面这样:

1 public sealed class Endpoint
2 {
3     public string Address { get; set; }
4     public string ChannelType { get; set; }
5     public int? CloseTimeout { get; set; }
6     public string FarmAddress { get; set; }
7     public bool MexBindingEnabled { get; set; }
8     public bool? IncludeExceptionDetailInFaults { get; set; }
9     public int? ListenBacklog { get; set; }
10     public int? MaxBufferPoolSize { get; set; }
11     public int? MaxBufferSize { get; set; }
12     public int? MaxConcurrentCalls { get; set; }
13     public int? MaxConcurrentInstances { get; set; }
14     public int? MaxConcurrentSessions { get; set; }
15     public int? MaxConnections { get; set; }
16     public int? MaxReceivedMessageSize { get; set; }
17     public int? OpenTimeout { get; set; }
18     public bool PortSharingEnabled { get; set; }
19     public int? ReceiveTimeout { get; set; }
20     public string SecurityMode { get; set; }
21     public string ClientCredentialTypeName { get; set; }
22     public int? SendTimeout { get; set; }
23     public bool? TransactionFlow { get; set; }
24     public int? TransactionTimeout { get; set; }
25     public string TransferMode { get; set; }
26     public bool? ReliableSessionEnabled { get; set; }
27     public int? ReliableSessionInactivityTimeout { get; set; }
28     public bool? ReliableSessionOrdered { get; set; }
29 }
30 
31 public interface IEndpointProvider
32 {
33     IList<Endpoint> GetServerEndpoints(Type serviceContract);
34     IList<Endpoint> GetClientEndpoints(Type serviceContract);
35 }
一个WCF服务提供者得到要发布的服务的端点的配置后,可以用类似下面的代码以编程方式构造一个用来发布服务的ServiceHost类的实例:
1 var host = new ServiceHost(serviceImplType, BuildBaseAddresses(serviceContracts));
2 var endpoints = EndpointProvider.GetServerEndpoints(serviceContract);
3 foreach (var endpoint in endpoints)
4 {
5     var address = WcfServiceHelper.BuildAddress(endpoint);
6     if (address == default(Uri)) continue;
7 
8     var binding = WcfServiceHelper.BuildBinding(serviceContract, endpoint);
9 
10     if (binding == null) continue;
11 
12     if (!IsBehaviorConfigured<ServiceMetadataBehavior>(host))
13     {
14         var smb = new ServiceMetadataBehavior();
15         host.Description.Behaviors.Add(smb);
16     }
17 
18     if (endpoint.MexBindingEnabled)
19     {
20         host.AddServiceEndpoint(typeof (IMetadataExchange), new CustomBinding(binding), "mex");
21     }
22 
23     if (!IsBehaviorConfigured<ServiceThrottlingBehavior>(host))
24     {
25         var serviceThrottle = new ServiceThrottlingBehavior();
26         if (endpoint.MaxConcurrentCalls.HasValue)
27             serviceThrottle.MaxConcurrentCalls = endpoint.MaxConcurrentCalls.Value;
28         if (endpoint.MaxConcurrentInstances.HasValue)
29             serviceThrottle.MaxConcurrentInstances = endpoint.MaxConcurrentInstances.Value;
30         if (endpoint.MaxConcurrentSessions.HasValue)
31             serviceThrottle.MaxConcurrentSessions = endpoint.MaxConcurrentSessions.Value;
32         host.Description.Behaviors.Add(serviceThrottle);
33     }
34 
35     if (!IsBehaviorConfigured<ServiceDebugBehavior>(host) && endpoint.IncludeExceptionDetailInFaults.HasValue && endpoint.IncludeExceptionDetailInFaults.Value)
36     {
37         var serviceDebug = new ServiceDebugBehavior
38                                {
39                                    IncludeExceptionDetailInFaults =
40                                        endpoint.IncludeExceptionDetailInFaults.Value
41                                };
42         host.Description.Behaviors.Add(serviceDebug);
43     }
44 
45     host.AddServiceEndpoint(serviceContract, binding, address);
46 }
类似的,一个WCF服务消费者可以用类似下面的代码构造一个服务代理的实例:
1 var endpoints = EndpointStore.GetClientEndpoints(typeof(T));
2 if (endpoints.Count > 0)
3 {
4     var endpoint = endpoints[0];
5     var binding = WcfServiceHelper.BuildBinding(typeof(T), endpoint);
6     var address = WcfServiceHelper.BuildAddress(endpoint);
7 
8     if (binding != null && address != null)
9     {
10         var cf = new ChannelFactory<T>(binding, new EndpointAddress(address));
11         return cf.CreateChannel();
12     }
13 }

提示

  • 一般,获取配置API可以实现为一个数据库存储过程包装类,或者本身就是一个WCF服务。
  • 不仅是WCF服务的元数据配置,其他包括数据库连接字串,策略,规则,流程和映射等都能像这样集中管理。
  • 对于服务的消费者,一定要记得关闭ChannelFactory实例,可以参考下面的最佳实践代码,确保ChannelFactoy实例和占用的信道资源得到释放:

 

1 //close channel factory best practice
2 //refer to: http://bloggingabout.net/blogs/erwyn/archive/2006/12/09/WCF-Service-Proxy-Helper.aspx
3 try
4 {
5     channelFactory.Close();
6 }
7 catch (CommunicationException)
8 {
9     channelFactory.Abort();
10 }
11 catch (TimeoutException)
12 {
13     channelFactory.Abort();
14 }
15 catch (Exception)
16 {
17     channelFactory.Abort();
18     throw;
19 }

 

参考

(1) SOA Design Pattern Catalog: http://www.soapatterns.org/

 

//我是结尾符,待续…

posted @ 2009-03-23 23:11  Teddy's Knowledge Base  Views(4912)  Comments(17Edit  收藏  举报