Dependency Injection In Azure Functions V2

With the Azure Functions v2 runtime, supporting .NET Core it has become easier to do dependency injection. It can be done in a similar way that ASP.NET Core does via Microsoft.Extensions.DependencyInjection.

ASP.NET Core encourages the use of dependency injection by the built-in DI container. This feature of ASP.NET Core is very handy as many extensions such as logging and configuration via IOptions pattern are registered using during startup in Startup.cs. ASP.NET Core registers these services, along with any custom services you need using the built-in DI container via IServiceCollection.

This feature of ASP.NET Core can be utilized for dependency injection in Azure Functions V2 as it comes with .NET Core. We can create a container by creating an instance of IServiceCollection and then registering the services we need.

Let’s see this in action with an example. We’ll create an Azure Function that returns a list of time zones. These time zones are maintained in a JSON file uploaded to Azure blob storage. Even though it is a very simple scenario, my solution consists of three different projects as below:

  • Function app project. Azure.Functions.v2.DI.FunctionApp. This is the project that contains an HTTP-triggered Azure function, which returns the list of time zones via an HTTP GET.
  • Helper project. Azure.Functions.v2.DI.Helpers. As the name suggests this contains helper class to read from Azure blob storage. The blob file containing a JSON array of time zones is stored in a file named timezones.json in a container azfnv2demo.
  • Services project. Azure.Functions.v2.DI.Services. This project contains the TimeZoneService class that returns data to the function project by reading data from the Azure blob via the helper project.

Complete source code is available at: https://github.com/akki-s/azure-functions-v2-dependency-injection

This means that the Function app project has a dependency on the services project, and services project has a dependency on the helper project.

At this stage TimeZoneService.cs looks like below:

azure-functions-v2-di

As you would have noticed in the code above, a new object of AzureBlobStorageHelper is created which is then used to get the data from blob storage. However, this makes my TimeZoneService.cs code difficult to unit test. What we need is to inject an instance of IAzureBlobStorageHelper, when an instance of TimeZoneService is created.

The first thing we do is make a change in TimeZoneService.cs in Services project to remove the instantiation of AzureBlobStorageHelper and have it injected in the constructor. The constructor of TimeZoneService can also include other dependencies such as ILogger for logging, HttpClient for REST calls etc, but those are left out for the sake of this example.

The next step is to register the services and build the ServiceProvider. This is done by creating an instance of IServiceCollection, registering the services and then making a call to the BuildServiceProvider method on the ServiceCollection. This returns the ServiceProvider that has all the registrations and other configuration if we used it, such as adding logging. Below is the class that has a static method called ConfigureServices that does all this work. This is what ASP.NET Core does out of the box and I’m utilizing same here for Azure functions.

Note that the above method registers TimeZoneService and AzureBlobStorageHelper.

Now all that’s left to be done is to call ConfigureServices from within the Azure Function, to configure the service collection, and get an instance of TimeZoneService from the ServiceProvider (You may like to call the serviceProvider something else, such as container as it is in other DI frameworks like AutoFac).

In order to use the generic method GetService above we need to add a reference to Microsoft.Extensions.DependencyInjection in our functions project:

TimeZoneService.cs now injects IAzureBlobStorageHelper in its constructor:

This is it. This might not be the best solution for DI in Azure functions, but it certainly is very simple.

Note: It is worth noting that, at the time of writing this post, Microsoft is working on integrating DI in Azure functions v2 as can be tracked here (https://github.com/Azure/Azure-Functions/issues/299). But till then above approach works great.

Complete source code is available at GitHub

Processing Azure Event Grid events across Azure subscriptions

Consider a scenario where you need to listen to Azure resource events happening in one Azure subscription from another Azure subscription. A use case for such a scenario can be when you are developing a solution where you listen to events happening in your customers’ Azure subscriptions, and then you need to handle those events from an Azure Function or Logic App running in your subscription.
A solution for such a scenario could be:
1. Create an Azure Function in your subscription that will handle Azure resource events received from Azure Event Grid.
2. Handle event validation in the above function, which is required to perform a handshake with Event Grid.
3. Create an Azure Event Grid subscription in the customers’ Azure subscriptions.
Before, I go into details let’s have a brief overview of Azure Event Grid.
Azure Event Grid is a routing service based on a publish/subscribe model, which is used for developing event-based applications. Event sources publish events, and event handlers can subscribe to these events via Event Grid subscriptions.

event-grids

Figure 1. Azure event grid publishers and handlers


Azure Event Grid subscriptions can be used to subscribe to system topics as well as custom topics. Various Azure services automatically send events to Event Grid. The system-level event sources that currently send events to Event Grid are Azure subscriptions, resource groups, Event Hubs, IOT Hubs, Azure Media Services, Service Bus, and blob storage
You can listen to these events by creating an event handler. Azure Event Grid supports several Azure Services and custom webhooks for event handlers. There are number of Azure services that can be used as event handlers, including Azure Functions, Logic Apps, Event Hubs, Azure Automation, Hybrid Connections, and storage queues.
In this post I’ll focus on using Azure Functions as an event handler to which an Event Grid subscription will send events to whenever an event occurs at the whole Azure subscription level. You can also create an Event Grid subscription at a resource group level to be notified only for the resources belonging to a particular resource group. The figure 1 posted above, shows various event sources that can publish events, and various supported event handlers. As per our solution Azure subscriptions and Azure Functions are marked.

Create an Azure Function in your subscription and handle the validation event from Event Grid

If our Event Grid subscription and function were in the same subscription, then we could have simply created an Event Grid-triggered Azure Function. Using that you can simply specify the Event Grid subscription details with this function specified as an endpoint in the Event Grid subscription. However, in our case this cannot be done as we need to have the Event Grid subscription in the customer subscription, and the Azure Function in our subscription. Therefore, we will simply create a HTTP-triggered function or a webhook function
Because we’re not selecting an Event Grid triggered function, we need us to do an extra validation step. At the time of creating a new Azure Event Grid subscription, Event Grid requires the endpoint to prove the ownership of the webhook, so that Event Grid can deliver the events to that endpoint. For built-in event handlers such as Logic Apps, Azure Automation, and Event Grid triggered functions, this process of validation is not necessary. However, in our scenario where we are using a HTTP-triggered function we need to handle the validation handshake
When an Event Grid subscription is created, it sends a subscription validation event in a POST request to the endpoint. All we need to do is to handle this event, read the request body, read the validationCode property in the data object in the request, and send it back in the response. Once Event Grid receives the same validation code back it knows that endpoint is validated, and it will start delivering events to our function. Following is an example of a POST request that Event Grid sends to the endpoint for validation.

Our function can check if the eventType is Microsoft.EventGrid.SubscriptionValidationEvent , which indicates it is meant for validation, and send back the value in data.validationCode. In all other scenarios, eventType will be based on the resource on which the event occurred, and the function can process those events accordingly. Also, the resource validation event contains a header aeg-event-type with value SubscriptionValidation. You should also validate this header.
Following is the sample code for a Node.js function to handle the validation event and send back the validation code and hence completing the validation handshake.

Processing Resource Events

To process the resource events, you can filter them on the resourceProvider or operationName properties. For example, the operationName property for a VM create event is set to Microsoft.Compute/virtualMachines/write. The event payload follows a fixed schema as described here. An event for a virtual machine creation looks like below:

Authentication

While creating the Event Grid subscription, detailed in next section, it should be created with the endpoint URL pointing to function URL including the function key.. Also, event validation done for the handshake acts as another means of authentication. To add an extra layer of authentication, you can generate your own access token, and append it to your function URL when specifying the endpoint for the Event Grid subscription. Your function can now also validate this access token before further processing.

Create an Azure Event Grid Subscription in customer’s subscription

A subscription owner/administrator should be able to run an Azure CLI or PowerShell command for creating the Event Grid subscription in customer subscription.
Important: This step must be done after the above step of creating the Azure Function is done. Otherwise, when you try to create an Event Grid subscription, and it raises the subscription validation event, Event Grid will not get a valid response back, and the creation of the Event Grid subscription will fail.
You can add filters to your Event Grid subscription to filter the events by subject. Currently, events can only be filtered with text comparison of the subject property value starting with or ending with some text. The subject filter doesn’t support a wildcard or regex search.

Azure CLI or PowerShell

An example Azure CLI command to create an Event Grid Subscription, which receives all the events occurring at subscription level is as below:

Here https://myhttptriggerfunction.azurewebsites.net/api/f1?code= is the URL of the function app.

Azure REST API

Instead of asking customer to run a CLI or PowerShell script to create the Event Grid subscription, you can automate this process by writing another Azure Function that calls Azure REST API. The API call can be invoked using service principal with rights on the customer’s subscription.
To create an Event Grid subscription for the customer’s Azure Subscription, you submit the following PUT request:
PUT https://management.azure.com/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /providers/Microsoft.EventGrid/eventSubscriptions/ eg-subscription-test?api-version=2018-01-01
Request Body:
{
"properties": {
"destination": {
"endpointType": "WebHook",
"properties": {
"endpointUrl": " https://myhttptriggerfunction.azurewebsites.net/api/f1?code="
}
},
"filter": {
"isSubjectCaseSensitive": false
}
}
}

 

Follow Us!

Kloud Solutions Blog - Follow Us!