Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Dependency Injection in Azure Functions

DZone 's Guide to

Dependency Injection in Azure Functions

Using dependency injection in Azure Functions can be especially handy when dealing with shared libraries and/or components.

· Cloud Zone ·
Free Resource

Azure Functions V2 supports ASP.NET Core functions like dependency injection. It is especially good if we write wrapper functions for shared libraries and components we are also using in web and other applications of our solution. This blog post shows how to use dependency injection in Azure Functions.

To get started with the code, check out Azure Functions with DI GitHub repository by @MikaBerglund. It's simple and minimal Visual Studio solution without any overhead.

Preparing the Code

Let's start with simple classes I previously used in this blog post ASP.NET Core: Inject all instances of interface. There's an interface for alerts service, and here, we use here service implementation that sends an alert to e-mail. Service uses customer class to get customer e-mail.

public class Customer
{
    public string Name { get; set; }
    public string Email { get; set; }
    public string Mobile { get; set; }
}

public interface IAlertService
{
    void SendAlert(Customer c, string title, string body);
}

public class EmailAlertService : IAlertService
{
    public void SendAlert(Customer c, string title, string body)
    {
        if (string.IsNullOrEmpty(c.Email))
        {
            return;
        }

        Debug.WriteLine($"Sending e-mail to {c.Email} for {c.Name}");
    }
}


Azure Functions Startup Class

The startup class is supported by Azure Functions V2. It's similar to one we know from ASP.NET Core but there are differences. To make dependency injection work, we must add a reference to Microsoft.Azure.Functions.Extensions to our Azure Functions project.

After our namespaces section in the Startup class, we have to define the FunctionsStartup attribute for assembly.

[assembly: FunctionsStartup(typeof(AzureFunctionsDI.Startup))]  


Our function's Startup class extends the FunctionsStartup class.

public abstract class FunctionsStartup : IWebJobsStartup
{
    protected FunctionsStartup();

    public abstract void Configure(IFunctionsHostBuilder builder);
    public void Configure(IWebJobsBuilder builder);
}


We have to define at least Configure() method that is called with functions host builder.

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddScoped<IAlertService, EmailAlertService>();
    }
}


We can add also other service registrations in this method. It seems like functions are on halfway to the Startup class we know from ASP.NET Core.

Injecting Instances to Azure Functions

With Azure Functions V2, we can use dependency injection similar to ASP.NET Core. A minimal default HTTP-triggered function is shown here.

public static class Function1
{ 
    [FunctionName("Function1")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");

        return await Task.FromResult(new OkObjectResult("OK"));
    }
}


To make it work with dependency injection, we have to move from static scope to instance scope and use constructor injection, as shown here.

public class Function1
{
    private readonly IAlertService _alertService;

    public Function1(IAlertService alertService)
    {
        _alertService = alertService;
    }

    [FunctionName("Function1")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");

        var customer = new Customer { Name = "John", Email = "john@example.com" };
        var title = "Emergy alert";
        var body = "The roof is on fire!";

        _alertService.SendAlert(customer, title, body);

        return await Task.FromResult(new OkObjectResult("OK"));
    }
}


Running the functions project and setting a breakpoint to the line in the constructor where IAlertService is assigned allows us to see if the instance is injected to functions class.

No errors, the function is running, and we have an instance of IAlertService injected to our function.

Injecting All Instances of the Interface

Similar to ASP.NET Core, we can also inject all instances of the interface to the function. I added a new implementation of IAlertService to the project.

public class SmsAlertService : IAlertService
{
    public void SendAlert(Customer c, string title, string body)
    {
        if (string.IsNullOrEmpty(c.Mobile))
        {
            return;
        }

        Debug.WriteLine($"Sending SMS to {c.Mobile} for {c.Name}");
    }
}


Then, I registered it to the dependency injection in the function's Startup class.

public class Startup : FunctionsStartup
{
    public override void Configure(IFunctionsHostBuilder builder)
    {
        builder.Services.AddScoped<IAlertService, EmailAlertService>();
        builder.Services.AddScoped<IAlertService, SmsAlertService>();
    }
}


Here is how my function looks with the injection of all IAlertService instances.

public class Function1
{
    private readonly IEnumerable<IAlertService> _alertServices;

    public Function1(IEnumerable<IAlertService> alertServices)
    {
        _alertServices = alertServices;
    }

    [FunctionName("Function1")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");

        var customer = new Customer { Name = "John", Email = "john@example.com" };
        var title = "Emergy alert";
        var body = "The roof is on fire!";

        foreach (var alertService in _alertServices)
        {
            alertService.SendAlert(customer, title, body);
        }

        return await Task.FromResult(new OkObjectResult("OK"));
    }
}


Running the function with breakpoint same way as before shows that both registered instances of IAlertService class are injected to function.

Dependency injection with Azure Functions V2 works like dependency injection in ASP.NET Core.

Wrapping Up

With Azure Functions V2, we can use the same dependency injection mechanism as in ASP.NET Core. There are differences like no support for direct injection through function arguments (ASP.NET Core supports controller action injection) but the basics are all the same. Support for dependency injection makes it easier to re-use the same components and services we are using in web applications through dependency injection.

Topics:
cloud ,azure ,dependency injection ,di ,functions

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}