Azure / Azure/azure-functions-dotnet-extensions
Dependencies of scoped services are resolved from the root container and become singletons
- Dominant language
- C#
- Stars
- 81
- Forks
- 50
- PR merge metrics
- No merged PRs in 30d
Description
We came across this issue when using MediatR within a function.
The issue seems to be that when you resolve a service from a scope and the service that service itself has dependencies, then those dependencies are not being resolved from the scope, as would be expected, but are being resolved from the root container. That turns those dependencies into singletons.
The following code sample illustrates the problem. It is a simplified version of what happens in MediatR.Extensions.Microsoft.DependencyInjection:
`
using System;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.DependencyInjection;
[assembly: FunctionsStartup(typeof(FunctionAppDiTest.Startup))]
namespace FunctionAppDiTest
{
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddTransient(p => p.GetService);
builder.Services.AddScoped();
builder.Services.AddScoped();
}
}
public class Function1
{
private readonly IServiceProvider _serviceProvider;
public Function1(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
[FunctionName("Function1")]
public void Run([TimerTrigger("*/10 * * * * *")]TimerInfo myTimer)
{
IMyService svc1, svc2;
IMyDependency dep1, dep2;
using (var scope = _serviceProvider.CreateScope())
{
svc1 = scope.ServiceProvider.GetService();
dep1 = svc1.MyDependency;
}
using (var scope = _serviceProvider.CreateScope())
{
svc2 = scope.ServiceProvider.GetService();
dep2 = svc2.MyDependency;
}
if (ReferenceEquals(svc1, svc2))
throw new Exception("Service instances from 2 different scopes should not be the same!");
if (ReferenceEquals(dep1, dep2))
throw new Exception("Dependency instances from 2 different scopes should not be the same!");
}
}
public delegate object ServiceFactory(Type type);
public class MyService : IMyService
{
public MyService(ServiceFactory serviceFactory)
{
MyDependency = (IMyDependency)serviceFactory(typeof(IMyDependency));
}
public IMyDependency MyDependency { get; }
}
public interface IMyService
{
IMyDependency MyDependency { get; }
}
public class MyDependency : IMyDependency
{
}
public interface IMyDependency
{
}
}
`
The resulting instances of svc1 and svc2 are not the same, but those of dep1 and dep2 are.
If you put a breakpoint in the lambda "p=>p.GetService" and mark the instance of "p" you will notice that both times the same instance of the ServiceProvider is used.
This probably is also the root cause of #19.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the dependency-injection setup and ServiceFactory delegate shown in the issue, then trace how IServiceProvider.CreateScope() and the scoped service's dependency resolution are wired. Reproduce the two-scope example and verify that both MyService and MyDependency come from their respective scopes without changing the expected service registrations.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- azure, csharp
- Domain
- backend, cloud
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100