Azure Functions Dependency Injection with Autofac

This post refers specifically to Azure Function V2.

If you want to write automated tests for Azure Functions methods and want to be able to control dependencies (e.g. to inject mock versions of things) you can set up dependency injection.

One way to do this is to install the AzureFunctions.Autofac NuGet package into your functions project.

Once installed, this package allows you to inject dependencies into your function methods at runtime.

Step 1: Create DI Mappings

The first step (after package installation) is to create a class that configures the dependencies. As an example suppose there was a function method that needed to make use of an implementation of an IInvestementAllocator. The following class can be added to the functions project:

using Autofac;
using AzureFunctions.Autofac.Configuration;

namespace InvestFunctionApp
{
    public class DIConfig
    {
        public DIConfig(string functionName)
        {
            DependencyInjection.Initialize(builder =>
            {
                builder.RegisterType<NaiveInvestementAllocator>().As<IInvestementAllocator>(); // Naive

            }, functionName);
        }
    }
}

In the preceding code, a constructor is defined that receives the name of the function that’s being injected into. Inside the constructor, types can be registered for dependency injection. In the preceding code the IInvestementAllocator interface is being mapped to the concrete class NaiveInvestementAllocator.

Step 2: Decorate Function Method Parameters

Now the DI registrations have been configured, the registered types can be injected in function methods. To do this the [Inject] attribute is applied to one or more parameters as the following code demonstrates:

[FunctionName("CalculatePortfolioAllocation")]
public static void Run(
    [QueueTrigger("deposit-requests")]DepositRequest depositRequest,
    [Inject] IInvestementAllocator investementAllocator,
    ILogger log)
    {
        log.LogInformation($"C# Queue trigger function processed: {depositRequest}");

        InvestementAllocation r = investementAllocator.Calculate(depositRequest.Amount, depositRequest.Investor);
    }

Notice in the preceding code the [Inject] attribute is applied to the IInvestementAllocator investementAllocator parameter. This IInvestementAllocator is the same interface that was registered earlier in the DIConfig class.

Step 3: Select DI Configuration

The final step to make all this work is to add an attribute to the class that contains the function method (that uses [Inject]). The attribute used is the DependencyInjectionConfig attribute that takes the type containing the DI configuration as a parameter, for example: [DependencyInjectionConfig(typeof(DIConfig))]

The full function code is as follows:

using AzureFunctions.Autofac;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;

namespace InvestFunctionApp
{
    [DependencyInjectionConfig(typeof(DIConfig))]
    public static class CalculatePortfolioAllocation
    {
        [FunctionName("CalculatePortfolioAllocation")]
        public static void Run(
            [QueueTrigger("deposit-requests")]DepositRequest depositRequest,
            [Inject] IInvestementAllocator investementAllocator,
            ILogger log)
        {
            log.LogInformation($"C# Queue trigger function processed: {depositRequest}");

            InvestementAllocation r = investementAllocator.Calculate(depositRequest.Amount, depositRequest.Investor);
        }
    }
}

At runtime, when the CalculatePortfolioAllocation runs, an instance of an NaiveInvestementAllocator will be supplied to the function.

The library also supports features such as named dependencies and multiple DI configurations, to read more check out GitHub.

If you want to fill in the gaps in your C# knowledge be sure to check out my C# Tips and Traps training course from Pluralsight – get started with a free trial.

SHARE:

Comments (10) -

  • Cedric

    2/7/2019 9:36:27 PM | Reply

    Hi,

    Thanks for your post.
    My Service need an IOptions<MySettings> implementation, using your sample, how can I add my configuration?

    • Venkatesh

      5/8/2019 5:19:02 PM | Reply

      I guess the below code snippet should inject the IConfiguration

      public DIConfig(string functionName, string baseDirectory)
          {
            DependencyInjection.Initialize(builder =>
            {
              // Reading the configuration.
              var config = new ConfigurationBuilder().SetBasePath(baseDirectory).AddJsonFile("local.settings.json", optional: true, reloadOnChange: true).AddEnvironmentVariables().Build();

              builder.Register(c => config).As<IConfiguration>().SingleInstance();

              builder.RegisterType<TableStorageRepository>().As<ITableStorageRepository>(); // TableStorage
              builder.RegisterType<BlobStorageRepository>().As<IBlobStorageRepository>(); // Blob Storage



            }, functionName);
          }

      • Jason Roberts

        5/9/2019 12:22:52 AM | Reply

        Thanks Venkatesh

      • Cédric Arnould

        5/27/2019 3:36:51 PM | Reply

        Thanks Smile

  • Ehsan

    8/6/2019 10:39:52 AM | Reply

    very useful! thanks for sharing,

  • Pavitra

    8/27/2019 8:12:52 AM | Reply

    Hi,
    I'm implementing  constructor dependency injection for my azure functions. Any idea how to achieve with autofac? Thanks in advance

  • tejinder singh

    8/29/2019 12:12:46 PM | Reply

    Hi,

    Thanks for your post.
    My Service need an IHttpClientFactory implementation, using your sample, how can I add that?

  • sam

    2/19/2020 5:21:10 AM | Reply

    Hi,
    Lets say P is parent class, it has 2 childs C1, C2
    C1 has 2 childs  GC11 and GC12
    C2  has 1 child GC21
    Interface I is implemented by class P.
    Now I want to create object of  any grantchild of P through autofac using dependency injection in azure function

  • Sandeep Kumar

    3/31/2020 6:40:33 PM | Reply

    I have function Named "Function" and I am using the above code for Autofac dependency. However, when I start the Azure function, public DIConfig(string functionName) gets called twice, not sure how.
    Also What If I would want to get a Service from the Builder just created with DependencyInjection.Initialize and call some method on that just after initialization has finished.
    I tried doing   IContainer servicesCollection = builder.Build();
                    var eventBus = servicesCollection.Resolve<IMyInterface>();
    It throws an exception that container cant be built twice.

  • Lisa Thompson

    9/7/2020 1:24:11 PM | Reply

    how would you setup a UnitTest projec that will call the function and test the output? Meaning I want the DIConfig to be setup in the test and then I call the function method Run()

Add comment

Loading