Search code examples
c#azureazure-webjobsazure-storage-queuesazure-webjobs-continuous

Azure WebJobs access configuration from within a static function


I'm creating a webjob in .net core 3.1. In this project I have a function that is timer activated which should read the number of messages in a queue Q1 and if empty, put a message in Q2 as well as trigger a rest call to an API.

In order to check how many messages are in the API I need to access the AzureWebJobsStorage in my appsettings.json and then the url which is also in the settings.

Program.cs

class Program
    {
        static async Task Main()
        {
            var builder = new HostBuilder();
            builder.ConfigureWebJobs(b =>
                {
                    b.AddAzureStorageCoreServices();
                    b.AddAzureStorage();
                    b.AddTimers();
                });
            builder.ConfigureLogging((context, b) =>
                {
                    b.AddConsole();
                });
            builder.ConfigureAppConfiguration((context, b) => 
            {
                b.SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddEnvironmentVariables();
            });
            builder.ConfigureServices((context, services) =>
            {
                var mySettings = new MySettings
                {
                    AzureWebJobsStorage = context.Configuration.GetValue<string>("AzureWebJobsStorage"),
                    AzureWebJobsDashboard = context.Configuration.GetValue<string>("AzureWebJobsDashboard"),
                    url = context.Configuration.GetValue<string>("url"),
                };
                services.AddSingleton(mySettings);
            });
            var host = builder.Build();
            using (host)
            {
                await host.RunAsync();
            }
        }
    }

Fuctions.cs

public class Functions
    {
public static void UpdateChannels([QueueTrigger("Q1")] string message, ILogger logger)
        {
            logger.LogInformation(message);
        }

        public static void WhatIsThereToUpdate([QueueTrigger("Q2")] string message, ILogger logger)
        {
            logger.LogInformation(message);
        }

        public static void CronJob([TimerTrigger("0 * * * * *")] TimerInfo timer, [Queue("Q2")] out string message, ILogger logger, MySettings mySettings)
        {
            message = null;
            // Get the connection string from app settings
            string connectionString = mySettings.AzureWebJobsStorage;
            logger.LogInformation("Connection String: " + connectionString);
            // Instantiate a QueueClient which will be used to create and manipulate the queue
            QueueClient queueClient = new QueueClient(connectionString, "Q1");
            if (queueClient.Exists())
            {
                QueueProperties properties = queueClient.GetProperties();

                // Retrieve the cached approximate message count.
                int cachedMessagesCount = properties.ApproximateMessagesCount;

                // Display number of messages.
                logger.LogInformation($"Number of messages in queue: {cachedMessagesCount}");

                if (cachedMessagesCount == 0)
                    message = "Hello world!" + System.DateTime.Now.ToString(); //here I would call the REST API as well
            }

            logger.LogInformation("Cron job fired!");
        }
    }

appsettings.json

{
  "AzureWebJobsStorage": "constr",
  "AzureWebJobsDashboard": "constr",
  "url": "url"
}

My Settings

public class MySettings
    {
        public string AzureWebJobsStorage { get; set; }
        public string AzureWebJobsDashboard { get; set; }
        public string url { get; set; }
    }

However when I run this I get the following error:

Error indexing method 'Functions.CronJob' Microsoft.Azure.WebJobs.Host.Indexers.FunctionIndexingException: Error indexing method 'Functions.CronJob' ---> System.InvalidOperationException: Cannot bind parameter 'mySettings' to type MySettings. Make sure the parameter Type is supported by the binding. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).

In addition to what is shown in the above codes I also tried using ConfigurationManager and Environment.GetEnvironmentVariable, both methods gave me null when I tried to read the values. For example ConfigurationManager.AppSettings.GetValues("AzureWebJobsStorage").

I also tried to register IConfiguration as a service services.AddSingleton(context.Configuration); and inject it in the parameters (instead of MySettings), but it also gave me the same binding error.

I'm really at a loss here, I've scoured the SO archives trying to find a solution and I think I tried everything I saw gave people positive results, but unfortunately I wasn't as lucky as the other posters.

Any guidance is much appreciated.

Edited to add my packages

In case it helps anyone, I'm using the following

Azure.Storage.Queues (12.4.0)

Microsoft.Azure.WebJobs.Extensions (3.0.6)

Microsoft.Azure.WebJobs.Extensions.Storage (4.0.2)

Microsoft.Extensions.Logging.Console (3.1.7)


Solution

  • When using DI, I suggest you use non-static method and constructor inject.

    Here is the Functions.cs:

    public class Functions
    {
        private readonly MySettings mySettings;
    
        public Functions(MySettings _mySettings)
        {
            mySettings = _mySettings;
        }
    
        public void ProcessQueueMessage([TimerTrigger("0 */1 * * * *")] TimerInfo timer, [Queue("queue")] out string message, ILogger logger)
        {
            message = null;
            string connectionString = mySettings.AzureWebJobsStorage;
            logger.LogInformation("Connection String: " + connectionString);
        }
    }
    

    No code change in other .cs file.

    Here is the test result:

    enter image description here