Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Azure App Configuration - Feature Flags with Dapr #1295

Open
tomas-blanarik opened this issue May 27, 2024 · 6 comments
Open

Azure App Configuration - Feature Flags with Dapr #1295

tomas-blanarik opened this issue May 27, 2024 · 6 comments

Comments

@tomas-blanarik
Copy link

tomas-blanarik commented May 27, 2024

Hello, we're using FeatureManagement library from Microsoft and we wanted to use it altogether with Azure App Configuration. However, we use Dapr .NET SDK for all 3rd party components (service bus, key vault, ...) and we're also using .NET extension method AddDaprConfigurationStore to register Azure App Configuration. However, the feature flags are not loaded also they're not available in IConfiguration. Any ideas ?

@philliphoff
Copy link
Collaborator

@tomas-blanarik Can you provide any sort of repro project or redacted snippet of startup code? Are the configuration values (used for the feature flags) specified in the AddDaprConfigurationStore() method but still not added to the IConfiguration?

@tomas-blanarik
Copy link
Author

So simply my method for registering configuration sources is something like this

public static void AddCustomConfiguration(this WebApplicationBuilder builder)
    {
        if (builder.Environment.IsLocal())
        {
            builder.Configuration.AddJsonFile("features.json", optional: true, reloadOnChange: true);
        }

        builder.Configuration.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
        builder.Configuration.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true, reloadOnChange: true);
        builder.Configuration.AddEnvironmentVariables();

        if (!builder.Environment.IsLocal())
        {
            string[] delimiters = ["--", ":", "__"];
            var logger = builder.Services.GetRequiredService<ILoggerFactory>().CreateLogger("DI");

            try
            {
                var daprClient = new DaprClientBuilder().Build();
                builder.Configuration.AddDaprSecretStore(
                    CoreConstants.Dapr.Components.SecretStorage, // resolves to "keyvault"
                    daprClient,
                    delimiters,
                    TimeSpan.FromSeconds(60));

                logger.LogInformation("Successfully registered dapr Secret Store to IConfiguration");

                builder.Configuration.AddDaprConfigurationStore(
                    CoreConstants.Dapr.Components.ConfigurationStorage, // resolves to "config"
                    [], // so I want to load everything, but I am starting to sense the problem that I need to be very specific here
                    daprClient,
                    TimeSpan.FromSeconds(60));

                logger.LogInformation("Successfully registered dapr Configuration Store to IConfiguration");
            }
#pragma warning disable S2139
            catch (Exception e)
#pragma warning restore S2139
            {
                logger.LogError(e, "Cannot register dapr secret store to the configuration: {Message}", e.Message);
                Exception? inner = e.InnerException;
                while (inner is not null)
                {
                    logger.LogError(inner, "Inner exception: {Message}", inner.Message);
                    inner = inner.InnerException;
                }

                throw;
            }
        }
    }

@tomas-blanarik
Copy link
Author

Ok my bad, I misread the documentation or misunderstood it in some way.

The correct way of using App Configuration was to explicitly specify keys to be loaded, for example
.appconfig.featureflag/SomeFlagName and this worked. Also if you have labels adding metadata is needed (as also stated in documentation). Something like this new Dictionary<string, string> { { "label", "my-label" } }

Then I saw loading these values in console log which indicates that it's actually working :)

@tomas-blanarik
Copy link
Author

However, the problem with loading values from App Configuration doesn't end there. If you want to use FeatureFlags you need to transform these into FeatureManagement section after they're loaded.

@philliphoff
Copy link
Collaborator

However, the problem with loading values from App Configuration doesn't end there. If you want to use FeatureFlags you need to transform these into FeatureManagement section after they're loaded.

@tomas-blanarik There's a new-ish feature of the SDK (SecretKey)which allows you to transform the keys of a secret store when adding them to the configuration. I'm not familiar enough with FeatureFlags to know whether that offers enough flexibility to automatically do what you need.

@jypa-github
Copy link

jypa-github commented Aug 28, 2024

@tomas-blanarik Thank you so much for the information. I would really appreciate if you could help me out with how to parse the feature flag object. Based on your comment, I have tried loading feature flag with .appconfig.featureflag/SomeFlagName although I could not parse it to Dictionary<string, string> to see the value of enabled flag.

See the below exception when I tried to load with bool type, I know this is not the proper way of loading feature flag although just to show you the actual feature flag object I have used "bool"

2024-08-27 06:21:16 Unhandled exception. System.InvalidOperationException: Failed to convert configuration value at '.appconfig.featureflag/enableFocusOrderTab' to type 'System.Boolean'.
2024-08-27 06:21:16 ---> System.FormatException: {"id":"enableFocusOrderTab","description":"Enable Focus Order Tab","enabled":true,"conditions":{"client_filters":[]}} is not a valid value for Boolean.
2024-08-27 06:21:16 ---> System.FormatException: String '{"id":"enableFocusOrderTab","description":"Enable Focus Order Tab","enabled":true,"conditions":{"client_filters":[]}}' was not recognized as a valid Boolean.

Please guide me how to transform featureFlags config into FeatureManagement section.

Much appreciated!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants