IFeatureDefinitionProvider 用于从 SQL Server 中选择功能

Phi*_*ley 6 c# .net-core

使用FeatureManagement.NET Core 3.1 中的功能,我正在尝试编写一个自定义数据库功能提供程序,它将提取功能以及它们是否从 SQL Server 数据库启用。为此,Microsoft 文档说您需要实现该IFeatureDefinitionProvider接口。

您需要返回一个FeatureDefinition不包含该功能是否启用但包含IEnumerable<FeatureFilterConfiguration>. 网上没有任何示例,因为该功能非常新,甚至查看 Azure 实现(他们的两个建议实现之一以及 appsettings.json 不适用于此特定用例)也非常令人困惑。FeatureDefinitionEnabledFor的文档没有提供任何有用的信息。

有谁知道如何Microsoft.FeatureManagement在 .NET Core 3.1 中使用从数据库中提取特征数据?

Luc*_*ain 10

你是对的,这些例子和教程非常浅薄、令人困惑,而且没有澄清任何概念。然而,我忍不住注意到上面建议的示例仅处理配置设置、JSON 等,但很难用于您的目的,即查询 SQL Server 并返回功能的状态。您需要的是一个如何实现接口IFeatureDefinitionProvider并能够灵活地查询SQL Server数据库的示例。这就是我要做的方式,不一定使用实体框架,ADO.NET 就足够了:

namespace FeatureDefinitionProviderDemo
{
    using System;
    using System.Collections.Generic;
    using System.Threading.Tasks;
    using Microsoft.FeatureManagement;

    public class FeatureDefinitionProvider : IFeatureDefinitionProvider
    {
        private const string FirstFeatureName = "FirstFeature";
        private const string SecondFeatureName = "SecondFeature";
        private const string ThirdFeatureName = "ThirdFeature";

        public Task<FeatureDefinition> GetFeatureDefinitionAsync(string featureName)
        {
            // YOU SUPPOSEDLY GO ASYNCHRONOUSLY TO THE DATABASE AND TAKE THE GIVEN FEATURE PROPERTIES
            // NOTE: part of the following is dummy
            var featureDefinition = featureName switch // NOTE: I'm using new C# switch expression here
            {
                // let's say the feature is boolean and it is enabled
                FirstFeatureName => CreateEnabledFeatureDefinition(featureName),

                // let's say the feature is boolean and it is disabled
                SecondFeatureName => CreateDisabledFeatureDefinition(featureName),

                // let's say this one is a 50% percentage
                ThirdFeatureName => CreatePercentageFeatureDefinition(featureName, 50),

                _ => throw new NotSupportedException("The requested feature is not supported.")
            };

            return Task.FromResult(featureDefinition);
        }

        public async IAsyncEnumerable<FeatureDefinition> GetAllFeatureDefinitionsAsync()
        {
            foreach (var featureDefinition in new[]
            {
                await GetFeatureDefinitionAsync(FirstFeatureName),
                await GetFeatureDefinitionAsync(SecondFeatureName),
                await GetFeatureDefinitionAsync(ThirdFeatureName),
            })
            {
                yield return featureDefinition;
            }
        }

        private FeatureDefinition CreateEnabledFeatureDefinition(string featureName)
        {
            // NOTE: adding a filter configuration without configurations means enabled
            return new FeatureDefinition
            {
                Name = featureName,
                EnabledFor = new[]
                {
                    new FeatureFilterConfiguration
                    {
                        Name = "AlwaysOn"
                    }
                }
            };
        }

        private FeatureDefinition CreateDisabledFeatureDefinition(string featureName)
        {
            // NOTE: don't add any filter configuration as by default it is disabled
            return new FeatureDefinition
            {
                Name = featureName
            };
        }

        private FeatureDefinition CreatePercentageFeatureDefinition(string featureName, double percentage)
        {
            // NOTE: this one is a bit more complicated and could be connected to a percentage SQL server setting
            return new FeatureDefinition
            {
                Name = featureName,
                EnabledFor = new[]
                {
                    new FeatureFilterConfiguration
                    {
                        Name = "Percentage",
                        Parameters = new DoubleConfiguration(percentage)
                    }
                }
            };
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

namespace FeatureDefinitionProviderDemo
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.Primitives;

    internal class DoubleConfiguration : IConfiguration
    {
        private readonly double _percentage;

        public DoubleConfiguration(double percentage)
        {
            _percentage = percentage;
        }

        public IEnumerable<IConfigurationSection> GetChildren()
        {
            // NOTE: no children
            return Enumerable.Empty<IConfigurationSection>();
        }

        public IChangeToken GetReloadToken()
        {
            // NOTE: this is not supported and not consumed either
            throw new NotSupportedException();
        }

        public IConfigurationSection GetSection(string key)
        {
            // NOTE: this is not supported and not consumed either
            throw new NotSupportedException();
        }

        public string this[string key]
        {
            get => _percentage.ToString("F"); // this produces the requested value

            // NOTE: this is not supported and not consumed either
            set => throw new NotSupportedException();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)