Configuring Function Apps to Use Azure App Configuration

Recently, we had a client that wanted to use an Azure Function app to listen to a Service Bus. Easy enough with ServiceBusTrigger but I wanted to ensure that the queue name to listen to came from Azure App Configuration service. But this proved to be more challenging.

What are we trying to do?

Here is what our function looks like:

public class ServiceBusQueueTrigger
{
[FunctionName("ServiceBusQueueTrigger")]
public void Run(
[ServiceBusTrigger(queueName: "%QueueName%", Connection = "ServiceBusConnection")]string myQueueItem,
ILogger log)
{
log.LogInformation($"C# ServiceBus queue trigger function processed message: {myQueueItem}");
}
}
view raw trigger.cs hosted with ❤ by GitHub

As you can see, we are using the %% syntax to indicate to the Function that it should pull the queue name from configuration. Our next step would be to connect to Azure App Configuration and get our configuration, including the queue name.

If you were to follow the Microsoft Learn tutorials, you would end up with something like this for the Startup.cs file:

[assembly: FunctionsStartup(typeof(FunctionApp.Startup))]
namespace FunctionApp
{
class Startup : FunctionsStartup
{
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
string cs = Environment.GetEnvironmentVariable("ConnectionString");
builder.ConfigurationBuilder.AddAzureAppConfiguration(cs);
}
public override void Configure(IFunctionsHostBuilder builder)
{
}
}
}
view raw startup.cs hosted with ❤ by GitHub
This came from: https://learn.microsoft.com/en-us/azure/azure-app-configuration/quickstart-azure-functions-csharp?tabs=in-process

If you use this code the Function App will not start. The reason is because the way the loading process happens is the configuration will now bind to the parameters in a Trigger. This all works fine for code that the functions execute, but if you are trying to bind trigger parameters to configuration values you have to do something different.

What is the solution?

After much Googling I came across this: https://github.com/Azure/AppConfiguration/issues/203

This appears to be a known issue that does not have an official solution, but the above workaround does work. So, if we use this implementation, we remove the error which prevents the Function Host from starting.

[assembly: FunctionsStartup(typeof(ConfigTest.Startup))]
namespace ConfigTest
{
public class Startup : IWebJobsStartup
{
public IConfiguration Configuration { get; set; }
public void Configure(IWebJobsBuilder builder)
{
var configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddEnvironmentVariables();
var config = configurationBuilder.Build();
configurationBuilder.AddAzureAppConfiguration(options =>
{
options.Connect(config["AppConfigConnectionString"])
.ConfigureRefresh(refresh =>
{
refresh.Register("QueueName", refreshAll: true)
.SetCacheExpiration(TimeSpan.FromSeconds(5));
});
});
Configuration = configurationBuilder.Build();
builder.Services.Replace(ServiceDescriptor.Singleton(typeof(IConfiguration), Configuration));
}
}
}
view raw startup2.cs hosted with ❤ by GitHub

Now this is interesting. If you are not aware, Function Apps are, for better or worse, built on much of the same compute infrastructure as App Service. App Service has a feature called WebJobs which allowed them to perform actions in the background – much of this underlying code seems to be in use for Azure Functions. FunctionsStartup, which is what is recommended for the Function App startup process, abstracts much of this into a more suitable format for Function Apps.

Here we are actually leveraging the old WebHost routines and replacing the configuration loaded by the Function Host as part of Function startup. This lets us build the Configuration as we want, thereby ensuring the Function Host is aware of the value coming in from App Configuration and supporting the binding to the Trigger parameter.

As a side note, you will notice that I am building configuration twice. The first time is so I can bring in Environment variables (values from the Function Configuration blade in Azure) which contains the endpoint for the App Configuration service.

The second time is when I build by IConfiguration type variable and then run replace to ensure the values from App Configuration are available.

Something to keep in mind

The %% syntax is a one-time bind. Thus, even though App Configuration SDK does support the concept of polling, if you change a value in Configuration service and it gets loaded via the poller the trigger bindings will not be affected – only the executing code.

Now, I dont think this is a huge issue because I dont think most use cases call for a real time value change on that binding and you would need the Function Host to rebind anyway. Typically, I think a change like this is going to be accompanied by a change to the code and a deployment which will force a restart anyway. If not, you can always indicate a restart action to the Function App itself which will accomplish the same goal.

One thought on “Configuring Function Apps to Use Azure App Configuration

Leave a comment