Azure Functions - Extension resolution and loading.
Implementing IExtensionConfigProvider
in a Function App is a common way to run code at startup of the Function App. It is also the place to register the components of your extension. In this post I will describe how Azure Functions finds and instantiates IExtensionConfigProvider
implementations.
There are several ways how an IExtensionConfigProvider
implementation is found.
Auto detection
The auto detection works in Azure Functions V1 and V2.
Auto detection of IExtensionConfigProvider
implementation starts when the ScriptHost
gets initialized.
- The
ScriptHost
loads all function metadata from yourfunction.json
files. - The
ExtensionLoader
examines all parameters with aBindingAttribute
of each function and gathers the Assembly where theBindingAttribute
is defined! - The
ExtensionLoader
retrieves all exported types of the assembly - The
ExtensionLoader
checks each exported type if it implementsIExtensionConfigProvider
- The
ExtensionLoader
usesActivator.CreateInstance
(with no further arguments) to instantiate theIExtensionConfigProvider
Pseudo code
var functionMetadata = LoadAllFunctionMetadata();
foreach (var function in functionMetadata)
{
var attributes = ExtensionLoader.GetAllReferencedBindingAttributes(function);
foreach (var attribute in attributes)
{
var assembly = GetAssemblyWhereAttributeIsDefined(attribute);
var types = assembly.GetExportedTypes();
foreach (var type in types)
{
if (type implements IExtensionConfigProvider)
{
Activator.CreateInstance(type);
}
}
}
}
While the auto detection is very convenient it also only works if we define and use a custom BindingAttribute
.
V1 - Auto detect from extension path
This only works in Azure Functions V1.
Azure Functions can also load additional extensions from a given path. For this you need to set AzureWebJobs_ExtensionsPath
either in your local.settings.json
or in Azure in the AppSettings to a path where your extensions are located.
Example
{
"Values": {
"AzureWebJobs_ExtensionsPath": "."
}
}
Within this folder the ExtensionLoader
looks for .dll
files, that have extension
in their filename. It then retrieves all exported types of the assembly and checks if they implement IExtensionConfigProvider
. If so it will instantiate the type.
V2 - Manual via config file
This only works in Azure Functions V2.
Beside the auto detection Azure Functions also can instantiate an IExtensionConfigProvider
via a config file. This is useful if you want to run code at startup without having a custom BindingAttribute
.
After the ScriptHost
auto detected IExtensionConfigProvider
implementation it checks if the Function App contains an extensions.json
file. The file must be placed in the bin
folder of the output directory! In the extensions.json
we can define which additional IExtensionConfigProvider
implementation should be loaded. The json file must contain an object with a property named extensions
. The property must contain an array of objects with a property named TypeName
.
Example:
{
"extensions": [
{
"TypeName": "MyFunctionApp.MyExtensionConfigProvider, MyFunctionApp"
}
]
}
If you want to have your extensions.json
copied into the bin
after each build, you can adjust your .csproj file.
<Target AfterTargets="Build" Name="CopyExtensions">
<Copy SourceFiles="extensions.json" DestinationFolder="$(OutputPath)\bin" ContinueOnError="true" />
</Target>