/// <summary>
        /// Initializes a new instance of the <see cref="CustomThrottlingHandler"/> class.
        /// </summary>
        /// <param name="log">Log</param>
        /// <param name="syncSettingsReader">synchronous settings reader</param>
        public CustomThrottlingHandler(ILog log, ISettingsReader syncSettingsReader)
            : base()
        {
            this.log   = log;
            this.alert = (string msg, Exception ex) => this.log.LogError(msg, ex);

            // Read the rate limit from the configuration
            long rateLimitPerMinute = Convert.ToInt64(syncSettingsReader.ReadValue("RateLimitPerMinute"));

            // The policy reads the threshold from the settings reader
            ThrottlePolicy throttlePolicyOnStartup = new ThrottlePolicy(perMinute: rateLimitPerMinute)
            {
                ClientThrottling = true
            };

            // Bug fixes <-- WebApiThrottle has a bug. Setting these to null tells WebApiThrottle that we do not do ip-based nor endpoint-based
            // rate limiting. We avoid the bug this way.
            throttlePolicyOnStartup.IpRules       = null;
            throttlePolicyOnStartup.EndpointRules = null;

            // Assign the static throttle policy on startup. Throttle on clients (meaning app keys).
            this.Policy = throttlePolicyOnStartup;

            this.Repository       = new CacheRepository();
            this.Logger           = new TracingThrottleLogger(this.log);
            this.PolicyRepository = new PolicyCacheRepository();

            // Set the throttle policy to update every 24 hours
            this.srvThrottlePolicy = new SelfRefreshingVar <IPolicyRepository>(this.PolicyRepository, TimeUtils.TwentyFourHours, this.RefreshingThottlePolicy, this.alert);
        }
        internal IConfigurationSetting GetConfigSettingFor(Type type)
        {
            var potentialMatches = GetPossibleKeysFor(type)
                                   .ToDictionary(k => k, k => _settingsReader.ReadValue(k))
                                   .Where(kvp => kvp.Value != null)
                                   .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            var potentialMatchCount = potentialMatches.Count();

            if (potentialMatchCount == 0)
            {
                throw new MissingSettingException(type);
            }
            if (potentialMatchCount > 1)
            {
                throw new AmbiguousSettingException(type, potentialMatches);
            }

            var setting = potentialMatches.Single();
            var candidateSettingObject = ConstructSettingObject(type, setting.Value);

            _logger.Log("Setting for type {0} loaded from settings provider (key: {1}; value: {2})", type.Name, setting.Key, candidateSettingObject.SanitizedValue);

            string overriddenValue;

            if (_settingsOverrider.TryFindOverrideFor(setting.Key, out overriddenValue))
            {
                var overriddenSettingObject = ConstructSettingObject(type, overriddenValue);
                _logger.Log("Setting for type {0} overridden (key: {1}; value: {2})", type.Name, setting.Key, overriddenSettingObject.SanitizedValue);
                return(overriddenSettingObject);
            }

            return(candidateSettingObject);
        }
        internal IConfigurationSetting GetConfigSettingFor(Type type)
        {
            var settingValueStrings = GetPossibleKeysFor(type)
                                      .Select(k => _settingsReader.ReadValue(k))
                                      .NotNull()
                                      .ToArray();

            var matchingSettingCount = settingValueStrings.Count();

            if (matchingSettingCount == 0)
            {
                throw new MissingSettingException(type);
            }
            if (matchingSettingCount > 1)
            {
                throw new AmbiguousSettingException(type, settingValueStrings);
            }

            var settingValueString = settingValueStrings.Single();

            return(ConstructSettingObject(type, settingValueString));
        }