Prerequisites
- Visual studio with Azure Function enabled
Case
When maintaining multiple Azure Function projects, occasionally we need to duplicate some common-use functions between the projects that are not directly related to the main projects. For example health checks or sending system info messages to a queue. To reduce the duplication and maintenance, we can actually create a Function inside library which will run inside all Azure Function projects which references it.
In this article, I created a brief solution with two Azure Function projects. The content inside those functions can be unrelated to each other, but on each project we need to have an ‘InstanceHealth’ function which writes a health-check report every interval confirming the function is still running. Rather than duplicating the same process and its configuration on each Function module, we will create a library which contains a single function to do the above process and reference it.
For the first step, we need to add the FunctionsInDepedencies
tag inside PropertyGroup in the Azure Function project .csproj
file. This will instruct the Azure Function SDK to load functions defined in referenced libraries.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
. . .
<FunctionsInDependencies>true</FunctionsInDependencies>
</PropertyGroup>
. . .
</Project>
Now we will make a library to be referenced by the function:
- Right click Solution → Add new project → Create new Class library
- Make sure the framework is compatible. For example in my case the Function Project is in .NET 6.0 and shared library with function is .NetStandard2.1
Add Package to write function trigger to the .csproj
file. Required packages will be automatically installed on build
//Project: Shared.HealthCheckFunction
<ItemGroup>
...
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions" Version="3.0.6" />
</ItemGroup>
Create a class with a function inside the library. In this example we are creating an interval based function using TimerTrigger set to run every one minute.
//Project: Shared.HealthCheckFunction
//Filename: HealthCheckFunction.cs
public class HealthCheckFunction
{
HealthCheckConfig config;
public HealthCheckFunction(HealthCheckConfig config)
{
this.config = config;
}
[FunctionName("HealthCheck")]
public async Task Run([TimerTrigger("0 */1 * * * *")] TimerInfo timer, ILogger log, CancellationToken ct)
{
log.LogInformation($"[HealthCheck] From module {config.ModuleName}");
}
}
//Project: Shared.HealthCheckFunction
//Filename: HealthCheckConfig.cs
public class HealthCheckConfig
{
public string ModuleName { get; set; }
}
To assign the HealthCheckConfig
object, we are using Dependency Injection by creating a ServiceCollection class.
//Project: Shared.HealthCheckFunction
//Filename: ServiceCollectionExtensions.cs
namespace Microsoft.Extensions.DependencyInjection
{
public static class HealthCheckServiceCollectionExtensions
{
public static IServiceCollection AddHealthCheckBindings(this IServiceCollection services, string moduleName)
{
services.AddScoped(_ => new HealthCheckConfig() { ModuleName = moduleName });
return services;
}
}
}
Reference the finished library to the main projects. Then we will add the ServiceExtension configuration to the Startup class.
//Project: ModuleFunction1
//Filename: Startup.cs
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
// Get Function AppSetting values for cloud deployment or local.settings.json for local
var configuration = builder.Services.BuildServiceProvider().GetRequiredService<IConfiguration>();
builder.Services.AddHealthCheckBindings(configuration["Module_Name"]);
. . .
}
}
Put the Module_Name
key with string values on local.settings.json or Azure Function App’s Configuration based on where you deploy the Function.
{
"IsEncrypted": false,
"Values": {
"Module_Name": "ModuleFunction1"
}
}
When all configurations are done, now we can run the Function project to test it. HealthCheckFunction will be registered and running like other functions.
Conclusion
By distributing the common-use function to the libraries it will help improve the extensibility of the Azure Function projects.