microsoft/FeatureManagement-Dotnet

FeatureManager in ASP.NET Core Web API

Closed this issue · 8 comments

my Team and I is planning to implement feature flag and I am doing POC currently. For security reason, we decided to return feature flag status via an API and this is why I am using FeatureManager in ASP . NET Core Web API. With my configuration, I realize feature flag is not reflected correctly right after I toggle the feature status in Azure Portal and request after caching interval. I have to request twice in order to retrieve the new status toggle in Azure Portal. Do anyone know workaround for it. The steps I encountered this behaviour:

Assuming I have a feature name "Beta" in azure portal.

  1. Retrieve current status of feature "Beta": true.
  2. Toggle to disabled in azure portal.
  3. Waited 10s (Cache is set to 1s).
  4. Request status, return as true.
  5. Request again only getting the right status which is false.

Overall, I need to make two requests in order to get conrect status. Is there any workaround?

Below are my configuration.

builder:

 builder.Services.AddFeatureManagement()
       .AddFeatureFilter<TargetingFilter>();
   builder.Services.AddSingleton<ITargetingContextAccessor, TargetingContextAccessor>();
   builder.Services.AddAzureAppConfiguration();
   builder.Configuration.AddAzureAppConfiguration(options =>
   {
       options.Connect(builder.Configuration["FEATUREFLAG_CONNECTION"])
           .Select("_") 
           .UseFeatureFlags(featureFlagOptions =>
           {
               featureFlagOptions.CacheExpirationInterval = TimeSpan.FromSeconds(1);
               featureFlagOptions.Select(KeyFilter.Any, builder.Configuration["ENV"]);
           });
   });

middleware:

app.UseAzureAppConfiguration();

Dependency that injected with featuremanager:

public class Service : IService
{
    private readonly IFeatureManager _manager;
    private readonly ILogger<Service> _logger;

    public Service(IFeatureManager manager, ILogger<Service> logger)
    {
        _manager = manager;
        _logger = logger;
    }

    public async Task<ConfigurationResponse<List<FeatureFlagConfigurationItem>>> GetFeatures()
    {
        try
        {
            var result = await GetFeaturesFromAzure();
            return;
        }
        catch (Exception e)
        {
            return;
        }
    }

    private async Task<List<FeatureFlagConfigurationItem>> GetFeaturesFromAzure()
    {
        var featureConfigurationItems = new List<FeatureFlagConfigurationItem>();

        var featureFlags = _manager.GetFeatureNamesAsync();


        await foreach (var featureFlag in featureFlags)
        {
            
            featureConfigurationItems.Add(await IsFeatureEnabled(featureFlag));
        }

        return featureConfigurationItems;
    }

    private async Task<FeatureFlagConfigurationItem> IsFeatureEnabled(string featureName)
    {
        var result = new FeatureFlagConfigurationItem()
        {
            Key = featureName,
            Value = false
        };
        
        try
        {
            var IsEnabled = await _manager.IsEnabledAsync(featureName);
            result.Value = IsEnabled;

        }
        catch (Exception e)
        {
           Console.WriteLine("");
        }

        return result;
    }
}

Hello @wen-git-acc,

This is expected behavior from the Azure App Configuration configuration provider. This is because the provider is designed to perform a refresh when a request is made, but it is done in parallel to the request to avoid slowing the request down. There are a few downsides that arise from deviating from this model. Can you explain a bit the problem that this is causing so I may offer a suggestion?

Hi @jimmyca15

Based on our design, the desktop application will be querying the API to retrieve set of feature status during the start up. It means that the user have to boot up the application twice in order to retrieve latest feature state (if any feature is toggled on azure portal), which is not ideal in our use case. Hence, I am looking if there is any work around to request the latest change update instead of sending request twice to retrieve the latest state.

While looking through previous few issues post, understand that we could not disable caching. Is there any way for me to refresh configuration in every request on purpose so that my IsEnabledAsync could have query the latest change from azure config service?

Besides, I have found this url, curious to know that does it works on feature flag items and will it increase cost of using azure config service since we are making more request.

Hi, is there any update on this?

Is there any way for me to refresh configuration in every request on purpose so that my IsEnabledAsync could have query the latest change from azure config service?

Yes. You can call IConfigurationProvider.RefreshAsync during the request pipeline and await it. This will ensure that the refresh completes before your code evaluates the flag. The refresh will still be subject to the configured cache interval.

This has the downsides that I mentioned that now the requests success and response time is now dependent upon the success of the refresh operation.

Hello @wen-git-acc, does this solve the issue?

@wen-git-acc The suggested approach should be able to solve the issue. Please feel free to re-open if anything is missed.

Hi @jimmyca15 , sorry missed out to reply. For your information, the above method only work without use azure configuration middleware :) Definitely solved my issue, thanks for your help