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

Add ability to perform custom transforms on App Configuration Settings. #157

Closed
jimmyca15 opened this issue Apr 8, 2020 · 9 comments · Fixed by #355
Closed

Add ability to perform custom transforms on App Configuration Settings. #157

jimmyca15 opened this issue Apr 8, 2020 · 9 comments · Fixed by #355
Assignees
Labels
enhancement New feature or request
Milestone

Comments

@jimmyca15
Copy link
Member

jimmyca15 commented Apr 8, 2020

Some applications may need to perform custom transforms on the configuration settings they retrieve from Azure App Configuration. An example might be if an application uses a custom defined content type and has to process the value before it is acceptable to be placed in .NET Core's IConfiguration. This is the kind of thing that is done for Key Vault references today.

This can be accomplished by exposing a new Map method to AzureAppConfigurationOptions.

Proposed API

/// Performs custom mapping for configuration settings retrieved from Azure App Configuration
public AppConfigurationOptions AppConfigurationOptions.Map(Func<ConfigurationSetting, ConfigurationSetting> mapper);

Usage

config.AddAzureAppConfiguration(options =>
    {
        options.Connect(settings["connection_string"])
            .Map((ConfigurationSetting setting) =>
            {
                if (setting.ContentType == "application/myContentType")
                {  
                    return new ConfigurationSetting(
                        key: setting.Key,
                        value: PerformSomeTransform(setting.Value),
                        label: setting.Label);
                }

                return setting;
        });
    });

The Value of the configuration setting is what is exposed from IConfiguration.

CC @zhenlan @drago-draganov @abhilasharora

@abhilasharora
Copy link
Contributor

This does seem like a viable approach to expose a ConfigurationSetting instance to the users and allow them to apply a transform on its value.

It might be a good idea to brainstorm the posssible scenarios where users might want to use transforms. That should help decide if we want to apply these after or before the feature management and key vault adapters are applied.

Also, if we expose the type directly, it is possible for a user to update the Key and Label fields in the ConfigurationSetting object, which could make it harder to understand if this method would act on those or just ignore them. We might want to expose an interface for the ConfigurationSetting class that provides setter for only the subset of properties that users are allowed to edit.

@jimmyca15
Copy link
Member Author

jimmyca15 commented Apr 8, 2020

I see two solutions to the ordering problem of before/after the built-in adapters.

An enum parameter like

enum MapPosition
{
  BeforeBuiltinMapping,
  AfterBuiltinMapping
}
Map(() => {}, MapPosition.BeforeBuiltinMapping);

Or pass a way to perform our value resolution on demand, which I think is even more flexible.

public AppConfigurationOptions AppConfigurationOptions.Map(Func<ConfigurationSetting, Func<ConfigurationSetting, Task<string>>, Task<ConfigurationSetting>> mapper);
config.AddAzureAppConfiguration(options =>
    {
        options.Connect(settings["connection_string"])
            .Map(async (setting, builtinMapper) =>
            {
                //
                // Performs built-in mapping like for key-vault references
                setting.Value = await builtinMapper(setting);

                if (setting.ContentType == "application/myContentType")
                {  
                    return new ConfigurationSetting(
                        key: setting.Key,
                        value: PerformSomeTransform(setting.Value),
                        label: setting.Label);
                }

                return setting;
        });
    });

And then we run the built-in mapping again internally if necessary.

@zhenlan zhenlan added the enhancement New feature or request label Apr 8, 2020
@drago-draganov
Copy link
Contributor

drago-draganov commented Apr 9, 2020

No need to over engineer from the start with ordering complexity, etc. Let's provide simple solution, calling after the internal adapters ran. The user code has the last saying what goes into the config.

@abhilasharora
Copy link
Contributor

For this issue, I plan to add the following API to the class AzureAppConfigurationOptions along with an explicit dependency on the package System.Threading.Tasks.Extensions.

public AzureAppConfigurationOptions Map(Func<ConfigurationSetting, ValueTask<ConfigurationSetting>> mapper);

@drago-draganov
Copy link
Contributor

drago-draganov commented Jun 11, 2020

By the naming convection used here it should be MapAsync, no?

@abhilasharora
Copy link
Contributor

This would not be an asynchronous method, only the delegate it takes would be asynchronous.

@drago-draganov
Copy link
Contributor

Good point. Thanks!

@bennypowers
Copy link

Please see https://stackoverflow.com/questions/65919559/access-azure-app-configuration-settings-that-reference-key-vault-in-nodejs/66018270?noredirect=1#comment117832100_66018270

If this issue can help improve the node.js SDK's ergonomics, it would be a huge benefit to users.

Thanks

@amerjusupovic
Copy link
Member

amerjusupovic commented Oct 24, 2022

Problem

As stated previously:

Some applications may need to perform custom transforms on the configuration settings they retrieve from Azure App Configuration. An example might be if an application uses a custom defined content type and has to process the value before it is acceptable to be placed in .NET Core's IConfiguration. This is the kind of thing that is done for Key Vault references today.

Proposed Solution

To solve this problem, we can add a new API that allows the user to pass in a function that performs custom transformations on configuration settings retrieved from Azure App Configuration.

// Provides a way to transform settings retrieved from App Configuration before they are processed by the
// configuration provider.
public AzureAppConfigurationOptions Map(Func<ConfigurationSetting, ValueTask<ConfigurationSetting>> mapper)

Usage Example

Here are some sample settings in App Configuration:

Key Value
Key__One Value1
Key__Two Value2

Let's say we set up our configurations with a call to Map like this:

var builder = new ConfigurationBuilder(); 
builder.AddAzureAppConfiguration(options =>
{
    options.Connect(connectionString)
                .Map((setting) => 
               {
                   ConfigurationSetting setting = new ConfigurationSetting(
                        key: setting.Key.Replace("__", ":"),
                        value: setting.Value,
                        label: setting.Label);
                   return new ValueTask<ConfigurationSetting>(setting);
               });
});

Here would be our updated settings:

Key Value
Key:One Value1
Key:Two Value2

Notes

  • Function delegates passed to Map are run before any internal adapters (e.g. Key Vault reference adapter).
  • Internal adapters will process the resulting ConfigurationSetting after all of the Map function delegates are run.
  • If Map is invoked multiple times, function delegates will be applied to each ConfigurationSetting in the order that they were invoked. Each Map callback would receive the ConfigurationSetting output from the previous callback.
  • You can pass an asynchronous function to Map as well which can be helpful, for example, to process the value of a setting with a custom defined content type, as mentioned in the problem description.
  • Since Map function delegates are run before running internal adapters, the appropriate adapter will choose and process the modified ConfigurationSetting based on content type.
  • If there are duplicates of a key, the last ConfigurationSetting will be used for IConfiguration.

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

Successfully merging a pull request may close this issue.

7 participants