loading...
Cover image for Inject configuration values in Azure Functions

Inject configuration values in Azure Functions

laur3d profile image Laurentiu Iarosevici Updated on ・2 min read

One of the most important updates to the Azure function framework was the addition of the DI support. One of the use-cases for having a DI is to read and use "feature flags" in the form of configuration values/environment variables.

So for the big question, how do we go from here (local.appsettings.json / env variables):

  {
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet",
        "FeatureFlag" : "True",
        "ConfigValue" : "some random value"
    }
}

To here (constructor injected in the function / trigger):

 public class FeatureHttpTrigger
    {
        private readonly FeatureConfig _config;

        public FeatureHttpTrigger(FeatureConfig config)
        {
            _config = config;
        }

        [FunctionName("FeatureHttpTrigger")]
        public async Task<IActionResult> RunAsync(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]
            HttpRequest req, ILogger log)
        {
          ......
        }
}
  • Although I know that there is quite a difference between a feature flag and an environment variable, a lot of people use them like this. Anyway ... moving on...
  • So, one of the most common things you tend to do is to rely on the DI framework to provide you with all sorts of useful constructs ( that you painstakingly set up beforehand) in order to simplify the way you use them. If you are not familiar with Dependency Injection, I suggest you look into it since this is one of the most important patterns used nowadays in most of the frameworks around web development.

Prepartiations

In order to get this working, we need to make sure we are using v3 of azure functions (should work with v2 though).
Next, we need to make sure that we have the DI setup. Here is a good resource to help you do this.

The actual steps

Before we continue, I want to add that I am a big fan of feature folders, and when I build this example I subconsciously used them, they are not required, and by all means, some other constructs could be bypassed, but this is the way I'm usually structuring my function code.

Good, now this is all out of the way, let's get down to business.

The first thing you'll want to do is to add a class that will hold your data in the shape you prefer to use via the constructor injection.

    public class FeatureConfig
    {
        public string ConfigValue { get; set; }
        public bool FeatureFlag { get; set; }
    }

Next, we need to make sure that we have the values set up either in the appsettings or the environment variables or in the function apps configuration (ideally everywhere :) ).

Now, the next thing I usually do, which is not required but I think it keeps the code more structured si to create a static class that will hold all the DI configuration:

internal static class ServiceRegistrations
    {
        public static void ConfigureServices(IServiceCollection builderServices, IConfiguration configuration)
        {
            builderServices.AddFeature();
        }

        private static IServiceCollection AddFeature(this IServiceCollection serviceCollection)
        {
            // here we would group all feature related DI code
            serviceCollection.TryAddSingleton<FeatureConfig>(sp =>
            {
                var config = sp.GetService<IConfiguration>();

                return new FeatureConfig
                {
                    ConfigValue = config.GetValue<string>("ConfigValue"),
                    FeatureFlag = config.GetValue<bool>("FeatureFlag" )
                };
            });

            return serviceCollection;
        }
    }

And boom, that is about it ...

If you want a closer look, here is a link to github

Discussion

pic
Editor guide