Azure Functions and .NET 5: Dependency Injection
Tags: azurefunctions, dotnet, di
Published: 2021-03-16 10:04:59

.NET 5 support for Azure Functions is announced as GA in [this blog article](https://techcommunity.microsoft.com/t5/apps-on-azure/net-on-azure-functions-roadmap/ba-p/2197916)!

We can find developer guide at [Guide for running functions on .NET 5.0 in Azure](https://docs.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide) and [Develop and publish .NET 5 functions using Azure Functions](https://docs.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-developer-howtos?pivots=development-environment-vscode&tabs=browser)

Today, I want to share how to use DI (Dependency Injection) in this "isolated process" when we use .NET 5.

[Reference: Start-up and configuration](https://docs.microsoft.com/en-us/azure/azure-functions/dotnet-isolated-process-guide#start-up-and-configuration)

# Create project

First thing first! We need to create function project by using new template.

1\. Install the latest version of Azure Function Core Tools v3. See [here](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash#v2) for more detail.

2\. Once you install the tool, make sure to check the version. It should be higher than 3.0.3381.

```shell
func --version
```

3\. Create new folder and initialize the function.

```shell
mkdir dotnet5func
cd dotnet5func
func init
```

4\. Now, we can see new option available. Select "dotnet (isolated process".

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4dmn2evk9bn1zutyq4xq.jpg)

5\. Then, create new function project. Select any trigger as you want. I selected HttpTrigger this time.

```shell
func new
```

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qt4orumau9766r6ynwf4.jpg)

6\. Enter function name to complete, then run the function and confirm it works as expected.

```shell
func start
```

7\. Stop the function and open the project by using Visual Studio Code or Visual Studio.

```shell
code .
```

# Configure Dependency Injection

The most important thing to know when use DI is, that we don't need Startup.cs!! We can directly change code in Program.cs to configure DI now.

1.\ Program.cs should looks like below when we scaffold the project.

```csharp
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Azure.Functions.Worker.Configuration;

namespace dotnet5func
{
    public class Program
    {
        public static void Main()
        {
            var host = new HostBuilder()
                .ConfigureFunctionsWorkerDefaults()
                .Build();

            host.Run();
        }
    }
}
```

2.\ To use DI, we simply modify HostBuilder. Let's add HttpClient factory. We can simply use ConfigureServices method and use **AddHttpClient()** which is exactly same as ASP.NET project.

```csharp
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace dotnet5func
{
    public class Program
    {
        public static void Main()
        {
            var host = new HostBuilder()
                .ConfigureFunctionsWorkerDefaults()
                .ConfigureServices(s => {
                    s.AddHttpClient();
                })
                .Build();

            host.Run();
        }
    }
}
```
3\. Open function code and accept IHttpClientFactory via DI. We need to change several places.

- Remove **static** keywords so that we can instantiate class
- Add private IHttpClientFactory and receive it via constructor
- Change signature of **Run** method to make it asynchronous call

I use swapi.dev this time. swapi is a cool api if you love Star Wars. Check out [swapi.dev](https://swapi.dev/) for more detail.

```shell
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;

namespace dotnet5func
{
    public class dotnet5func
    {
        private readonly IHttpClientFactory clientFactory;

        public dotnet5func(IHttpClientFactory clientFactory)
        {
            this.clientFactory = clientFactory;
        }

        [Function("dotnet5func")]
        public async Task<HttpResponseData> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req,
            FunctionContext executionContext)
        {
            var logger = executionContext.GetLogger("dotnet5func");
            logger.LogInformation("C# HTTP trigger function processed a request.");

            var client = clientFactory.CreateClient();
            var swapires = await client.GetStringAsync("https://swapi.dev/api/people/1/");
            var response = req.CreateResponse(HttpStatusCode.OK);
            response.Headers.Add("Content-Type", "text/plain; charset=utf-8");

            response.WriteString(swapires);

            return response;
        }
    }
}
```

4\. Run the function again and call the endpoint.

```shell
func start
```
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/an5nvac8vbhrwy0dxyr4.jpg)

# Summary

Even though there are still slight differences between Azure Functions and Web API when we writing code, I can easily and effectively reusing my knowledge once I fill the gap!

I cannot wait .NET 6 release which is LTS next year!