Azure Functions with Dependency Injection

Azure Functions got some improvements in the last months. Now it’s no longer necessary to create static methods, instance methods can be used, and dependency injection using Microsoft.Extensions.DependencyInjection is built-in. How this can be done is explained in this article.

Breaking Chains

Azure Functions

Azure Functions are part of the Azure Functions as a Service (FaaS) category which allow pay-per-use payment models. Depending on how the function is used, this offers cheap prices but also great scalability. On the other hand, it’s also possible to use the same Azure Function and configure it with a full-blown App-Service plan which belongs to the Platform as a Service (PaaS) category where a virtual machine needs to be calculated with the cost. This increases the time, the Azure Function can run (extending it from the maximum 10 minutes with the FaaS version), and you don’t pay-per-use.

Azure Functions can be triggered when a message arrives in a queue, a timer based on a CRON configuration, HTTP requests arrive, and more.

The sample application makes use of EF Core and injects an EF Core context in the Azure function.

.NET Standard Library

The library that is used with the sample application defines the EF Core context to access a database. The sample application just uses the Book type and defines a simple BooksContext that is prepared for dependency injection:

public class Book
{
    public int BookId { get; set; }
    public string Title { get; set; }
    public string Publisher { get; set; }
}
public class BooksContext : DbContext
{
    public BooksContext(DbContextOptions<BooksContext> options)
        : base(options)
    {
    }

    public DbSet<Book> Books { get; set; }
}

Register Services

To register services, the NuGet package Microsoft.Azure.Functions.Extensions needs to be added. This package just contains the FunctionsStartup attribute, the FunctionsStartup class, and the interface IFunctionsHostBuilder. The attribute FunctionsStartup can be applied on assembly-scope to define the type of the Startup class. The Startup class can derive from the FunctionsStartup abstract base class. The method Configure needs to be overridden – this method makes use of the IFunctionsHostBuilder type as the parameter. The interface IFunctionsHostBuilder specifies the Services property of type IServiceCollection. This is the well-known interface from Microsoft.Extensions.DependencyInjection where all the services can be configured with the DI container. In the sample code, the AddDbContext extension method is used to register the services used by EF Core.

using BooksLib;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;

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

namespace FunctionAppWithDI
{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddDbContext<BooksContext>(config =>
            {
                config.UseSqlServer(Environment.GetEnvironmentVariable("BooksConnection"));
            });
        }
    }
}

Injecting Services

With the DI configuration in place, the EF Core context BooksContext can be injected with the Azure function. The Azure Function from this sample is triggered on HTTP requests. In the constructor, the BooksContext is injected, which is then used in the function implementation to return a list of books:

public class SampleFunction
{
    private readonly BooksContext _booksContext;
    public SampleFunction(BooksContext booksContext) => _booksContext = booksContext;

    [FunctionName("SampleFunction")]
    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("SampleFunction invoked to process a request");

        var books = await _booksContext.Books.ToListAsync();
        return new OkObjectResult(books);
    }
}

Running the application in the simulator, the local SQL Server database is accessed to return a list of books.

Books returned from the Azure Function

Take away

Using dependency injection allows for easier maintainability, testability, and flexibility. You can create service types independent of the hosting technology, and use the same implementation in different technologies. For example, you can use the same implementation with Azure Functions as well as ASP.NET Core Web APIs. It’s just a matter of configuring the hosting technology with it’s dependency injection container.
Using Azure Functions, you can now use Microsoft.Extensions.DependencyInjection in a similar way to ASP.NET Core Web applications using simple attributes and types with the NuGet package Microsoft.Azure.Functions.Extensions.

Enjoy learning and programming!

Christian

If you’ve read this far, consider buying me a coffee which helps me staying up longer and writing more articles.

Buy Me A Coffee

More information on C#, EF Core, APIs, and programming .NET Core applications is in my book Professional C# 7 and .NET Core 2.0, and in my workshops.

Articles related to the content:

Microsoft – using dependency injection in .NET Azure Functions

Hosting DI Container with .NET Core 3

.NET Core Dependency Injection with Configuration

Disposing Injected Services

Dependency Injection with .NET Core

HTTP Client Factory with .NET Core 2.1

And here more information on the topmost image with this blog:

Image ID 10491981 © Peterdenovo, Dreamstime.com

One thought on “Azure Functions with Dependency Injection

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.