This enables Azure Functions to utilise an IoC container offered by ASP.NET Core.
This is only applicable to Azure Functions V2, as V2 runtime now take out the static modifier. The more details around the constructor injection approach on Azure Functions can be found on this blog post.
In order to use dependency injections, all dependencies should be registered through the StartUp class implementing the IWebJobsStartup interface.
[assembly: WebJobsStartup(typeof(StartUp))]
namespace Aliencube.AzureFunctions.FunctionAppV2
{
public class StartUp : IWebJobsStartup
{
public void Configure(IWebJobsBuilder builder)
{
builder.Services.AddSingleton<AppSettings>();
builder.Services.AddTransient<ISampleHttpFunction, SampleHttpFunction>();
builder.Services.AddTransient<ISampleTimerFunction, SampleTimerFunction>();
builder.Services.AddTransient<IMyDependency, MyDependency>();
}
}
}Any Azure Function trigger does not require the static modifier any longer. Because of this, it is possible to use the constructor injection approach like below:
public class SampleHttpTrigger : TriggerBase<ILogger>
{
private readonly ISampleHttpFunction _function;
public SampleHttpTrigger(ISampleHttpFunction function)
{
this._function = function ?? throw new ArgumentNullException(nameof(function));
}
[FunctionName(nameof(GetSample))]
public async Task<IActionResult> GetSample(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "samples")] HttpRequest req,
ILogger log)
{
var result = await this._function
.AddLogger(log)
.InvokeAsync<HttpRequest, IActionResult>(req)
.ConfigureAwait(false);
return result;
}For Azure Function V1, the most efficient way for dependency injection would be the property injection approach. The more details around the property injections on Azure Functions can be found on this blog post.
This extension supports the
property injectionapproach. However, if themethodd injectionapproach is preferred, visit https://github.com/rikvandenberg/AzureFunctions.Extensions.DependencyInjection.
In order to use dependency injection, all dependencies should be registered beforehand. The Module class needs to be inherited then all dependencies are registered within the Load(IServiceCollection services) method.
public class StartUp : Module
{
public override void Load(IServiceCollection services)
{
services.AddSingleton<AppSettings>();
services.AddTransient<ISampleHttpFunction, SampleHttpFunction>();
services.AddTransient<ISampleTimerFunction, SampleTimerFunction>();
services.AddTransient<IMyDependency, MyDependency>();
}
}ContainerBuilder builds IServiceProvider so that each Function can directly use the IoC container within the method. In order to use the ContainerBuilder into the Function, the IServiceProvider property should be defined as a static property first like:
public static class SampleHttpTrigger
{
public static IServiceProvider Container = new ContainerBuilder
.RegisterModule<StartUp>()
.Build();
[FunctionName("SampleHttpTrigger")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req,
ILogger log)
{
var function = Container.GetService<IFunction>();
var result = await function.InvokeAsync<HttpRequestMessage, HttpResponseMessage>(req)
.ConfigureAwait(false);
return result;
}
}Instead of directly using the ContainerBuilder, the FunctionFactory class might be more useful. In order to use the FunctionFactory into the Function, the IFunctionFactory property should be defined as a static property like:
public static class SampleHttpTrigger
{
public static IFunctionFactory Factory = new FunctionFactory<StartUp>();
[FunctionName("SampleHttpTrigger")]
public static async Task<HttpResponseMessage> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req,
ILogger log)
{
var result = await Factory.Create<ISampleHttpFunction, ILogger>(log)
.InvokeAsync<HttpRequestMessage, HttpResponseMessage>(req)
.ConfigureAwait(false);
return result;
}
}