Browse Source

Resolved #3837: Singleton services exposing multiple services should return the same instance

pull/3840/head
Halil İbrahim Kalkan 7 years ago
parent
commit
f537cd1179
  1. 73
      framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DefaultConventionalRegistrar.cs
  2. 22
      framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs

73
framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/DefaultConventionalRegistrar.cs

@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection;
@ -24,13 +26,18 @@ namespace Volo.Abp.DependencyInjection
return;
}
var serviceTypes = ExposedServiceExplorer.GetExposedServices(type);
var exposedServiceTypes = ExposedServiceExplorer.GetExposedServices(type);
TriggerServiceExposing(services, type, serviceTypes);
TriggerServiceExposing(services, type, exposedServiceTypes);
foreach (var serviceType in serviceTypes)
foreach (var exposedServiceType in exposedServiceTypes)
{
var serviceDescriptor = ServiceDescriptor.Describe(serviceType, type, lifeTime.Value);
var serviceDescriptor = CreateServiceDescriptor(
type,
exposedServiceType,
exposedServiceTypes,
lifeTime.Value
);
if (dependencyAttribute?.ReplaceServices == true)
{
@ -46,7 +53,63 @@ namespace Volo.Abp.DependencyInjection
}
}
}
protected virtual ServiceDescriptor CreateServiceDescriptor(
Type implementationType,
Type exposingServiceType,
List<Type> allExposingServiceTypes,
ServiceLifetime lifeTime)
{
if (lifeTime.IsIn(ServiceLifetime.Singleton, ServiceLifetime.Scoped))
{
var redirectedType = GetRedirectedTypeOrNull(
implementationType,
exposingServiceType,
allExposingServiceTypes
);
if (redirectedType != null)
{
return ServiceDescriptor.Describe(
exposingServiceType,
provider => provider.GetService(redirectedType),
lifeTime
);
}
}
return ServiceDescriptor.Describe(
exposingServiceType,
implementationType,
lifeTime
);
}
protected virtual Type GetRedirectedTypeOrNull(
Type implementationType,
Type exposingServiceType,
List<Type> allExposingServiceTypes)
{
if (allExposingServiceTypes.Count < 2)
{
return null;
}
if (exposingServiceType == implementationType)
{
return null;
}
if (allExposingServiceTypes.Contains(implementationType))
{
return implementationType;
}
return allExposingServiceTypes.FirstOrDefault(
t => t != exposingServiceType && exposingServiceType.IsAssignableFrom(t)
);
}
protected virtual DependencyAttribute GetDependencyAttributeOrNull(Type type)
{
return type.GetCustomAttribute<DependencyAttribute>(true);

22
framework/test/Volo.Abp.Core.Tests/Microsoft/Extensions/DependencyInjection/DependencyInjection_Tests.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using Shouldly;
using Volo.Abp;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Modularity;
using Volo.Abp.Testing;
@ -63,6 +62,15 @@ namespace Microsoft.Extensions.DependencyInjection
GetRequiredService<ConcreteGenericServiceWithPropertyInject>().ProperyInjectedService.ShouldNotBeNull();
}
[Fact]
public void Singletons_Exposing_Multiple_Services_Should_Returns_The_Same_Instance()
{
var objectByInterfaceRef = GetRequiredService<IMySingletonExposingMultipleServices>();
var objectByClassRef = GetRequiredService<MySingletonExposingMultipleServices>();
ReferenceEquals(objectByInterfaceRef, objectByClassRef).ShouldBeTrue();
}
public class MySingletonService : ISingletonDependency
{
public List<MyEmptyTransientService> TransientInstances { get; }
@ -116,6 +124,17 @@ namespace Microsoft.Extensions.DependencyInjection
}
}
public interface IMySingletonExposingMultipleServices
{
}
[ExposeServices(typeof(IMySingletonExposingMultipleServices), typeof(MySingletonExposingMultipleServices))]
public class MySingletonExposingMultipleServices : IMySingletonExposingMultipleServices, ISingletonDependency
{
}
public class TestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
@ -124,6 +143,7 @@ namespace Microsoft.Extensions.DependencyInjection
context.Services.AddType<MyTransientService1>();
context.Services.AddType<MyEmptyTransientService>();
context.Services.AddType<ServiceWithPropertyInject>();
context.Services.AddType<MySingletonExposingMultipleServices>();
context.Services.AddTransient(typeof(GenericServiceWithPropertyInject<>));
context.Services.AddTransient(typeof(ConcreteGenericServiceWithPropertyInject));
}

Loading…
Cancel
Save