AnotherDev
AnotherDev

Reputation: 123

.NET Core 2.2 Azure Function v2 Dependency Injection

I am having an issue registering a singleton using Microsoft.Extensions.DependencyInjection. I have created a Startup class (which is definitely working) and created an ITestService with implementation.

The singleton is injected into the function's constructor. Initially I had no issues with this implementation, however, a couple days later the function fails because it can't resolve ITestService. I have no clue why.

here is the Startup class

using Microsoft.Azure.WebJobs.Hosting;

[assembly: WebJobsStartup(typeof(Startup))]
namespace Test.Functions
{
    using System;

    using Microsoft.Azure.WebJobs;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;

    public class Startup : IWebJobsStartup
    {
        public void Configure(IWebJobsBuilder builder)
        {
            var configuration = new ConfigurationBuilder()
                .SetBasePath(Environment.CurrentDirectory)
                .AddJsonFile("local.settings.json", true, true)
                .AddEnvironmentVariables()
                .Build();

            builder.Services.AddSingleton<ITestService>(new TestService("test string"));
        }
    }
}

And here is the function

public class TestFunction
{
    private readonly ITestService testService

    public TestFunction(ITestService testService)
    {
        this.testService = testService ?? throw new ArgumentNullException(nameof(testService));
    }

    [FunctionName(nameof(TestFunction))]
    public void Run([ServiceBusTrigger("test", Connection = "ServiceBusConnection")]Message message, ILogger log)
    {
        ////use test service here
    }
}

When I debug startup and look at Services I see that the implementation type is null for ITestService, which I assume is why it won't resolve. Like I mentioned this totally worked for a couple days. The version of functions etc have not changed. Any ideas how to get this working again would be greatly appreciated.

update

I tried to simplify this even further and created another dummy interface with an implementation that has a parameter-less constructor. I added it using: builder.AddSingleton<ITestService2, TestService2>()

It obviously assigned the type to the implementation type, but when it came time to inject it into the constructor it failed with the same can't activate exception.

Upvotes: 9

Views: 6218

Answers (3)

Kirk Larkin
Kirk Larkin

Reputation: 93003

There's a regression in the latest version of the function host that has broken Dependency Injection.

In order to work around this in an Azure environment, you can lock down the specific version of the functions host by setting the FUNCTIONS_EXTENSION_VERSION application setting to 2.0.12342.0.

If you're running the function host locally using the azure-functions-core-tools NPM package, be sure to use 2.4.419 as the latest version (2.4.498) results in the same issue. You can install that explicitly with the following:

npm i -g [email protected]

See this GitHub issue for more background.

Upvotes: 7

Samuel Aalmeida
Samuel Aalmeida

Reputation: 31

Try this in your code:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ITestService, TestService>();
}

Upvotes: 3

cl0ud
cl0ud

Reputation: 1614

Have a go with this

  builder.Services.AddSingleton<ITestService>(s => new TestService("test string"));

This uses the IServiceProvider in order to provide the string parameter to the constructor.

EDIT :

Try Changing your code to the below and installing Willezone.Azure.WebJobs.Extensions.DependencyInjection

This adds the extension method AddDependencyInjection and allows you to do the traditional ConfigureServices method call in a net core app startup.

using Microsoft.Azure.WebJobs.Hosting;

 [assembly: WebJobsStartup(typeof(Startup))]
   namespace Test.Functions
{
using System;

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

public class Startup : IWebJobsStartup
{
    public void Configure(IWebJobsBuilder builder)
    {
        var configuration = new ConfigurationBuilder()
            .SetBasePath(Environment.CurrentDirectory)
            .AddJsonFile("local.settings.json", true, true)
            .AddEnvironmentVariables()
            .AddDependencyInjection(ConfigureServices)
            .Build();

    }
  private void ConfigureServices(IServiceCollection services)
  {
    services.AddSingleton<ITestService>(s => new TestService("test string"));
  }
}

}

Upvotes: 2

Related Questions