 Configuration Centralization (配置集中管理))
文WCF服务有两种配置方式配置文件和编程方式。配置文件方式我们大多都很熟悉了但是对于SOA尤其是企业及的SOA编程方式的配置管理更有利。最大的好处是它使得配置中控更容易了。)为什么要使用配置集中管理采用配置文件方式时所有的服务行为和端点的配置都依赖注入的放在应用配置文件中对于大多数小范围数量有限的SOA用例来说是足够了。但是对企业级的存在部署在更多连通性各不相同的服务器和服务器群的不同绑定信道的服务这种规模的SOA来说配置文件方式就太难管理了服务的部署、监控版本控制等等的成本都将变得不可接受。如何实现配置集中管理要实现配置集中管理第一步是要决定所有的配置存储在哪里可以放在数据库表统一的分类文件系统目录或诸如SharePoint和DNN这样的特定的内容管理系统中。第二步是为服务的提供者和消费者定义一个一致的获取配置的API。一个典型的获取WCF服务端点配置的API可能会象下面这样1 public sealed class Endpoint2 {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 }3031 public interface IEndpointProvider32 {33 IListEndpoint GetServerEndpoints(Type serviceContract);34 IListEndpoint 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;78 var binding WcfServiceHelper.BuildBinding(serviceContract, endpoint);910 if (binding null) continue;1112 if (!IsBehaviorConfiguredServiceMetadataBehavior(host))13 {14 var smb new ServiceMetadataBehavior();15 host.Description.Behaviors.Add(smb);16 }1718 if (endpoint.MexBindingEnabled)19 {20 host.AddServiceEndpoint(typeof (IMetadataExchange), new CustomBinding(binding), mex);21 }2223 if (!IsBehaviorConfiguredServiceThrottlingBehavior(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 }3435 if (!IsBehaviorConfiguredServiceDebugBehavior(host) endpoint.IncludeExceptionDetailInFaults.HasValue endpoint.IncludeExceptionDetailInFaults.Value)36 {37 var serviceDebug new ServiceDebugBehavior38 {39 IncludeExceptionDetailInFaults 40 endpoint.IncludeExceptionDetailInFaults.Value41 };42 host.Description.Behaviors.Add(serviceDebug);43 }4445 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);78 if (binding ! null address ! null)9 {10 var cf new ChannelFactoryT(binding, new EndpointAddress(address));11 return cf.CreateChannel();12 }13 }提示一般获取配置API可以实现为一个数据库存储过程包装类或者本身就是一个WCF服务。不仅是WCF服务的元数据配置其他包括数据库连接字串策略规则流程和映射等都能像这样集中管理。对于服务的消费者一定要记得关闭ChannelFactory实例可以参考下面的最佳实践代码确保ChannelFactoy实例和占用的信道资源得到释放1 //close channel factory best practice2 //refer to: http://bloggingabout.net/blogs/erwyn/archive/2006/12/09/WCF-Service-Proxy-Helper.aspx3 try4 {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 }