Azure / AppConfiguration-DotnetProvider

The .NET Standard configuration provider for Azure App Configuration
https://github.com/Azure/AppConfiguration
MIT License
77 stars 34 forks source link

Get multiple values with different labels #501

Closed shadowano closed 6 months ago

shadowano commented 7 months ago

In our App Configuration we have a Key e.g. ApiEndpoints, Values with different endpoints and a Label telling us which region this belongs to. Our use case is to support multiple regions/environments (as described on this MS Learn guide) and fetch the api endpoints, clientid and secrets from App Configuration. At any time, a new region can be added, so our app needs to be able to fetch new regions (with modification of a Sentinel key as described in this MS Learn tutorial) .

Our app is a multi regional client written in NETFramework, and it should connect to all of the different regions at any given time. The only identifier that our app knows about is the Region, and the Keys are generic known values.

Below is a screenshot of the App Configuration setup. In each Region we have Apiendpoints, ClientIDs and ClientSecrets. image

I have created a small console app very similar to https://learn.microsoft.com/en-us/azure/azure-app-configuration/enable-dynamic-configuration-dotnet. I removed the code regarding refresh stuff to make it simpler. I have also written a powershell script to create a resource group with an App Configuration and adding dummy data that shows you how we structure our data in the App Configuration.

Powershell script for creating App Config with dummy data ``` $resourceGroup = "AppConfigTestResources" $appConfigName = "MyTestAppconfig" $location = "" $subscription = "" az login az account set --subscription $subscription # Create a resource group az group create --name $resourceGroup --location $location # Create an App Configuration store az appconfig create --location $location --name $appConfigName --resource-group $resourceGroup --sku free $appConfig = az appconfig list --resource-group $resourceGroup | ConvertFrom-Json # It might take some time for the app configuration resource to be available via AZ CLI so below commands might fail # Create key-value pairs # Region01 az appconfig kv set --name $appConfigName --key "Apiendpoints" --value "A" --label "Region01" --yes --endpoint $appConfig[0].endpoint az appconfig kv set --name $appConfigName --key "ClientIDs" --value "E" --label "Region01" --yes --endpoint $appConfig[0].endpoint az appconfig kv set --name $appConfigName --key "ClientSecrets" --value "F" --label "Region01" --yes --endpoint $appConfig[0].endpoint # Region02 az appconfig kv set --name $appConfigName --key "Apiendpoints" --value "B" --label "Region02" --yes --endpoint $appConfig[0].endpoint az appconfig kv set --name $appConfigName --key "ClientIDs" --value "C" --label "Region02" --yes --endpoint $appConfig[0].endpoint az appconfig kv set --name $appConfigName --key "ClientSecrets" --value "D" --label "Region02" --yes --endpoint $appConfig[0].endpoint ```

After looking into this .Net App Configuration provider I have not been able to get this use case to work without possibly making bad workarounds. The list below show what I have found to be limitations in order to implement the use case above.

  1. The AzureAppConfigurationOptions.Select method does not allow wildcards for Label. Since all of our Keys have a label, we cannot fetch all keys without specifying those

  2. If we specify the regions to fetch in separate selects like this

    options.Connect(Environment.GetEnvironmentVariable("AppConfiguration.ConnectionString"))
    .Select(KeyFilter.Any, "Region01")
    .Select(KeyFilter.Any, "Region02");

    we only get data for one region back. image

  3. By specifying Regions we want to get, I guess this will not discover new regions being added to the App Configuration even if we add a listener on a Sentinel key, as the already added selects will exclude new regions.

  4. The App Configuration provider does not return Label information, so if stacking several Selects with known regions would work, Label would have to be included in the returned object in order to identify which value belonged to which region.

My understanding of this provider is to only have one connection to App Configuration, and let this live for as long as the app is up. If I haven't misunderstood anything I have written above or in the documentation, the only way to solve my use case is to connect to and dispose the App Configuration client connection every time I need to fetch data about a different region. This also means I will not be able to use the feature of a Sentinel key, but reconnecting to the App Configuration will probably give me newest data.

Any advice or help on this topic is very welcome:)

PS: This issue covers and replace #500 so you can go ahead and close that one (created by me, but was transferred so I don't have access to it)

shadowano commented 7 months ago

If I haven't misunderstood anything I have written above or in the documentation, the only way to solve my use case is to connect to the App Configuration client connection every time I need to fetch data about a different region. This also means I will not be able to use the feature of a Sentinel key, but reconnecting to the App Configuration will probably give me newest data anyway.

I'm very surprised that fetching multiple regional settings is not supported, even when it is documented on Microsoft's learn page that the App Configuration can be configured like we have done.

amerjusupovic commented 7 months ago

Hi @shadowano, I'm sorry if that documentation was misleading. Labels apply better to scenarios where the environments are known and only one value is needed for a key at a time, like in the example of using development and production.

A very similar question has been asked in another repo here. To achieve the functionality you want, I'd recommend using namespaces as explained here. Let me know if this answers your question.

shadowano commented 7 months ago

Thanks @amerjusupovic. The documentation is not clear at all on this topic. Even on the page you link to our use case is within the recommendations when you read on Label Keys. It only says "A common use of labels..." and then mentions dev, staging and prod.

The description of Labels matches our use case as we create variants of keys. Label provides a convenient way to create variants of a key.

So what you are suggesting is that we do it this way instead image

Do you not acknowledge that the way we have set it up today (see screenshot in my initial comment) is a valid and good configuration based on our use case?

drago-draganov commented 7 months ago

@shadowano

Looks like in this case your configuration isn't multi-variant, but flat. The scenario described doesn't require specific projections (namespace or label). It appears as multi-value config setting.

In such case I would consider single setting with a value represented as json array (more)

Example:

image

The client-side config will map that to a list of strings.

More complex representation may even consider complete object mapping, instead of simple string. For example:

[
    {
            "RegionName": "region1",
        "Endpoint": "https://...",
        "ClientId": "c1"
    },
    {
           "RegionName": "region2",
           "Endpoint": "https://...",
       "ClientId": "c2"
    },
        // More regions ...
]

The client-side config will map that to a list of objects.

Maintaining that list on won't require any changes of the client-side config mapping and allows for auto-discovery new regions.

Hope that helps a bit.