diff --git a/src/Volo.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceCollectionConventionalRegistrationExtensions.cs b/src/Volo.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceCollectionConventionalRegistrationExtensions.cs index ba8b99547f..6c1f978caf 100644 --- a/src/Volo.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceCollectionConventionalRegistrationExtensions.cs +++ b/src/Volo.DependencyInjection/Microsoft/Extensions/DependencyInjection/ServiceCollectionConventionalRegistrationExtensions.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Collections.Generic; using Volo.DependencyInjection; using Volo.ExtensionMethods.Collections.Generic; @@ -11,11 +12,11 @@ namespace Microsoft.Extensions.DependencyInjection public static class ServiceCollectionConventionalRegistrationExtensions { - private static readonly Dictionary> ConventionalRegistrars; + private static readonly ConcurrentDictionary> ConventionalRegistrars; static ServiceCollectionConventionalRegistrationExtensions() { - ConventionalRegistrars = new Dictionary>(); + ConventionalRegistrars = new ConcurrentDictionary>(); } public static IServiceCollection AddConventionalRegistrar(this IServiceCollection services, IConventionalRegistrar registrar) @@ -31,16 +32,12 @@ namespace Microsoft.Extensions.DependencyInjection private static List GetOrCreateRegistrarList(IServiceCollection services) { - var registrars = ConventionalRegistrars.GetOrDefault(services); - if (registrars == null) - { - registrars = ConventionalRegistrars[services] = new List + return ConventionalRegistrars.GetOrAdd( + services, + () => new List { new DefaultConventionalRegistrar() - }; - } - - return registrars; + }); } } } \ No newline at end of file diff --git a/test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpConventionalDependencyInjectionExtensions_Tests.cs b/test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpConventionalDependencyInjectionExtensions_Tests.cs index adf93ecc7b..64c31b9cc5 100644 --- a/test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpConventionalDependencyInjectionExtensions_Tests.cs +++ b/test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpConventionalDependencyInjectionExtensions_Tests.cs @@ -1,4 +1,5 @@ -using Shouldly; +using System.Linq; +using Shouldly; using Volo.DependencyInjection; using Xunit; @@ -43,16 +44,92 @@ namespace Microsoft.Extensions.DependencyInjection _services.ShouldContainScoped(typeof(MyScopedClass)); } + [Fact] + public void Should_Register_Scoped_With_Dependency_Attribute() + { + //Act + _services.AddType(typeof(MyScopedClassWithDependencyAttribute)); + + //Assert + _services.ShouldContainScoped(typeof(MyScopedClassWithDependencyAttribute)); + } + + [Fact] + public void Dependency_Attribute_Should_Override_Interface_Lifetimes() + { + //Act + _services.AddType(typeof(MyScopedClassWithDependencyAttribute2)); + + //Assert + _services.ShouldContainScoped(typeof(MyScopedClassWithDependencyAttribute2)); + } + [Fact] public void Should_Register_For_Exposed_Services() { + //Act _services.AddType(typeof(MyServiceWithExposeList)); + //Assert _services.ShouldContain(typeof(IMyService1), typeof(MyServiceWithExposeList), ServiceLifetime.Transient); _services.ShouldContain(typeof(IMyService2), typeof(MyServiceWithExposeList), ServiceLifetime.Transient); _services.ShouldNotContain(typeof(MyServiceWithExposeList)); } + [Fact] + public void Should_Register_Multiple_Implementation_For_Same_Service() + { + //Act + + _services.AddTypes(typeof(FirstImplOfMyService), typeof(SecondImplOfMyService)); + + //Assert + + //Check descriptons in service collection + var descriptions = _services.Where(s => s.ServiceType == typeof(IMyService)).ToList(); + descriptions.Count.ShouldBe(2); + descriptions[0].ImplementationType.ShouldBe(typeof(FirstImplOfMyService)); + descriptions[1].ImplementationType.ShouldBe(typeof(SecondImplOfMyService)); + + //Check from service provider + var serviceProvider = _services.BuildServiceProvider(); + + //Default service should be second one + serviceProvider.GetRequiredService().ShouldBeOfType(typeof(SecondImplOfMyService)); + + //Should also get all services + var instances = serviceProvider.GetServices().ToList(); + instances.Count.ShouldBe(2); + instances[0].ShouldBeOfType(typeof(FirstImplOfMyService)); + instances[1].ShouldBeOfType(typeof(SecondImplOfMyService)); + } + + [Fact] + public void Should_Not_Register_Second_Implementation_For_Same_Service_If_Second_Is_Marked_As_TryRegister() + { + //Act + + _services.AddTypes(typeof(FirstImplOfMyService), typeof(TryRegisterImplOfMyService)); + + //Assert + + //Check descriptons in service collection + var descriptions = _services.Where(s => s.ServiceType == typeof(IMyService)).ToList(); + descriptions.Count.ShouldBe(1); + descriptions[0].ImplementationType.ShouldBe(typeof(FirstImplOfMyService)); + + //Check from service provider + var serviceProvider = _services.BuildServiceProvider(); + + //Default service should be second one + serviceProvider.GetRequiredService().ShouldBeOfType(typeof(FirstImplOfMyService)); + + //Should also get all services + var instances = serviceProvider.GetServices().ToList(); + instances.Count.ShouldBe(1); + instances[0].ShouldBeOfType(typeof(FirstImplOfMyService)); + } + [Fact] public void AddObjectAccessor_Test() { @@ -90,6 +167,18 @@ namespace Microsoft.Extensions.DependencyInjection } + [Dependency(ServiceLifetime.Scoped)] + public class MyScopedClassWithDependencyAttribute + { + + } + + [Dependency(ServiceLifetime.Scoped)] //Attribute overrides interface + public class MyScopedClassWithDependencyAttribute2 : ITransientDependency + { + + } + public interface IMyService1 { @@ -99,13 +188,31 @@ namespace Microsoft.Extensions.DependencyInjection { } - + [ExposeServices(typeof(IMyService1), typeof(IMyService2))] public class MyServiceWithExposeList : IMyService1, IMyService2, ITransientDependency { } + public interface IMyService : ITransientDependency + { + + } + + public class FirstImplOfMyService : IMyService + { + } + + public class SecondImplOfMyService : IMyService + { + } + + [Dependency(TryRegister = true)] + public class TryRegisterImplOfMyService : IMyService + { + } + public class MyEmptyClass { diff --git a/test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpDependencyInjectionSpecifications.cs b/test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpDependencyInjectionSpecifications.cs deleted file mode 100644 index 7ea2bb0f04..0000000000 --- a/test/Volo.DependencyInjection.Tests/Microsoft/Extensions/DependencyInjection/AbpDependencyInjectionSpecifications.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Volo.DependencyInjection; - -namespace Microsoft.Extensions.DependencyInjection -{ - public class AbpDependencyInjectionSpecifications - { - //TODO: Tests... - - public class MyScopedClass : IScopedDependency - { - - } - - } -}