Reputation: 123
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
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
Reputation: 31
Try this in your code:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ITestService, TestService>();
}
Upvotes: 3
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