Skip to content

Commit

Permalink
Simplifies creating child containers for tenants (#16190)
Browse files Browse the repository at this point in the history
Co-authored-by: Hisham Bin Ateya <[email protected]>
  • Loading branch information
gvkries and hishamco authored May 30, 2024
1 parent 9aeb411 commit 2940fb5
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ public static IServiceCollection CreateChildContainer(this IServiceProvider serv
// Prevent hosting 'IStartupFilter' to re-add middleware to the tenant pipeline.
if (services.Key.ServiceType == typeof(IStartupFilter))
{
continue;
}

// A generic type definition is rather used to create other constructed generic types.
else if (services.Key.ServiceType.IsGenericTypeDefinition)
if (services.Key.ServiceType.IsGenericTypeDefinition)
{
// So, we just need to pass the descriptor.
foreach (var service in services)
Expand Down Expand Up @@ -75,65 +76,42 @@ public static IServiceCollection CreateChildContainer(this IServiceProvider serv
}
}

// If all services of the same type are not singletons.
else if (services.All(s => s.Lifetime != ServiceLifetime.Singleton))
{
// We don't need to resolve them.
foreach (var service in services)
{
clonedCollection.Add(service);
}
}

// If all services of the same type are singletons.
else if (services.All(s => s.Lifetime == ServiceLifetime.Singleton))
// If services of the same type have at least one singleton.
else if (services.Any(s => s.Lifetime == ServiceLifetime.Singleton))
{
// We can resolve them from the main container.
var instances = services.Key.ServiceKey is not null
? serviceProvider.GetKeyedServices(services.Key.ServiceType, services.Key.ServiceKey)
: serviceProvider.GetServices(services.Key.ServiceType);

for (var i = 0; i < services.Count(); i++)
{
var instance = instances.ElementAt(i);
if (instance is null)
{
continue;
}

clonedCollection.CloneSingleton(services.ElementAt(i), instance);
}
}

// If singletons and scoped services are mixed.
else
{
// We need a service scope to resolve them.
using var scope = serviceProvider.CreateScope();

var instances = services.Key.ServiceKey is not null
? serviceProvider.GetKeyedServices(services.Key.ServiceType, services.Key.ServiceKey)
: serviceProvider.GetServices(services.Key.ServiceType);

// Then we only keep singleton instances.
for (var i = 0; i < services.Count(); i++)
{
if (services.ElementAt(i).Lifetime == ServiceLifetime.Singleton)
var service = services.ElementAt(i);
if (service.Lifetime == ServiceLifetime.Singleton)
{
var instance = instances.ElementAt(i);
if (instance is null)
{
continue;
}

clonedCollection.CloneSingleton(services.ElementAt(i), instance);
clonedCollection.CloneSingleton(service, instance);
}
else
{
clonedCollection.Add(services.ElementAt(i));
clonedCollection.Add(service);
}
}
}
else // If all services of the same type are not singletons.
{
// We don't need to resolve them.
foreach (var service in services)
{
clonedCollection.Add(service);
}
}
}

return clonedCollection;
Expand Down
3 changes: 3 additions & 0 deletions test/OrchardCore.Tests/Shell/ShellContainerFactoryTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,8 @@ public async Task HostServiceLifeTimesShouldBePreserved()
.CreateScope()
.ServiceProvider;

var appSingleton = _applicationServiceProvider.GetRequiredService<ITestSingleton>();

var singleton1 = container.GetRequiredService<ITestSingleton>();
var singleton2 = container.GetRequiredService<ITestSingleton>();
var transient1 = container.GetRequiredService<ITestTransient>();
Expand All @@ -109,6 +111,7 @@ public async Task HostServiceLifeTimesShouldBePreserved()
Assert.IsType<TestScoped>(scoped3);

Assert.Equal(singleton1, singleton2);
Assert.Same(appSingleton, singleton1);
Assert.NotEqual(transient1, transient2);
Assert.NotEqual(scoped1, scoped3);
Assert.Equal(scoped1, scoped2);
Expand Down

0 comments on commit 2940fb5

Please sign in to comment.