https://github.com/MicrosoftDocs/azure-docs/issues/44467:
With the release of dependency injection in Azure Functions, there is a FunctionStartup class to do the dependency injection. My guess is that configuration should also be done in the FunctionStartup to properly configure dependency injection with the settings. I think this page should be updated to reflect that.
Yes, I've just investigating the use of App Configuration with Functions but it requires us to build a second IConfigurationBuilder, add App Configuration, call .Build(), read the output settings from it, and then register the config types (IOptions<SomePOCO>) on the IFunctionsHostBuilder.Services DI container.
It would be good if we were able to add App Configuration to the Function app without doing that before the GA release soon. It is a blocker have to duplicate this registration... If anyone has a workaround for now I would appreciate it.
Looking forward to hear some good news.
Thanks!
Maybe the Azure Function Teams should be involved here. Main issue is that the IConfiguration used by the AF sdk is not exposed in the FunctionStartup. It must be more complicated than that but if the IConfiguration was available, we would just have use it.
That is definitively a blocker. Both WebApps and Functions should have support to it.
@fabiocav do you have any plans to make it work on Functions Host/SDK?
Thanks
Here's an example of how I've been doing this; should be relatively trivial to turn into a proper extension.
The Azure Functions example in this repo is already updated to use the FunctionsStartup.
The example injected a new instance of IOptions<T> to the DI. It didn't choose to replace the IConfiguration instance Azure Functions already had so users can still access existing configuration but that can be a choice of each user. As @TechWatching mentioned earlier, Azure Functions didn't provide a way so the configuration builder of App Configuration can be added to what built-in in Azure Functions. We've been in conversations with the Azure Functions team and they are aware of the issue. We will update the example if there is anything new coming up.
Awesome! Please update this thread when you have it :)
The Azure Functions example in this repo is already updated to use the
FunctionsStartup.
Could this sample at least get a shout out on https://docs.microsoft.com/en-us/azure/azure-app-configuration/quickstart-azure-functions-csharp so that others don't need to be lucky enough to stumble upon this issue to find it?
@wdspider yes, that's the plan. We got a bit backlog on documentation.
It's also worth noting that there doesn't seem to be an easy way to add all of the App Configuration to DI without modeling it with POCO objects. I'm setting up an endpoint that a React client can hit to obtain configuration without worrying about how to talk to App Configuration and don't want to have to push a new version of the endpoint every time I add a new config key. As such, I ended up going with the non-DI way that the Quickstart currently demostrates since the function is doing nothing else and configuration.AsEnumerable().Where(x => x.Value != null) gives me what I want while also being refreshed by configurationRefresher
@zhenlan Thanks for your work. Also @Kittoes0124 thanks for your example
About the example on https://github.com/Azure/AppConfiguration/tree/main/examples/DotNetCore/AzureFunction would it be possible to update it to use the last version of Microsoft.Azure.Functions.Extensions (1.1.0) There is an important change, on the new version we can access the IFunctionsConfigurationBuilder object which allows us to extend the default configuration, without having to override it(in case we use values on our trigger for example) @Kittoes0124 has provided already a partially example...
Unfortunately for me I'm still struggling to make it work, I'm getting some ideas from @Kittoes0124 example and completing them with ideas from @zhenlan example...but for some reason all load correctly the first round but I never get new values when I change them on AZ...
Unfortunately for me I'm still struggling to make it work, I'm getting some ideas from @Kittoes0124 example and completing them with ideas from @zhenlan example...but for some reason all load correctly the first round but I never get new values when I change them on AZ...
If you're following my example then getting all settings to refresh should be as simple as updating the sentinel key (which I named "Application:ConfigurationVersion"); I simply increment it according to SemVer rules.
You'll also want to ensure that you inject the IConfigurationRefresher singleton via your function constructor and then call its refresh method before accessing any IOptionsSnapshot<T> based settings. I will update my SO post in a bit to reflect my suggestion here.
If you're following my example then getting all settings to refresh should be as simple as updating the sentinel key (which I named "Application:ConfigurationVersion"); I simply increment it according to SemVer rules.
You'll also want to ensure that you inject the IConfigurationRefresher singleton via your function constructor and then call its refresh method before accessing any IOptionsSnapshot
based settings. I will update my SO post in a bit to reflect my suggestion here.
Yes, that is what I'm trying, I'm calling the _configurationRefresher.TryRefreshAsync() inside a class(which has Transient scope...)...but nothing. I've tried with IOptionsSnapshot
I must be missing something if this is working for others...
@Kittoes0124 Could you share the version number you are using? for:
Microsoft.Extensions.Configuration.AzureAppConfiguration
Microsoft.Azure.Functions.Extensions
PS: I've tried using @zhenlan example and it works for me...unfortunately that example forces me to override existing configuration which is not good neither...
PS: This is working for me https://azureappconfiguration.slack.com/archives/CGK08MHML/p1579021966026200?thread_ts=1579021523.021200&cid=CGK08MHML
I just added the code to get and inject the Refresher(seems necessary) and as on @Kittoes0124 example I inject the refresher on the constructor of my function
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.KeyVault;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Azure.WebJobs.Host.Bindings;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
private static IConfiguration configuration { set; get; } = null!;
private IConfigurationRefresher ConfigurationRefresher { get; private set; } = null!;
public void ConfigurationBuilderWithAzureAppConfiguration(IServiceCollection services)
{
var providers = new List<IConfigurationProvider>();
var existingConfig = services.BuildServiceProvider().GetService<IConfiguration>() as IConfigurationRoot;
var connectionString = GetConnectionString();
var config = new ConfigurationBuilder()
.AddAzureAppConfiguration(options =>
{
options.Connect(connectionString)
.ConfigureRefresh(refreshOptions =>
{
refreshOptions.Register("SentinelKey", LabelFilter.Null, true)
.SetCacheExpiration(TimeSpan.FromSeconds(20));
});
ConfigurationRefresher = options.GetRefresher();
});
providers.AddRange(config.Build().Providers);
foreach (var provider in existingConfig!.Providers)
{
providers.Add(provider);
}
var configurationRoot = new ConfigurationRoot(providers);
services.AddSingleton<IConfiguration>(configurationRoot);
configuration = config.Build();
}
public override void Configure(IFunctionsHostBuilder builder)
{
var options = ConfigurationBuilderWithAzureAppConfiguration(builder.Services);
builder.Services.AddSingleton<IConfigurationRefresher>(ConfigurationRefresher);
ConfigurationRefresher.RefreshAsync();//maybe not necessary, still testing
//...
}
With this I get refresh and I keep the default Providers values
I have a PR (#446) to update the Azure Functions example to leverage the IFunctionsConfigurationBuilder. The AppConfig provider can now be added as an additional config source. The Azure Functions existing providers will be preserved.
The quickstart and tutorial have been updated to use dependency injection in Azure Functions