0

I am a new a developer in terms of dealing with creating an Azure functions App. Since we have different environments for deployment, we use environment based appsettings.json files to load the correct values from the Azure Key Vault. I followed the tutorial here: https://learn.microsoft.com/en-us/azure/azure-functions/functions-dotnet-dependency-injection for adding appsettings.json files. Here is what my Startup class looks like.

[assembly: FunctionsStartup(typeof(Trialtimer.FunctionApp.Startup))]
namespace Trialtimer.FunctionApp
{
    public class Startup: FunctionsStartup
    {
        public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
        {
            FunctionsHostBuilderContext context = builder.GetContext();
            var config = builder.ConfigurationBuilder
                .AddJsonFile(Path.Combine(context.ApplicationRootPath, "appsettings.json"), optional: true, reloadOnChange: false)
                .AddJsonFile(Path.Combine(context.ApplicationRootPath, $"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json"), optional: true, reloadOnChange: true)
                .AddEnvironmentVariables()
                .Build();
        }

        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddOptions<MyOptions>().Configure<IConfiguration>((options, configuration) =>
            {
                var section = configuration.GetSection("MyOptions");
                section.Bind(options);
            });
        }
    }
}

My appsettings.json file is empty while my appsettings.build.json file has the following, based on the tutorial above

"MyOptions": {
    "MyCustomSetting": "Foobar"
  }

My MyOptions class is the following

public class MyOptions
    {
        public string MyCustomSetting { get; set; }
    }

My main class which houses the Azure Timer function is the following

public class TestTimerFunction
    {
        private readonly MyOptions _settings;

        public TestTimerFunction(IOptions<MyOptions> options)
        {
            _settings = options.Value;
        }

        [FunctionName("AzureTimerFunction")]
        public async Task Run([TimerTrigger("*/3 * * * * *")]TimerInfo myTimer, ILogger log)
        {
            var option = _settings;
            log.LogInformation($"Renew function executed at: {DateTime.Now} successfully with {option.MyCustomSetting}");   
        }
    }

The problem i'm having is, when i run the app, the "MyCustomSetting" variable is null. If i add the same json block that is in my appsettings.build.json file to the local.settings.json file, it looks like it gets read correctly and "MyCustomSetting" has the value "FooBar". The ASPNETCORE_ENVIRONMENT variable is also correctly returning "build". I've checked to make sure that both the appsettings.json files are "Copy if Newer" and when hovering over the "configuration" variable in the "Configure" method, i see that my appsettings.build.json file there. How can I make the function app bind the block from appsettings.build.json rather than local.settings.json? Am i doing something incorrectly?

Spartan 117
  • 520
  • 2
  • 6
  • 21
  • Why did you add `.Build()` after `AddEnvironmentVariables()` ?? Also have you updated your `.csproj` with ` PreserveNewest PreserveNewest Never ` – Venkata N Bhupathi Nov 12 '21 at 00:31
  • This might help you https://stackoverflow.com/questions/40768490/azure-functions-using-appsettings-json/64947058#64947058 – Venkata N Bhupathi Nov 12 '21 at 00:37
  • @VenkataNBhupathi already did that, but I got it to work, will post the answer below. Also, i removed the Build() as per your suggestion. – Spartan 117 Nov 12 '21 at 04:41

1 Answers1

0

Got it to work by swapping out the

builder.Services.AddOptions<MyOptions>().Configure<IConfiguration>((options, configuration) =>
            {
                var section = configuration.GetSection("MyOptions");
                section.Bind(options);
            });

with

builder.Services.Configure<MyOptions>(builder.GetContext().Configuration.GetSection("MyOptions"));

I don't know why this worked while the way that was described in the tutorial did not. But this has resolved my issue so I'm marking the question as answered.

Spartan 117
  • 520
  • 2
  • 6
  • 21
  • How would you do it, if you didn't have a prefix for every appSetting? Like I have here in my local.settings.json: "Values": { "AzureWebJobsStorage__accountName": "sazyrynkj6", "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated", "QueueName_AccessEvent": "access-queue" } – Oliver Nilsen Oct 11 '22 at 13:58