Dependency Injection (DI) has been available in .NET Core Web Applications for a while and now seems to have finally made it’s way to Azure Functions as well and is available in the current Azure Functions Runtime 2.0.12382. The GitHub issue tracking DI implementation in Azure Functions is here.

I’ve created a test project in an effort to figure out how it works but happily it seems pretty similar to using it in a Web Application.

In my case I wanted to inject a Serilog logger and a service to help in accessing the JSONPlaceholder API.

The first step is to add a new Startup.cs class to the project that inherits from IWebJobsStartup, this will allow you to added the required DI services and build the ServiceProvider.

Startup.cs

namespace JsonPlaceHolderDependencyInjection
{
    public class Startup : IWebJobsStartup
    {
        public Startup()
        {
            // Initialize serilog logger
            Log.Logger = new LoggerConfiguration()
                     .WriteTo.Console(Serilog.Events.LogEventLevel.Debug)
                     .MinimumLevel.Debug()
                     .Enrich.FromLogContext()
                     .CreateLogger();
        }

        public void Configure(IWebJobsBuilder builder)
        {
            ConfigureServices(builder.Services).BuildServiceProvider(true);
        }

        private IServiceCollection ConfigureServices(IServiceCollection services)
        {
            services
                .AddLogging(loggingBuilder =>
                    loggingBuilder.AddSerilog(dispose: true)
                )
                .AddTransient<IJsonPlaceholderClient, JsonPlaceholderClient>(client =>
                    new JsonPlaceholderClient(Environment.GetEnvironmentVariable("BaseAddress"))
                )
                .AddTransient<IJsonPlaceholderService, JsonPlaceholderService>();

            return services;
        }
    }
}

In your function you then need to provide an assembly reference to the Startup class [assembly: WebJobsStartup(typeof(Startup))] and you can then use DI as expected.

GetAlbums.cs

[assembly: WebJobsStartup(typeof(Startup))]

namespace JsonPlaceHolderDependencyInjection.Function
{
    public class GetAlbums
    {
        private readonly IJsonPlaceholderService _jsonPlaceholderService;
        private readonly ILogger _logger;

        public GetAlbums(IJsonPlaceholderService jsonPlaceholderService, ILoggerFactory loggerFactory)
        {
            _jsonPlaceholderService = jsonPlaceholderService;
            _logger = loggerFactory.CreateLogger("GetAlbums");
        }

        [FunctionName("GetAlbums")]
        public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = "GetAlbums/{id?}")] HttpRequest req, int? id)
        {
            _logger.LogInformation("C# HTTP trigger function processed a request.");
            //log.LogInformation("C# HTTP trigger function processed a request.");

            if (id == null)
            {
                return (ActionResult)new OkObjectResult(await _jsonPlaceholderService.GetAlbums());
            }
            else
            {
                return (ActionResult)new OkObjectResult(await _jsonPlaceholderService.GetAlbumById((int)id));
            }
        }
    }
}

6 Comments

Mrunal · 26th June 2019 at 12:35 pm

This is great stuff.

How can we test this? As far as I understand the concept the main reason for having dependency injection is to make is loosely coupled and hence easy to test.

How can I inject my mocks?

Luis Javier Posada Marin · 27th July 2019 at 5:13 am

Hi,

I have some errors:

[23:13:01 INF] Host initialized (6646ms)
[23:13:01 INF] Host started (6712ms)
[23:13:01 INF] Job host started
[23:13:01 ERR] The following 2 functions are in error:
GetAlbums: The method ‘Run’ cannot be found.
GetPhotos: The method ‘Run’ cannot be found.

What is the error?

Leave a Reply

Your email address will not be published. Required fields are marked *