A simple package that allows you to configure Azure Functions trigger in the dotnet-isolated process similarly to the In-Process model.
$ dotnet add package AzureFunction.Isolated.HostConfiguratorThe new dotnet-isolated hosting model of Azure Functions doesn't allow you to configure the connection for triggers or binding the same way it does in the In-Process model. This is a problem when you want to use a connection string from Key Vault, for example.
The problem is that the host process needs the connection before it calls into your code (i.e. before your Program.cs is called) so you only have a couple of ways to configure it:
local.settings.json fileBoth of these options may not be sufficient to cover your scenario so this package helps you work around this limitation that will hopefully be resolved soon on the Azure Functions side. See this issue and this issue for context.
Azure Functions using the dotnet-isolated hosting model will load the extensions that your project references and will initialize the extensions before trying to resolve the connection strings.
This step happens inside the AddScriptHost method of the ScriptHostBuilderExtensions when the host calls the HasExternalConfigurationStartups() method. (the code I'm talking about here is in the azure-function-host project on GitHub here.
So this package essentially hooks into that functionality to allow you to customize the host configuration before it's used.
This package implements a WebJob extension that will delegate the configuration to a type that you have to implement and specify in your project using the assembly attribute [HostConfiguratorAttribute(typeof(TheTypeToBeInvoked))].
You need to specify a type that implements the interface IWebJobsConfigurationStartup from the package Microsoft.Azure.WebJobs in the attribute, this type will then be invoked by this extension allowing you to add additional configuration sources to the host configuration.
AzureFunction.Isolated.HostConfigurator into your Azure Functions dotnet-isolated project or in a separate class library project that targets net6.0 if your function project targets net7.0.dotnet add package AzureFunction.Isolated.HostConfigurator
IWebJobsConfigurationStartup from the package Microsoft.Azure.WebJobs in your project.
This is where you will add your custom configuration sources.internal class StartupExtension : IWebJobsConfigurationStartup
{
public void Configure(WebJobsBuilderContext context, IWebJobsConfigurationBuilder builder)
{
// Please note the usage of the context.ApplicationRootPath to get the path to the application root, where we can find our configuration files
builder.ConfigurationBuilder
.AddJsonFile(Path.Combine(context.ApplicationRootPath, "appsettings.json"), optional: false, reloadOnChange: false)
.AddJsonFile(Path.Combine(context.ApplicationRootPath, $"appsettings.{context.EnvironmentName}.json"), optional: false, reloadOnChange: false)
.AddEnvironmentVariables();
}
}
[HostConfiguratorAttribute(typeof(TheTypeToBeInvoked))] to your project.[assembly: HostConfiguratorAttribute(typeof(StartupExtension))]
ConfiguratorAssemblyName configuration with the name of the assembly that contains the [assembly: HostConfiguratorAttribute] attribute. Such configuration can be added to either the host.json, the appsettings.json or as an environment variablehost.json example
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"excludedTypes": "Request"
}
}
},
"ConfiguratorAssemblyName": "FunctionApp1.dll"
}
This package provides a workaround for an unsupported functionality loading an assembly that you specify into the function host process, this comes with a set of limitations and constraints as you can see below.
If you need to call AddJsonFile('appsettings.json'), make sure to call Path.Combine(context.ApplicationRootPath, "appsettings.json") because the host will not be running from the same directory your code is running from.
If you use a single assembly approach, you're forced to target net6.0 and your assembly will be loaded twice, once in the host process and once by the Azure Functions host. If you have any static initialization code, it may potentially be called twice. To prevent this issue you should define a standalone assembly that contains the configuration code instead of adding the type in your functions code directly.
If you need an assembly reference in your configuration class, you have to make sure it can be loaded in the host process (the function host) that targets .NET 6.0. Keep the code in the host configurator class as small as possible, and if your function needs to target net7.0, place your custom configuration class in a separate assembly and target net6.0.
Since local.settings.json is not published during deployment, I decided not to include that file in the assembly name lookup here. If you add the appsettings.json file, make sure to set the Copy to Output Directory property to Copy always or Copy if newer so that the file is copied to the output directory during the build process.
Please note that you're also constrained about the version of the packages that you're using, for KeyVault and App Configuration, you can copy that from the relative samples.
You may get a warning telling you that: The Functions scale controller may not scale the following functions correctly because some configuration values were modified in an external startup class.
This is caused by a validation that checks if the configuration values have been modified by an external startup class, which is the case here since the original configuration has no means to read from the additional configuration sources we want to add. This warning can be safely ignored since it's the problem this library tries to solve.
If you want to dig deeper, this behavior is implemented in the ExternalConfigurationStartupValidator in the azure-functions-host project.
Note that if you use managed identities with e.g. Azure Service Bus you won't get the warning because the configuration value is null but not the nested configuration called
fullyQualifiedNamespaceand the service only checks for top level ones.
Debugger.Launch() method to attach a debugger to the process.Check the /samples folder for some sample projects.
This has been tested on Visual Studio 17.6.5 and via the func cli 4.0.5085 both of which can successfully run a project as well as deployed in Azure Function.