コード例 #1
0
        ///<inheritdoc/>
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            if (Double.TryParse(data.Percentage.ToString(), out double percentage))
            {
                string claimType = data.ClaimType?.ToString();

                if (claimType != null && percentage > 0)
                {
                    var user = _httpContextAccessor
                               .HttpContext
                               .User;

                    if (user != null && user.Identity.IsAuthenticated)
                    {
                        var value = user.FindFirst(claimType)?.Value;

                        if (value != null)
                        {
                            // this only apply when claim exist, we apply also some entropy to current claim value.
                            // adding this entropy ensure that not all features with gradual rollout for claim value are enabled/disable at the same time for the same user.

                            var assignedPartition = _partitioner.ResolvePartition(featureName + value, partitions: 100);
                            return(assignedPartition <= percentage);
                        }
                    }
                }
            }

            return(false);
        }
コード例 #2
0
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            string headerName = data.HeaderName;

            if (Double.TryParse(data.Percentage.ToString(), out double percentage))
            {
                if (percentage > 0d)
                {
                    var values = _httpContextAccessor.HttpContext
                                 .Request
                                 .Headers[headerName];

                    var headerValue = values != StringValues.Empty ? values.First() : NO_HEADER_DEFAULT_VALUE;

                    var assignedPartition = Partitioner.ResolveToLogicalPartition(headerValue, Partitions);
                    return(assignedPartition <= percentage);
                }
            }

            return(false);
        }
コード例 #3
0
        /// <inheritdoc/>
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            string headerName = data.HeaderName;

            if (Double.TryParse(data.Percentage.ToString(), out double percentage))
            {
                if (percentage > 0d)
                {
                    var values = _httpContextAccessor.HttpContext
                                 .Request
                                 .Headers[headerName];

                    if (values != StringValues.Empty)
                    {
                        // this only apply when header exist, we apply also some entropy to header value.
                        // adding this entropy ensure that not all features with gradual rollout for claim value are enabled/disable at the same time for the same user.

                        var assignedPartition = _partitioner.ResolvePartition(featureName + values.First(), partitions: 100);
                        return(assignedPartition <= percentage);
                    }
                }
            }

            return(false);
        }
コード例 #4
0
        ///<inheritdoc/>
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            if (Double.TryParse(data.Percentage.ToString(), out double percentage))
            {
                if (percentage > 0d)
                {
                    var sessionId = _httpContextAccessor
                                    .HttpContext
                                    .Session
                                    .Id;

                    // we apply also some entropy to sessionid value.
                    // adding this entropy ensure that not all features with gradual rollout for claim value are enabled/disable at the same time for the same user.

                    var assignedPartition = _partitioner.ResolvePartition(featureName + sessionId);
                    return(assignedPartition <= percentage);
                }
            }

            return(false);
        }
コード例 #5
0
ファイル: UserNameToggle.cs プロジェクト: sitwalkstand/Esquio
        ///<inheritdoc/>
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var currentUserName = await _userNameProviderService
                                  .GetCurrentUserNameAsync();

            if (currentUserName != null)
            {
                var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

                var toggle = feature.GetToggle(this.GetType().FullName);
                var data   = toggle.GetData();

                string activeUserNames = data.Users?.ToString();

                if (activeUserNames != null)
                {
                    var tokenizer = new StringTokenizer(activeUserNames, EsquioConstants.DEFAULT_SPLIT_SEPARATOR);

                    return(tokenizer.Contains(
                               currentUserName, StringSegmentComparer.OrdinalIgnoreCase));
                }
            }

            return(false);
        }
コード例 #6
0
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            if (Double.TryParse(data.Percentage.ToString(), out double percentage))
            {
                string claimType = data.ClaimType?.ToString();

                if (claimType != null && percentage > 0)
                {
                    var user = _httpContextAccessor
                               .HttpContext
                               .User;

                    if (user != null && user.Identity.IsAuthenticated)
                    {
                        var value = user.FindFirst(claimType)?.Value ?? NO_CLAIMTYPE_DEFAULT_VALUE;

                        var assignedPartition = Partitioner.ResolveToLogicalPartition(value, Partitions);
                        return(assignedPartition <= percentage);
                    }
                }
            }

            return(false);
        }
コード例 #7
0
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var    toggle      = feature.GetToggle(typeof(ServerIpAddressToggle).FullName);
            var    data        = toggle.GetData();
            var    ipAddress   = _contextAccessor.HttpContext.Connection.LocalIpAddress;
            var    bytes       = ipAddress.GetAddressBytes();
            string ipAddresses = data.IpAddresses;

            _logger.LogDebug($"{nameof(ServerIpAddressToggle)} is trying to verify if '{ipAddress}' is in the IP list.");

            var tokenizer = new StringTokenizer(ipAddresses, EsquioConstants.DEFAULT_SPLIT_SEPARATOR);

            foreach (var token in tokenizer)
            {
                if (token.HasValue &&
                    IPAddress.TryParse(token, out IPAddress address) &&
                    address.GetAddressBytes().SequenceEqual(bytes))
                {
                    _logger.LogInformation($"The server IP address '{ipAddress}' is in the IP '{ipAddresses}' list.");

                    return(true);
                }
            }

            _logger.LogInformation($"The server IP address '{ipAddress}' is not in the IP list.");

            return(false);
        }
コード例 #8
0
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            if (Double.TryParse(data.Percentage.ToString(), out double percentage))
            {
                if (percentage > 0d)
                {
                    try
                    {
                        var sessionId = _httpContextAccessor
                                        .HttpContext
                                        .Session
                                        .Id;

                        var assignedPartition = Partitioner.ResolveToLogicalPartition(sessionId, Partitions);
                        return(assignedPartition <= percentage);
                    }
                    catch (InvalidOperationException)
                    {
                        _logger.LogError($"The toggle {nameof(GradualRolloutSessionToggle)} can't perform rollout on Session because  Session has not been configured for this application or request.");
                    }
                }
            }

            return(false);
        }
コード例 #9
0
        ///<inheritdoc/>
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore
                          .FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            string claimType     = data.ClaimType?.ToString();
            string allowedValues = data.ClaimValues?.ToString();

            if (claimType != null
                &&
                allowedValues != null)
            {
                var user = _httpContextAccessor.HttpContext.User;
                if (user != null && user.Identity.IsAuthenticated)
                {
                    var value = user.FindFirst(claimType)?
                                .Value;

                    if (value != null)
                    {
                        var tokenizer = new StringTokenizer(allowedValues, EsquioConstants.DEFAULT_SPLIT_SEPARATOR);

                        return(tokenizer.Contains(
                                   value, StringSegmentComparer.OrdinalIgnoreCase));
                    }
                }
            }

            return(false);
        }
コード例 #10
0
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            string allowedCountries = data.Countries;
            string accessKey        = data.AccessKey;

            var currentCountry = await _locationProviderService
                                 .GetCountryCode(GetRemoteIpAddress(), accessKey);

            if (allowedCountries != null
                &&
                currentCountry != null
                &&
                accessKey != null)
            {
                var tokenizer = new StringTokenizer(allowedCountries, EsquioConstants.DEFAULT_SPLIT_SEPARATOR);

                return(tokenizer.Contains(currentCountry, StringSegmentComparer.OrdinalIgnoreCase));
            }

            return(false);
        }
コード例 #11
0
        ///<inheritdoc/>
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            string headerName    = data.HeaderName?.ToString();
            string allowedValues = data.HeaderValues?.ToString();

            if (headerName != null
                &&
                allowedValues != null)
            {
                var values = _httpContextAccessor.HttpContext
                             .Request
                             .Headers[headerName];

                foreach (var item in values)
                {
                    var tokenizer = new StringTokenizer(allowedValues, SPLIT_SEPARATOR);

                    if (tokenizer.Contains(item, StringSegmentComparer.OrdinalIgnoreCase))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
コード例 #12
0
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(typeof(HostNameToggle).FullName);
            var data   = toggle.GetData();

            string hostNames = data.HostNames;

            var hostName = _contextAccessor.HttpContext.Request.Host.Host;

            _logger.LogDebug($"{nameof(HostNameToggle)} is trying to verify if '{hostName}' is in the hostNames list.");

            var tokenizer = new StringTokenizer(hostNames, EsquioConstants.DEFAULT_SPLIT_SEPARATOR);

            foreach (var token in tokenizer)
            {
                if (token.HasValue && token.Value.Equals(hostName, StringComparison.InvariantCultureIgnoreCase))
                {
                    _logger.LogInformation($"The hostname '{hostName}' is in the hostnames '{hostNames}' list.");

                    return(true);
                }
            }

            _logger.LogInformation($"The hostname '{hostName}' is not in the hostnames list.");

            return(false);
        }
コード例 #13
0
        /// <inheritdoc/>
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore
                          .FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            if (Double.TryParse(data.Percentage.ToString(), out double percentage))
            {
                if (percentage > 0)
                {
                    var currentUserName = await _userNameProviderService
                                          .GetCurrentUserNameAsync();

                    if (currentUserName != null)
                    {
                        // this only apply for authenticted users, we apply some entropy to currentUserName.
                        // adding this entropy ensure that not all features with gradual rollout for username are enabled/disable at the same time for the same user.

                        var assignedPartition = _partitioner.ResolvePartition(featureName + currentUserName, partitions: 100);

                        return(assignedPartition <= percentage);
                    }
                }
            }

            return(false);
        }
コード例 #14
0
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(typeof(UserAgentBrowserToggle).FullName);
            var data   = toggle.GetData();

            var allowedBrowsers = data.Browsers.ToString();
            var currentBrowser  = GetCurrentBrowser();

            if (allowedBrowsers != null && !String.IsNullOrEmpty(currentBrowser))
            {
                _logger.LogDebug($"{nameof(UserAgentBrowserToggle)} is trying to verify if {currentBrowser} is satisfying allowed browser configuration.");

                var tokenizer = new StringTokenizer(allowedBrowsers, split_characters);

                foreach (var segment in tokenizer)
                {
                    if (segment.Value?.IndexOf(currentBrowser, StringComparison.InvariantCultureIgnoreCase) >= 0)
                    {
                        _logger.LogInformation($"The browser {currentBrowser} is satisfied using {allowedBrowsers} configuration.");

                        return(true);
                    }
                }
            }

            _logger.LogInformation($"The browser {currentBrowser} is not allowed using current toggle configuration.");

            return(false);
        }
コード例 #15
0
ファイル: FromToToggle.cs プロジェクト: mitch-b/Esquio
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            var fromDate = DateTime.ParseExact(data.From.ToString(), FORMAT_DATE, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
            var toDate   = DateTime.ParseExact(data.To.ToString(), FORMAT_DATE, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
            var now      = DateTime.UtcNow;

            if (now > fromDate && now < toDate)
            {
                return(true);
            }
            return(false);
        }
コード例 #16
0
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            string allowedCountries = data.Countries;
            var    currentCountry   = await _locationProviderService
                                      .GetCountryName(GetRemoteIpAddress());

            if (allowedCountries != null
                &&
                currentCountry != null)
            {
                var tokenizer = new StringTokenizer(allowedCountries, split_characters);

                return(tokenizer.Contains(currentCountry, StringSegmentComparer.OrdinalIgnoreCase));
            }

            return(false);
        }
コード例 #17
0
        public async Task <bool> IsActiveAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            var feature = await _featureStore.FindFeatureAsync(featureName, productName, cancellationToken);

            var toggle = feature.GetToggle(this.GetType().FullName);
            var data   = toggle.GetData();

            if (Double.TryParse(data.Percentage.ToString(), out double percentage))
            {
                if (percentage > 0)
                {
                    var currentUserName = await _userNameProviderService
                                          .GetCurrentUserNameAsync() ?? AnonymousUser;

                    var assignedPartition = Partitioner.ResolveToLogicalPartition(currentUserName, Partitions);

                    return(assignedPartition <= percentage);
                }
            }

            return(false);
        }
コード例 #18
0
        public async Task <bool> IsEnabledAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            try
            {
                var totalTime = ValueStopwatch.StartNew();

                _diagnostics.BeginFeatureEvaluation(featureName, productName);

                var feature = await _featureStore
                              .FindFeatureAsync(featureName, productName, cancellationToken);

                if (feature == null)
                {
                    _diagnostics.FeatureEvaluationNotFound(featureName, productName);
                    return(_options.NotFoundBehavior == NotFoundBehavior.SetEnabled);
                }

                if (!feature.IsEnabled)
                {
                    _diagnostics.FeatureEvaluationDisabled(featureName, productName);
                    return(false);
                }

                var enabled = true;
                var toggles = feature.GetToggles();

                foreach (var toggle in toggles)
                {
                    _diagnostics.BeginTogglevaluation(featureName, productName, toggle.Type);

                    var active         = false;
                    var evaluationTime = ValueStopwatch.StartNew();

                    var toggleInstance = _toggleActivator
                                         .CreateInstance(toggle.Type);

                    if (toggleInstance != null)
                    {
                        active = await toggleInstance?.IsActiveAsync(featureName, productName, cancellationToken);
                    }

                    _diagnostics.Togglevaluation(featureName, productName, toggle.Type, (long)evaluationTime.GetElapsedTime().TotalMilliseconds);
                    _diagnostics.EndTogglevaluation(featureName, productName, toggle.Type, active);

                    if (!active)
                    {
                        _diagnostics.ToggleNotActive(featureName, toggle.Type);

                        enabled = false;
                        break;
                    }
                }

                _diagnostics.EndFeatureEvaluation(featureName, productName, (long)totalTime.GetElapsedTime().TotalMilliseconds, enabled);

                return(enabled);
            }
            catch (Exception exception)
            {
                _diagnostics.FeatureEvaluationThrow(featureName, productName, exception);

                if (_options.OnErrorBehavior == OnErrorBehavior.Throw)
                {
                    throw;
                }

                return(_options.OnErrorBehavior == OnErrorBehavior.SetEnabled);
            }
        }
コード例 #19
0
        public async Task <bool> IsEnabledAsync(string featureName, string productName = null, CancellationToken cancellationToken = default)
        {
            try
            {
                var totalTime = ValueStopwatch.StartNew();

                Log.FeatureServiceProcessingBegin(_logger, featureName, productName);

                var feature = await _featureStore
                              .FindFeatureAsync(featureName, productName, cancellationToken);

                if (feature == null)
                {
                    Log.FeatureServiceNotFoundFeature(_logger, featureName, productName);
                    return(_options.NotFoundBehavior == NotFoundBehavior.SetEnabled);
                }

                if (!feature.IsEnabled)
                {
                    Log.FeatureServiceDisabledFeature(_logger, featureName, productName);
                    return(false);
                }

                var enabled = true;
                var toggles = feature.GetToggles();

                foreach (var toggle in toggles)
                {
                    var active         = false;
                    var evaluationTime = ValueStopwatch.StartNew();

                    var toggleInstance = _toggleActivator
                                         .CreateInstance(toggle.Type);

                    if (toggleInstance != null)
                    {
                        active = await toggleInstance?.IsActiveAsync(featureName, productName, cancellationToken);
                    }

                    Counters.Instance
                    .ToggleEvaluationTime(
                        featureName: featureName,
                        toggleName: toggle.Type,
                        elapsedMilliseconds: evaluationTime.GetElapsedTime().TotalMilliseconds);

                    if (!active)
                    {
                        Log.FeatureServiceToggleIsNotActive(_logger, featureName, productName);
                        enabled = false;
                        break;
                    }
                }

                Counters.Instance
                .FeatureEvaluationTime(
                    featureName: featureName,
                    elapsedMilliseconds: totalTime.GetElapsedTime().TotalMilliseconds);

                return(enabled);
            }
            catch (Exception exception)
            {
                Log.FeatureServiceProcessingFail(_logger, featureName, productName, exception);

                if (_options.OnErrorBehavior == OnErrorBehavior.Throw)
                {
                    throw;
                }

                return(_options.OnErrorBehavior == OnErrorBehavior.SetEnabled);
            }
        }