优秀代码学习之configSections
Microsoft.AppFabricCAT.Samples.Azure.TransientFaultHandling库是针对Windows Azure下部分服务,由于网络瞬断导致应用出错而推出的一套重试解决方案,这些服务包括SQL Azure/ServiceBus/AzureStorage等;本篇主要是学习该类库下的配置方式,其核心功能代码暂不涉及。
下面是Demo中给出的配置示例,configSections节点集定义了一个节点,该节点自身有属性,还有一组子节点,看起来应该是一个数组。当然这不是最完整的,知道该库的实现方式以及支持哪些功能,还得从代码中入手。
<configuration> <configSections> <section name="RetryPolicyConfiguration" type="SubjectConfiguration.Configuration.RetryPolicyConfigurationSettings, SubjectConfiguration" /> </configSections> <RetryPolicyConfiguration defaultPolicy="FixedIntervalDefault" defaultSqlConnectionPolicy="FixedIntervalDefault" defaultSqlCommandPolicy="FixedIntervalDefault" defaultStoragePolicy="IncrementalIntervalDefault" defaultCommunicationPolicy="IncrementalIntervalDefault"> <add name="FixedIntervalDefault" maxRetryCount="3" retryInterval="3000"/> <add name="IncrementalIntervalDefault" maxRetryCount="3" retryInterval="100" retryIncrement="50" /> <add name="ExponentialIntervalDefault" maxRetryCount="3" minBackoff="100" maxBackoff="1000" deltaBackoff="100" /> </RetryPolicyConfiguration> </configuration>
RetryPolicyConfigurationSettings类是整个配置的入口,类的最上面部分定义了一些常量,包括私有和公有的。私有常量DefaultXXXX的值,与App.Config中的RetryPolicyConfiguration节点属性一一对应。公有常量SectionName则是自身的名称。
class RetryPolicyConfigurationSettings { #region Private members private const string DefaultPolicyProperty = "defaultPolicy"; private const string DefaultSqlConnectionPolicyProperty = "defaultSqlConnectionPolicy"; private const string DefaultSqlCommandPolicyProperty = "defaultSqlCommandPolicy"; private const string DefaultStoragePolicyProperty = "defaultStoragePolicy"; private const string DefaultCommunicationPolicyProperty = "defaultCommunicationPolicy"; #endregion #region Public members /// <summary> /// The name of the configuration section represented by this type. /// </summary> public const string SectionName = "RetryPolicyConfiguration"; #endregion }
紧接着是一批public属性,这些属性借助自定义Attribute:ConfigurationProperty,实现从配置文件到对象的映射,并且提供了IsRequired检查;属性Policies对应的是一个ConfigurationCollection,集合的类型是RetryPolicyCollection,而集合内的每一个元素又是一个个RetryPolicyInfo对象。也就是说,想要在App.Config(Web.config)中配置一个强类型的数组,需要创建两个类支持。
class RetryPolicyConfigurationSettings { #region Public properties /// <summary> /// Gets or sets the name of the default general-purpose retry policy. /// </summary> [ConfigurationProperty(DefaultPolicyProperty, IsRequired = true)] public string DefaultPolicy { get { return (string)base[DefaultPolicyProperty]; } set { base[DefaultPolicyProperty] = value; } } /// <summary> /// Gets or sets the name of a retry policy dedicated to handling transient conditions with SQL connections. /// </summary> [ConfigurationProperty(DefaultSqlConnectionPolicyProperty, IsRequired = false)] public string DefaultSqlConnectionPolicy { get { return (string)base[DefaultSqlConnectionPolicyProperty]; } set { base[DefaultSqlConnectionPolicyProperty] = value; } } /// <summary> /// Gets or sets the name of a retry policy dedicated to handling transient conditions with SQL commands. /// </summary> [ConfigurationProperty(DefaultSqlCommandPolicyProperty, IsRequired = false)] public string DefaultSqlCommandPolicy { get { return (string)base[DefaultSqlCommandPolicyProperty]; } set { base[DefaultSqlCommandPolicyProperty] = value; } } /// <summary> /// Gets or sets the name of a retry policy dedicated to handling transient conditions in Windows Azure storage services. /// </summary> [ConfigurationProperty(DefaultStoragePolicyProperty, IsRequired = false)] public string DefaultStoragePolicy { get { return (string)base[DefaultStoragePolicyProperty]; } set { base[DefaultStoragePolicyProperty] = value; } } /// <summary> /// Gets or sets the name of a retry policy dedicated to handling transient conditions in the WCF communication infrastructure. /// </summary> [ConfigurationProperty(DefaultCommunicationPolicyProperty, IsRequired = false)] public string DefaultCommunicationPolicy { get { return (string)base[DefaultCommunicationPolicyProperty]; } set { base[DefaultCommunicationPolicyProperty] = value; } } /// <summary> /// Returns a collection of retry policy definitions represented by the <see cref="RetryPolicyInfo"/> object instances. /// </summary> [ConfigurationProperty("", Options = ConfigurationPropertyOptions.IsDefaultCollection)] [ConfigurationCollection(typeof(RetryPolicyInfo))] public RetryPolicyCollection Policies { get { return (RetryPolicyCollection)base[String.Empty]; } } #endregion }
最后是一个公开的方法,根据policyName在Policies中找到匹配的RetryPolicyInfo,然后通过RetryPolicyInfo创建一个RetryPolicy<T>;如果找不到匹配项,则返回Null。
class RetryPolicyConfigurationSettings { /// <summary> /// Returns an instance of the <see cref="RetryPolicy"/> object initialized for a given policy name. /// </summary> /// <typeparam name="T">The type implementing the <see cref="ITransientErrorDetectionStrategy"/> interface which is responsible for detecting transient conditions.</typeparam> /// <param name="policyName">The name under which a retry policy definition is registered in the application configuration.</param> /// <returns>The retry policy initialized from the specified policy definition, or a null reference if no such policy definition was found.</returns> public RetryPolicy<T> GetRetryPolicy<T>(string policyName) where T : ITransientErrorDetectionStrategy, new() { RetryPolicy<T> retryPolicy = null; if (!String.IsNullOrEmpty(policyName) && Policies.Contains(policyName)) { RetryPolicyInfo retryPolicyInfo = Policies.Get(policyName); return retryPolicyInfo != null ? retryPolicyInfo.CreatePolicy<T>() : null; } return retryPolicy; } }
这一系列配置如何在内存中缓存起来呢?常规的做法一般都是声明一个单例类。ApplicationConfiguration中的私有变量currentConfiguration是自己唯一的一个实例,public static属性Current利用double check实现了单例。正如类注释所说,提供强类型配置节点的缓存访问,适用于同类场景,代码能够高度重用。
namespace SubjectConfiguration.Configuration { #region Using references using System; using System.Collections.Generic; using System.Configuration; #endregion /// <summary> /// Helper class that exposes all strongly-typed configuration sections and also provides an ability to save the /// configuration changes for custom sections. /// </summary> public sealed class ApplicationConfiguration { #region Private members /// <summary> /// A pre-initialized instance of the current configuration. /// </summary> private static volatile ApplicationConfiguration currentConfiguration; /// <summary> /// A lock object. /// </summary> private static readonly object initLock = new object(); /// <summary> /// A dictionary object containing cached instances of the configuration sections. /// </summary> private readonly IDictionary<string, ConfigurationSection> configSectionCache; /// <summary> /// A lock object for the configuration section cache. /// </summary> private readonly object configSectionCacheLock = new object(); #endregion #region Constructors /// <summary> /// Initializes a new instance of the ApplicationConfiguration class using default configuration source. /// </summary> private ApplicationConfiguration() { this.configSectionCache = new Dictionary<string, ConfigurationSection>(16); } #endregion #region Public properties /// <summary> /// Returns an instance of the ApplicationConfiguration class by enforcing a singleton design pattern with a lazy initialization. /// </summary> public static ApplicationConfiguration Current { get { if (null == currentConfiguration) { lock (initLock) { // If we were the second process attempting to initialize the currentConfiguration member, when we enter // this critical section let's check once again if the member was not already initialized by the another // process. As the lock will ensure a serialized execution, we need to make sure that we don't attempt // to re-initialize the ready-to-go instance. if (null == currentConfiguration) { currentConfiguration = new ApplicationConfiguration(); } } } return currentConfiguration; } } #endregion #region Public methods /// <summary> /// Returns a configuration section defined by the given type <typeparamref name="T"/> and name that corresponds to the type's fully qualified name. /// </summary> /// <typeparam name="T">The type of the configuration section.</typeparam> /// <returns>An instance of the type <typeparamref name="T"/> containing the configuration section or a null reference if configuration section was not found.</returns> public T GetConfigurationSection<T>() where T : ConfigurationSection { return GetConfigurationSection<T>(typeof(T).FullName); } /// <summary> /// Returns a configuration section defined by the given type <typeparamref name="T"/> and specified section name. /// </summary> /// <typeparam name="T">The type of the configuration section.</typeparam> /// <param name="sectionName">The name of the configuration section.</param> /// <returns>An instance of the type <typeparamref name="T"/> containing the configuration section or a null reference if configuration section was not found.</returns> public T GetConfigurationSection<T>(string sectionName) where T: ConfigurationSection { ConfigurationSection configSection = null; if (!this.configSectionCache.TryGetValue(sectionName, out configSection)) { lock (this.configSectionCacheLock) { if (!this.configSectionCache.TryGetValue(sectionName, out configSection)) { configSection = ConfigurationManager.GetSection(sectionName) as ConfigurationSection; if (configSection != null) { this.configSectionCache.Add(sectionName, configSection); } } } } return configSection as T; } /// <summary> /// Signals the configuration manager to unload all currently loaded configuration sections by removing them from in-memory cache. /// </summary> public void Unload() { lock (this.configSectionCacheLock) { this.configSectionCache.Clear(); } } #endregion } }

浙公网安备 33010602011771号