Azure / Azure/azure-functions-dotnet-extensions

Dependencies of scoped services are resolved from the root container and become singletons

Open
#27 0 comments 2 reactions 0 assignees View on GitHub
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.