The simplicity of Azure Functions makes it tempting to avoid following good design practices like dependency injection. The default project template doesn’t even support it. This may be fine for learning and quick experiments but would be a mistake for production code. Simplicity is not an excuse for bad engineering.
Luckily, setting up dependency injection in Azure Functions C# projects is easy. We can configure a .NET Azure Functions project to use the Microsoft.Extensions.DependencyInjection library that is widely used in ASP.NET Core. This post will show you how.
Install Prerequisites
First, we need to install some NuGet dependencies.
dotnet add package Microsoft.Extensions.DependencyInjection | |
dotnet add package Microsoft.Azure.Functions.Extensions |
Create a Startup Class
Then we need to define a Startup
class. This is very similar to the Startup class used in some ASP.NET Core projects except it extends the FunctionsStartup
class. We register our services with the dependency injection system inside the Startup.Configure
method.
using Microsoft.Azure.Functions.Extensions.DependencyInjection; | |
using Microsoft.Extensions.DependencyInjection; | |
[assembly: FunctionsStartup(typeof(DIExample.Startup))] | |
namespace DIExample | |
{ | |
public class Startup : FunctionsStartup | |
{ | |
public override void Configure(IFunctionsHostBuilder builder) | |
{ | |
builder.Services.AddTransient<IMyService, MyService>(); | |
} | |
} | |
} |
We also need to add the FunctionsStartup
attribute (highlighted above) so the functions runtime knows to run this code on application start. Without that attribute, none of this will work.
Update Functions to use Dependency Injection
The framework we’re using injects dependencies into a class’s constructor. By default, functions are static methods in static classes and don’t have a constructor. We’ll need to remove the static keyword from the class and function. Don’t worry though, the runtime doesn’t require functions to be static.
Once the function and class are no longer marked as static we can define a constructor that accepts our dependencies and use them in our function.
using System.Threading.Tasks; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.Azure.WebJobs; | |
using Microsoft.Azure.WebJobs.Extensions.Http; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.Extensions.Logging; | |
namespace DIExample | |
{ | |
public class HttpTrigger | |
{ | |
private readonly IMyService _myService; | |
public HttpTrigger(IMyService myService) | |
{ | |
_myService = myService; | |
} | |
[FunctionName(“MyHttpTrigger“)] | |
public async Task<IActionResult> Run( | |
[HttpTrigger(AuthorizationLevel.Anonymous, “get“, Route = null)] HttpRequest req, | |
ILogger log) | |
{ | |
// Call the service that the dependency injection system gave us | |
await _myService.DoSomethingAsync(); | |
return new NoContentResult(); | |
} | |
} | |
} |
That’s all! Your project is now ready to go.