During Build 2019, Microsoft announce a lot of Azure new features and some of them are related to Azure Functions, one of the most widely used serverless offerings. Some interesting announcements are the new Azure Functions Premium Plan, support for PowerShell or Bring Azure Functions to Kubernetes

In this blog post, I will talk about a new feature that has much less visibility, but that it will bring a great capability to Azure Functions development. Dependency Injection (DI) support for Azure Functions.

.NET developers have using Dependency Injection to better architect the applications in a way that simplifies management of application services, such as connections as well as an easier way for testing. Until now, Azure Functions lacked support for it.

When creating an Azure Function, the templates creates a static method that contains the main code and that forces any other method in the class to be also static. This creates some issues, especially if we want to use the provided .NET Core DI. With the native support for DI in Azure Functions, we can get rid of the static modifier.

In a nutshell, to be able to use Dependency Injection in a Function, first of all we need to install Microsoft.Azure.Functions.Extensions NuGet package, create a Startup.cs class and inject the services as dependencies.

Once we have NuGet package installed, we need to make a few changes on the file where the function code is, in the default case Function1.cs

First, we can get rid of the static modified on the Run method and the class

Also, we will need a constructor with the services that we want to inject. In this case, I just inject a SQL Server connection. The code will look like this:

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Data.SqlClient;

namespace FunctionApp1
{
 public class Function1
 {
 private readonly SqlConnection _connection;
 public Function1(SqlConnection conn)
 {
 _connection = conn;
 }
 [FunctionName("Function1")]
 public async Task<iactionresult> Run(
 [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
 {
 log.LogInformation("C# HTTP trigger function processed a request.");

 using (SqlConnection connection = new SqlConnection(_connection))
 {
 ...
 }

 string name = req.Query["name"];

 string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
 dynamic data = JsonConvert.DeserializeObject(requestBody);
 name = name ?? data?.name;

 return name != null
 ? (ActionResult)new OkObjectResult($"Hello, {name}")
 : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
 }
 }
}

Note, there is no static modifiers anymore and there is a new constructor.

The last piece we need is a new startup.cs file that looks like this:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

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

namespace FunctionApp1
{
 class Startup : FunctionsStartup 
 {
 public override void Configure(IFunctionsHostBuilder builder)
 {
 builder.Services.AddSingleton((s) =>
 {
 return new SqlConnection("ConnectionString");
 });
 }
 }
}

We need to add a couple of references for the Dependency Injection, Microsoft.Azure.Functions.Extensions.DependencyInjection and Microsoft.Extensions.DependencyInjection;

Here, we add an annotation that tells what’s the startup class and we register all the services that we need to inject in the Configure method In this case, we register the SqlConnection as a Singleton, but there are also transient and scoped lifetimes available.

To summarize, this is the same Dependency Injection that we have been using in any other .NET application with same uses and best practices, and will allow for better abstraction, better testing and overall better architecture.