public ContextualFeatureFilterEvaluator(IFeatureFilterMetadata filter, Type appContextType)
        {
            if (filter == null)
            {
                throw new ArgumentNullException(nameof(filter));
            }

            if (appContextType == null)
            {
                throw new ArgumentNullException(nameof(appContextType));
            }

            Type targetInterface = GetContextualFilterInterface(filter, appContextType);

            //
            // Extract IContextualFeatureFilter<T>.EvaluateAsync method.
            if (targetInterface != null)
            {
                MethodInfo evaluateMethod = targetInterface.GetMethod(nameof(IContextualFeatureFilter <object> .EvaluateAsync), BindingFlags.Public | BindingFlags.Instance);

                _evaluateFunc = TypeAgnosticEvaluate(filter.GetType(), evaluateMethod);
            }

            _filter = filter;
        }
Пример #2
0
        private static Type GetContextualFilterInterface(IFeatureFilterMetadata filter, Type appContextType)
        {
            IEnumerable <Type> contextualFilterInterfaces = filter.GetType().GetInterfaces().Where(i => i.IsGenericType && i.GetGenericTypeDefinition().IsAssignableFrom(typeof(IContextualFeatureFilter <>)));

            Type targetInterface = contextualFilterInterfaces.FirstOrDefault(i => i.GetGenericArguments()[0].IsAssignableFrom(appContextType));

            return(targetInterface);
        }
Пример #3
0
        private IFeatureFilterMetadata GetFeatureFilterMetadata(string filterName)
        {
            const string filterSuffix = "filter";

            IFeatureFilterMetadata filter = _filterMetadataCache.GetOrAdd(
                filterName,
                _ =>
            {
                IEnumerable <IFeatureFilterMetadata> matchingFilters = _featureFilters.Where(f =>
                {
                    Type t = f.GetType();

                    string name =
                        ((FilterAliasAttribute)Attribute.GetCustomAttribute(t, typeof(FilterAliasAttribute)))
                        ?.Alias;

                    if (name == null)
                    {
                        name = t.Name.EndsWith(filterSuffix, StringComparison.OrdinalIgnoreCase)
                                ? t.Name.Substring(0, t.Name.Length - filterSuffix.Length)
                                : t.Name;
                    }

                    //
                    // Feature filters can have namespaces in their alias
                    // If a feature is configured to use a filter without a namespace such as 'MyFilter', then it can match 'MyOrg.MyProduct.MyFilter' or simply 'MyFilter'
                    // If a feature is configured to use a filter with a namespace such as 'MyOrg.MyProduct.MyFilter' then it can only match 'MyOrg.MyProduct.MyFilter'
                    if (filterName.Contains('.'))
                    {
                        //
                        // The configured filter name is namespaced. It must be an exact match.
                        return(string.Equals(name, filterName, StringComparison.OrdinalIgnoreCase));
                    }

                    //
                    // We take the simple name of a filter, E.g. 'MyFilter' for 'MyOrg.MyProduct.MyFilter'
                    string simpleName = name.Contains('.') ? name.Split('.').Last() : name;

                    return(string.Equals(simpleName, filterName, StringComparison.OrdinalIgnoreCase));
                });

                if (matchingFilters.Count() > 1)
                {
                    throw new FeatureManagementException(FeatureManagementError.AmbiguousFeatureFilter,
                                                         $"Multiple feature filters match the configured filter named '{filterName}'.");
                }

                return(matchingFilters.FirstOrDefault());
            }
                );

            return(filter);
        }
        private ContextualFeatureFilterEvaluator GetContextualFeatureFilter(string filterName, Type appContextType)
        {
            if (appContextType == null)
            {
                throw new ArgumentNullException(nameof(appContextType));
            }

            ContextualFeatureFilterEvaluator filter = _contextualFeatureFilterCache.GetOrAdd(
                $"{filterName}{Environment.NewLine}{appContextType.FullName}",
                (_) => {
                IFeatureFilterMetadata metadata = GetFeatureFilterMetadata(filterName);

                return(ContextualFeatureFilterEvaluator.IsContextualFilter(metadata, appContextType) ?
                       new ContextualFeatureFilterEvaluator(metadata, appContextType) :
                       null);
            }
                );

            return(filter);
        }
        private async Task <bool> IsEnabledAsync <TContext>(string feature, TContext appContext, bool useAppContext)
        {
            foreach (ISessionManager sessionManager in _sessionManagers)
            {
                bool?readSessionResult = await sessionManager.GetAsync(feature).ConfigureAwait(false);

                if (readSessionResult.HasValue)
                {
                    return(readSessionResult.Value);
                }
            }

            bool enabled = false;

            FeatureSettings settings = await _settingsProvider.GetFeatureSettingsAsync(feature).ConfigureAwait(false);

            if (settings != null)
            {
                //
                // Check if feature is always on
                // If it is, result is true, goto: cache

                if (settings.EnabledFor.Any(featureFilter => string.Equals(featureFilter.Name, "AlwaysOn", StringComparison.OrdinalIgnoreCase)))
                {
                    enabled = true;
                }
                else
                {
                    //
                    // For all enabling filters listed in the feature's state calculate if they return true
                    // If any executed filters return true, return true

                    foreach (FeatureFilterSettings featureFilterSettings in settings.EnabledFor)
                    {
                        IFeatureFilterMetadata filter = GetFeatureFilterMetadata(featureFilterSettings.Name);

                        if (filter == null)
                        {
                            string errorMessage = $"The feature filter '{featureFilterSettings.Name}' specified for feature '{feature}' was not found.";

                            if (!_options.IgnoreMissingFeatureFilters)
                            {
                                throw new FeatureManagementException(FeatureManagementError.MissingFeatureFilter, errorMessage);
                            }
                            else
                            {
                                _logger.LogWarning(errorMessage);
                            }

                            continue;
                        }

                        var context = new FeatureFilterEvaluationContext()
                        {
                            FeatureName = feature,
                            Parameters  = featureFilterSettings.Parameters
                        };

                        //
                        // IContextualFeatureFilter
                        if (useAppContext)
                        {
                            ContextualFeatureFilterEvaluator contextualFilter = GetContextualFeatureFilter(featureFilterSettings.Name, typeof(TContext));

                            if (contextualFilter != null && await contextualFilter.EvaluateAsync(context, appContext).ConfigureAwait(false))
                            {
                                enabled = true;

                                break;
                            }
                        }

                        //
                        // IFeatureFilter
                        if (filter is IFeatureFilter featureFilter && await featureFilter.EvaluateAsync(context).ConfigureAwait(false))
                        {
                            enabled = true;

                            break;
                        }
                    }
                }
            }

            foreach (ISessionManager sessionManager in _sessionManagers)
            {
                await sessionManager.SetAsync(feature, enabled).ConfigureAwait(false);
            }

            return(enabled);
        }
 public static bool IsContextualFilter(IFeatureFilterMetadata filter, Type appContextType)
 {
     return(GetContextualFilterInterface(filter, appContextType) != null);
 }