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
ScriptHostloads all function metadata from yourfunction.jsonfiles. - The
ExtensionLoaderexamines all parameters with aBindingAttributeof each function and gathers the Assembly where theBindingAttributeis defined! - The
ExtensionLoaderretrieves all exported types of the assembly - The
ExtensionLoaderchecks each exported type if it implementsIExtensionConfigProvider - The
ExtensionLoaderusesActivator.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>