Azure Functions V2 – KeyVault and IConfiguration

Update:

The method below to get IConfiguration from your DI container is not needed anymore, since Azure Functions are supporting Dependency Injection now: Azure Functions DI

With that you don’t need the extra ConfigProvider and the ConfigAttribute anymore.

AddAzureKeyVault is still valid and works like a charm, also check out the auto refresh on it. AzureKeyVaultConfigurationOptions


Since Azure Functions V2 are out of preview finally, I started using them more and more. Obviously you run into some sort of issues immediately, like how do you get your app settings out of IConfiguration since there is no real .Net Core dependency injection built in right now. Just adding IConfiguration to the function itself doesn’t work. Or how do you access the KeyVault and have the values auto resolve.

Well, its actually not that difficult. And no you don’t have to add those “Inject” provider/attribute unless you want to, but you kind of follow the same steps.

I’m using a default function v2 in my example with an HttpTrigger and you can find the code on my Github.

In order to get your IConfiguration and use the built-in “AddAzureKeyVault” to add the KeyVault provider, all you have to do is create an implementation of “IWebJobsStartup” which will give you the “IWebJobsBuilder”. I guess that sounds familiar if you have used ASP.Net Core apps.

You can now access the current IConfiguration and add the KeyVault. After that you have to replace the existing one with the new configuration in order to make it accessible later with the key vault provider you added.

[assembly: WebJobsStartup(typeof(FunctionStartup))]
namespace FunctionApp1
{
    public class FunctionStartup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder)
        {
            //Get the current config and merge it into a new ConfigurationBuilder to keep the old settings
            var configurationBuilder = new ConfigurationBuilder();
            var descriptor = builder.Services.FirstOrDefault(d => d.ServiceType == typeof(IConfiguration));
            if (descriptor?.ImplementationInstance is IConfigurationRoot configuration)
            {
                configurationBuilder.AddConfiguration(configuration);
            }

            //build the config in order to access the appsettings for getting the key vault connection settings
            var config = configurationBuilder.Build();

            var vaultUrl = config["VaultUrl"];
            var vaultClientId = config["VaultClientId"];
            var vaultClientSecret = config["VaultClientSecret"];

            //add the key vault to the configuration builder
            configurationBuilder.AddAzureKeyVault(vaultUrl, vaultClientId, vaultClientSecret);

            //build the config again so it has the key vault provider
            config = configurationBuilder.Build();

            //replace the existing config with the new one
            builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), config));

            //add the ConfigProvider if you want to use IConfiguration in your function
            //the ConfigProvider is just an implementation of IExtensionConfigProvider to give you access to the current IConfiguration
            builder.AddExtension<ConfigProvider>();
        }
    }
}

Now you need to add your ConfigProvider and the ConfigAttribute so you can access the IConfiguration with the key vault provider in your function.

internal class ConfigProvider : IExtensionConfigProvider
{
    private readonly IConfiguration _config;

    public ConfigProvider(IConfiguration config) => _config = config;

    public void Initialize(ExtensionConfigContext context) => context.AddBindingRule<ConfigAttribute>().BindToInput(_ => _config);
}
[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = true)]
[Binding]
public sealed class ConfigAttribute :Attribute
{
}

Everything is now setup and you can start using it. In my example I put in the KeyVault connection settings into the local.settings.json in case you were wondering where they are coming from.

So to use the IConfiguration like you are used to do, just add [ConfigAttribute] IConfiguration config into your function.

My test function gets a value out of the settings file and one out of the KeyVault I set up.

[FunctionName("Function1")]
public static IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequest req, ILogger log,[ConfigAttribute] IConfiguration config)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    string name = req.Query["name"];

    string configValue = config["TestConfig"];

    string vaultValue = config["VaultConfig"];

    string requestBody = new StreamReader(req.Body).ReadToEnd();
    dynamic data = JsonConvert.DeserializeObject(requestBody);
    name = name ?? data?.name;

    return name != null
    ? (ActionResult)new OkObjectResult($"Hello, {name} with test config value: {configValue} and a vault config value: {vaultValue}")
    : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}

Running and testing the function looks like that:

2 thoughts on “Azure Functions V2 – KeyVault and IConfiguration”

  1. thank you very much for writing this. after countless hours of trying and googling, this helped me finally.
    i followed your approach to integrate user-secrets into configuration

  2. Thank you for this article. I learned a lot from this. I’m using .NET Core 3.1 in Azure functions and I needed to replace this line:

    if (descriptor?.ImplementationInstance is IConfigurationRoot configuration)

    with:

    if (descriptor?.ImplementationFactory.Invoke(null) is IConfigurationRoot configuration)

    Except from this everything worked beautifully.

Leave a Reply

Your email address will not be published. Required fields are marked *