Dependency Injection and Injecting Multiple Instances of an Interface in Azure Functions

Time to Read: 4 minutes

This is a short and fun scenario that I tried out while playing around with the dependency injection in Azure Functions Runtime V2 (.NET Core run-time).

The Dependency Injection support in Azure Functions comes with a lot of advantages. Some are

  1. We get loosely coupled code, our functions are no more tied with concrete classes
  2. We get the ability to unit test our code more easily as we can implement fakes of our interfaces
  3. There are no more static functions, we can inject the dependencies directly into the class constructors (Constructor Injection)
  4. With inbuilt support for dependency injection, we do not have to rely on external DI containers like Autofac(Which I like very much by the way!)

Now let us take look at a fictional scenario

Scenario

Let us consider a scenario where we are catering to different types of customers who avail the products of our dummy company. I have one function which caters to normal customers and one function for elite customers. The function for normal customers sends SMS notifications to customer of company discounts etc, while the function for the Elite customer sends both a SMS and a phone call from company execute. Now I understand this not a very viable scenario, but it will suffice for our POC.

Implementation

We begin by creating a new function project in Visual studio. You can also replicate this example in VS code.

We now add following NuGet packages to set up support for dependency injection in Azure functions

Microsoft.Azure.Functions.Extensions available at ( https://www.nuget.org/packages/Microsoft.Azure.Functions.Extensions/ )

Microsoft.NET.Sdk.Functions available at https://www.nuget.org/packages/Microsoft.NET.Sdk.Functions/

Now let us add our interface for Notification Services. It is as shown below

Now Let us create the classes that implement this interface.

Following is the class which invokes the phone call process. Right now it does not do anything other than logging, but that should be sufficient to understand the concept.

Following is the class which invokes the SMS notification process. Right now it does not do anything other than logging, but that should be sufficient to understand the concept.

Now we register these concrete implementations with the FunctionHostBuilder so that they are injected into the function class constructors. We do this by adding a class called Startup.cs to the project. The code in startup looks as follows

To keep things simple, I have registered the concrete implementations as Scoped, meaning the instances are created once per a service request. To read more about the Instance lifetimes refer to official documentation at https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2#service-lifetimes

Now the hard work is done. All we need to do is implement our functions.

My Function to Process normal customers looks like following.

Notice we do not have static instances of classes or function any more!!

My Function to Process Elite customers looks like following.

Notice I am providing an IEnumerable of Type INotificationSeervice instead of INotificationService as parameter to my function class constructor.

This IEnumberable<T> is what does the magic!!. That is it

Now let us test our functions

Testing the Functions

I started by running the functions project in a debug mode. The functions runtime generated following urls for me.

I tested the ProcessNormalCustomer function first by executing the Get request from the browser. We can see that an instance of SMSNotification which implements the INotificationService service is injected in the constructor.

After that I tested the ProcessEliteCustomer functions and following was the output.

The output clearly shows that instances for both the implementations for INotificationService were injected into the function.

Wrapping Up

Following can be concluded from the POC

  1. The in built support for Dependency Injection makes life much more simpler as we do not need to deal with static functions
  2. When multiple implementations of an interface are registered, the last one always gets injected
  3. To inject all the registered implementations of the interface, we pass IEnumerable<T> in the constructors.

Programmer by profession, curious by nature.