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;
using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using JetBrains.Annotations; using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -24,13 +26,18 @@ namespace Volo.Abp.DependencyInjection
return; 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) 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) protected virtual DependencyAttribute GetDependencyAttributeOrNull(Type type)
{ {
return type.GetCustomAttribute<DependencyAttribute>(true); 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;
using System.Collections.Generic; using System.Collections.Generic;
using Shouldly; using Shouldly;
using Volo.Abp;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.Testing; using Volo.Abp.Testing;
@ -63,6 +62,15 @@ namespace Microsoft.Extensions.DependencyInjection
GetRequiredService<ConcreteGenericServiceWithPropertyInject>().ProperyInjectedService.ShouldNotBeNull(); 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 class MySingletonService : ISingletonDependency
{ {
public List<MyEmptyTransientService> TransientInstances { get; } 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 class TestModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
@ -124,6 +143,7 @@ namespace Microsoft.Extensions.DependencyInjection
context.Services.AddType<MyTransientService1>(); context.Services.AddType<MyTransientService1>();
context.Services.AddType<MyEmptyTransientService>(); context.Services.AddType<MyEmptyTransientService>();
context.Services.AddType<ServiceWithPropertyInject>(); context.Services.AddType<ServiceWithPropertyInject>();
context.Services.AddType<MySingletonExposingMultipleServices>();
context.Services.AddTransient(typeof(GenericServiceWithPropertyInject<>)); context.Services.AddTransient(typeof(GenericServiceWithPropertyInject<>));
context.Services.AddTransient(typeof(ConcreteGenericServiceWithPropertyInject)); context.Services.AddTransient(typeof(ConcreteGenericServiceWithPropertyInject));
} }

Loading…
Cancel
Save