4
votes

I have trouble reading configuration values from appSettings.json file in webjob. The webjob uses the following nuget packages:

enter image description here

I have two settings file in my console application (webjob): appsettings.development.json appsettings.production.json

In the Main method, the webjob is configured as follows:

 static void Main(string[] args)
    {
        var builder = new HostBuilder()
                .ConfigureWebJobs(webJobConfiguration =>
                {
                    webJobConfiguration.AddTimers();
                    webJobConfiguration.AddAzureStorageCoreServices();  
                })
                .ConfigureAppConfiguration((hostingContext, config) =>
                 {
                     var env = hostingContext.HostingEnvironment;
                     Console.WriteLine("hostingContext.HostingEnvironment: " + env.EnvironmentName);
                     config.SetBasePath(Directory.GetCurrentDirectory())
                     .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: false, reloadOnChange: true)
                     .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: false, reloadOnChange: true)
                     .AddEnvironmentVariables().Build();
                 })
                .ConfigureServices((context, serviceCollection) =>
                {
                    serviceCollection.AddSingleton<IConfiguration>(context.Configuration);
                    serviceCollection.AddTransient<SayHelloWebJob>(job => new SayHelloWebJob(context.Configuration));
                })
                .Build();

        builder.Run();
    }

The code for SayHelloWebJob is below:

public class SayHelloWebJob
{
     static IConfiguration _configuration;
    public SayHelloWebJob(IConfiguration config)
    {
        _configuration = config;
        Console.WriteLine("Initialized SayHelloWebJob");
    }

    [Singleton]
    public static void TimerTick([TimerTrigger("0 */1 * * * *")]TimerInfo myTimer)
    {
        Console.WriteLine($"From SayHelloWebJob: Hello at {DateTime.UtcNow.ToString()}");
        var test = _configuration.GetSection("WebJobConfiguration:message").Value;
        Console.WriteLine("Configuration access: message: " + test);
        Console.WriteLine("Configuration access: " + _configuration.GetSection("WebJobConfiguration:api").Value);
        Console.WriteLine("configuration object: "+ _configuration.GetConnectionString("AzureWebJobsStorage"));

    }
}

When I run my webjob, I see that console.writeline logs never output the configurations which I'm trying to read in the TimerTick method.

Questions:

  1. How can I inject the appSettings configuration inside the TimerTick method?
  2. I have two appSettings files - for development & production. How can I make sure the correct file gets loaded during production?

Example appSettings.development.json file below:

{
"connectionStrings": {
    "AzureWebJobsStorage": stringhere",
    "AzureWebJobsDashboard": "stringhere"
},
"WebJobConfiguration": {
    "message": "I'm running locally!",
    "pfuWebApiUrl": "API link here",
    "api": "api here",
    "ApplicationInsights": {
        "InstrumentationKey": "key here"
    }
}

}

2

2 Answers

2
votes

My preference is to have all environment configuration checked in as you have and it is definitely possible to load the correct file at runtime based on environment.

First set your config files to "copy to output directory in newer" in the Properties pane in Visual Studio or add this to your csproj:

    <None Update="base.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    </None>
    <None Update="prod.settings.json">
      <CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
    </None>

Now you just need to load the correct configuration at runtime.

        private static IConfigurationRoot GetConfiguration(string basePath)
        {
            string filename = Constants.IsAzureEnvironment ? "prod.settings.json" : "dev.settings.json";

            IConfigurationBuilder configBuilder = new ConfigurationBuilder()
                .SetBasePath(basePath)
                .AddJsonFile("base.settings.json")
                .AddJsonFile(filename);

            return configBuilder.Build();
        }

I get basePath from the executionContext parameter of the azure function

        [FunctionName("Function1")]
        public static async Task<IActionResult> RunAsync([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log, Microsoft.Azure.WebJobs.ExecutionContext context)
        {
            // context.FunctionAppDirectory
            return new OkResult();
        }
0
votes

I used the Json.NET to read the json file.

This is my json content:

{
   "object": {
      "name": "cwr"
   },
   "others": "123"
}

And this is function.cs code:

 public static void Run([TimerTrigger("0 */1 * * * *")] TimerInfo timer,
        ILogger logger)
    {
        
        JObject jsonData = JObject.Parse(File.ReadAllText(path));

        logger.LogInformation(jsonData["object"]["name"].ToString());
        logger.LogInformation(jsonData["others"].ToString());

    }

And here is output:

enter image description here

Hope this could help you, if you still have other questions, please let me know.