diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProviderManager.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProviderManager.cs index 84d0ad0b2c..09b2da2acb 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProviderManager.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionValueProviderManager.cs @@ -9,7 +9,7 @@ namespace Volo.Abp.Authorization.Permissions; public class PermissionValueProviderManager : IPermissionValueProviderManager, ISingletonDependency { - public IReadOnlyList ValueProviders => _lazyProviders.Value; + public IReadOnlyList ValueProviders => GetProviders(); private readonly Lazy> _lazyProviders; protected AbpPermissionOptions Options { get; } @@ -28,4 +28,17 @@ public class PermissionValueProviderManager : IPermissionValueProviderManager, I true ); } + + protected virtual List GetProviders() + { + var providers = _lazyProviders.Value; + + var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1); + if(multipleProviders != null) + { + throw new AbpException($"Duplicate permission value provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}"); + } + + return providers; + } } diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs index c2a4a71ab3..66e145563d 100644 --- a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureChecker.cs @@ -12,34 +12,26 @@ public class FeatureChecker : FeatureCheckerBase protected AbpFeatureOptions Options { get; } protected IServiceProvider ServiceProvider { get; } protected IFeatureDefinitionManager FeatureDefinitionManager { get; } - protected List Providers => _providers.Value; - - private readonly Lazy> _providers; + protected IFeatureValueProviderManager FeatureValueProviderManager { get; } public FeatureChecker( IOptions options, IServiceProvider serviceProvider, - IFeatureDefinitionManager featureDefinitionManager) + IFeatureDefinitionManager featureDefinitionManager, + IFeatureValueProviderManager featureValueProviderManager) { ServiceProvider = serviceProvider; FeatureDefinitionManager = featureDefinitionManager; + FeatureValueProviderManager = featureValueProviderManager; Options = options.Value; - - _providers = new Lazy>( - () => Options - .ValueProviders - .Select(type => (ServiceProvider.GetRequiredService(type) as IFeatureValueProvider)!) - .ToList(), - true - ); } public override async Task GetOrNullAsync(string name) { var featureDefinition = await FeatureDefinitionManager.GetAsync(name); - var providers = Enumerable - .Reverse(Providers); + var providers = FeatureValueProviderManager.ValueProviders + .Reverse(); if (featureDefinition.AllowedProviders.Any()) { diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureValueProviderManager.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureValueProviderManager.cs new file mode 100644 index 0000000000..98d73dd4e4 --- /dev/null +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/FeatureValueProviderManager.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.Features; + +public class FeatureValueProviderManager : IFeatureValueProviderManager, ISingletonDependency +{ + public IReadOnlyList ValueProviders => GetProviders(); + private readonly Lazy> _lazyProviders; + + protected AbpFeatureOptions Options { get; } + + public FeatureValueProviderManager( + IServiceProvider serviceProvider, + IOptions options) + { + Options = options.Value; + + _lazyProviders = new Lazy>( + () => Options + .ValueProviders + .Select(c => serviceProvider.GetRequiredService(c) as IFeatureValueProvider) + .ToList()!, + true + ); + } + + protected virtual List GetProviders() + { + var providers = _lazyProviders.Value; + + var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1); + if(multipleProviders != null) + { + throw new AbpException($"Duplicate feature value provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}"); + } + + return providers; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Features/Volo/Abp/Features/IFeatureValueProviderManager.cs b/framework/src/Volo.Abp.Features/Volo/Abp/Features/IFeatureValueProviderManager.cs new file mode 100644 index 0000000000..56de662a99 --- /dev/null +++ b/framework/src/Volo.Abp.Features/Volo/Abp/Features/IFeatureValueProviderManager.cs @@ -0,0 +1,8 @@ +using System.Collections.Generic; + +namespace Volo.Abp.Features; + +public interface IFeatureValueProviderManager +{ + IReadOnlyList ValueProviders { get; } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionValueProviderManager_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionValueProviderManager_Tests.cs new file mode 100644 index 0000000000..d4af25ad3a --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionValueProviderManager_Tests.cs @@ -0,0 +1,59 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Volo.Abp.Authorization; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.Authorization.TestServices; +using Xunit; + +namespace Volo.Abp; + +public class PermissionValueProviderManager_Tests: AuthorizationTestBase +{ + private readonly IPermissionValueProviderManager _permissionValueProviderManager; + + public PermissionValueProviderManager_Tests() + { + _permissionValueProviderManager = GetRequiredService(); + } + + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.Services.Configure(permissionOptions => + { + permissionOptions.ValueProviders.Add(); + }); + } + + [Fact] + public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected() + { + var exception = Assert.Throws(() => + { + var providers = _permissionValueProviderManager.ValueProviders; + }); + + exception.Message.ShouldBe($"Duplicate permission value provider name detected: TestPermissionValueProvider1. Providers:{Environment.NewLine}{typeof(TestDuplicatePermissionValueProvider).FullName}{Environment.NewLine}{typeof(TestPermissionValueProvider1).FullName}"); + } +} + +public class TestDuplicatePermissionValueProvider : PermissionValueProvider +{ + public TestDuplicatePermissionValueProvider(IPermissionStore permissionStore) : base(permissionStore) + { + } + + public override string Name => "TestPermissionValueProvider1"; + + public override Task CheckAsync(PermissionValueCheckContext context) + { + throw new NotImplementedException(); + } + + public override Task CheckAsync(PermissionValuesCheckContext context) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureValueProviderManager_Tests.cs b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureValueProviderManager_Tests.cs new file mode 100644 index 0000000000..7e73ef65fc --- /dev/null +++ b/framework/test/Volo.Abp.Features.Tests/Volo/Abp/Features/FeatureValueProviderManager_Tests.cs @@ -0,0 +1,54 @@ +using System; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Xunit; + +namespace Volo.Abp.Features; + +public class FeatureValueProviderManager_Tests : FeatureTestBase +{ + private readonly IFeatureValueProviderManager _featureValueProviderManager; + + public FeatureValueProviderManager_Tests() + { + _featureValueProviderManager = GetRequiredService(); + } + + protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) + { + options.Services.Configure(permissionOptions => + { + permissionOptions.ValueProviders.Add(); + }); + } + + [Fact] + public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected() + { + var exception = Assert.Throws(() => + { + var providers = _featureValueProviderManager.ValueProviders; + }); + + exception.Message.ShouldBe($"Duplicate feature value provider name detected: {TestDuplicateFeatureValueProvider.ProviderName}. Providers:{Environment.NewLine}{typeof(TestDuplicateFeatureValueProvider).FullName}{Environment.NewLine}{typeof(DefaultValueFeatureValueProvider).FullName}"); + } +} + +public class TestDuplicateFeatureValueProvider : FeatureValueProvider +{ + public const string ProviderName = "D"; + + public override string Name => ProviderName; + + public TestDuplicateFeatureValueProvider(IFeatureStore settingStore) + : base(settingStore) + { + + } + + public override Task GetOrNullAsync(FeatureDefinition setting) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/SettingValueProviderManager_Tests.cs b/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/SettingValueProviderManager_Tests.cs index 93bf26431a..f85e465d8e 100644 --- a/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/SettingValueProviderManager_Tests.cs +++ b/framework/test/Volo.Abp.Settings.Tests/Volo/Abp/Settings/SettingValueProviderManager_Tests.cs @@ -1,9 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; -using NSubstitute.Extensions; using Shouldly; using Volo.Abp.DependencyInjection; using Volo.Abp.Testing; @@ -25,7 +23,7 @@ public class SettingValueProviderManager_Tests: AbpIntegratedTest(settingOptions => { - settingOptions.ValueProviders.Add(); + settingOptions.ValueProviders.Add(); }); } @@ -37,18 +35,18 @@ public class SettingValueProviderManager_Tests: AbpIntegratedTest ProviderName; - public Test2SettingValueProvider() + public TestDuplicateSettingValueProvider() { }