A Practical Guide to Azure Durable Functions — Part 2: Dependency Injection

Everything you need to know to create a production-ready function app via Azure Durable Functions.

Allen Zhang
The Startup
Published in
6 min readMay 29, 2020

--

Please read the first article of the series if you haven’t already.

In the second part of the series, we will:

  • Introduce the GitHub repo view count app.
  • Implement DI via autofac.
  • Implement DI via .NET core framework.

The Application

This demo app has a simple logic: it gets a user’s repo list from GitHub, then it gets the view count of each repo, and finally, it prints the view counts. The code can be found in my GitHub repo.

The app implements the Azure Durable Function’s fan-out/fan-in pattern. In real work projects, there are a lot of applications that implement a similar workflow:

  1. Get a list of items.
  2. Process each item concurrently (fan-out).
  3. Get results and do something with it. For example, send them via an email or save them in blob storage (fan-in).

There is a “Mode” variable in the settings file. It lets us easily run the same durable function with three different configurations:

  • naive: no DI.
  • autofac: DI via autofac.
  • core: DI via .NET core framework.

You might have also noticed that the code gets settings from environment variables. You need to set these variables in the local.settings.json file with your real GitHub username and password when you develop locally.

Run the Function App Locally

Let’s test the updated function app locally. Please make sure the “Mode” config is set to “naive”. If you have run this function app locally before, you might need to clear the Azure Storage Emulator because you have renamed one of the activity function.

Run this command to clear the emulator.

You might want to add the emulator’s installation directory to the Path. The installation directory on my PC is:

If all goes well, you should see something like this:

That’s right… at the time of this writing, I only have one repo and the view count is only 4 😢.

But something is interesting about the output: that “repository list” message appeared twice. If you scroll up, it appeared 3 times.

Why?

Microsoft has a document about the event sourcing pattern the orchestrator function uses. But I’ll try to explain it in human-friendly language:

The orchestrator code execution stops when it sees an “await” and stores the state in an Azure Storage Account — that’s why it’s a stateful Azure Function. It then runs the code from the beginning over and over again to check the awaited tasks. Once they are complete, it stores the state (and the output from the tasks if you save them to a local variable) in the storage account and carries on the execution after the “await” statement. Because of this behavior, the orchestrator functions need to be deterministic. Imagine you use DateTime.UtcNow in your orchestrator. Each time the orchestrator code is replayed, DateTime.UtcNow will have a different value.

Dependency Injection via Autofac

Now the naive implementation works. But it’s not very good. We want to create a GitHubApiService and move all GitHub related logic to this service. And we want to follow good software engineering practice so we’ll introduce dependency injection to our code.

Before Azure Functions Runtime V2, functions’ methods and classes have to be static. Hence, the normal .NET core dependency injection pattern cannot be applied because private instances are not allowed in a static class.

Autofac comes to rescue. Let’s set up dependency injection via autofac.

The GitHubApiServiceAutofac.cs can be found in the GitHub repo. It implements IGitHubApiService.cs interface. We want to inject this service into our activity functions.

Dependency injection is configured in ServicesModule.cs:

The default scope of type registration is “instance per dependency”. You can read more about autofac DI scopes here.

To differentiate from the naive implementation, I created a folder ActivityFunctionsAutofac and put activity functions with autofac DI in it. The key is the [Inject] attribute.

Don’t forget to set the “Mode” to “autofac” if you want to try it locally.

Dependency Injection via .NET Core Framework

Now we have extracted GitHub API logic into its service and we have DI. But I’m still not very happy because it requires a third party library autofac. What if I want to use a library that has an IServiceCollection extension to set up its dependencies? We normally do it in the Startup class. But this autofac DI implementation doesn’t have one.

The good news is that we can follow the normal .NET Core DI approach with Microsoft.Azure.Functions.Extensions nuget package installed.

DI is configured in the Startup class like other .NET Core framework projects. But Azure Function projects are created without a Startup.cs file. We need to add one ourselves.

The scope of the DI registration is part of the method name. This service is registered as a singleton. Microsoft documents the scopes here.

ActivityFunctionsCore folder is created for the .NET Core framework DI functions. Let’s have a look at one example.

This looks very much .NET Core native. Because we host our function app on Azure Functions Runtime V3 the class and method don’t have to be static. This is how DI is done in a regular .NET core project. It allows us to create an IServiceCollection extension and share it with other .NET Core projects. Or use one from a library in the Startup class.

To try this implementation, simply set the “Mode” to “core” and hit F5 in visual studio.

Update the Pipeline

We need to update the pipeline to pass environment variables as app settings to our deployed functions on Azure.

Define two new variables for the username and password, then reference them in the AzureFunctionApp job. If the variable value contains space, you need to wrap them up with double-quotes.

Wait for the pipeline to do its job, and then verify the app settings on the Azure portal.

Summary

In this article, we developed a durable function with the fan-out/fan-in pattern that reports a user’s GitHub repositories’ view counts. We have created three implementations: no DI, DI via autofac, and DI via .NET Core framework.

I generally prefer the .NET Core framework DI. IServiceCollectionextension extension method is widely used in libraries you may want to use. And you might need to create one in your project for others to use. But if you have to use static classes and methods for some reason, go with Autofac.

Now we have our DI framework in place. But I’m still not very happy about how configurations are handled in our code. Can we use .NET Core’s wonderful configuration manager in Azure functions? Can we protect the secret config item GitHubPassword?Can we use the amazing Azure Key Vault service to do that? We will answer these questions in the next story of the series.

Part 3 is available here.

--

--