Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve ValueProvider system. #18823

Merged
merged 5 commits into from
Jan 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,31 @@ public class PermissionValueProviderManager : IPermissionValueProviderManager, I
private readonly Lazy<List<IPermissionValueProvider>> _lazyProviders;

protected AbpPermissionOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }

public PermissionValueProviderManager(
IServiceProvider serviceProvider,
IOptions<AbpPermissionOptions> options)
{
Options = options.Value;
ServiceProvider = serviceProvider;

_lazyProviders = new Lazy<List<IPermissionValueProvider>>(
() => Options
.ValueProviders
.Select(c => serviceProvider.GetRequiredService(c) as IPermissionValueProvider)
.ToList()!,
true
);
_lazyProviders = new Lazy<List<IPermissionValueProvider>>(GetProviders, true);
}

protected virtual List<IPermissionValueProvider> GetProviders()
{
var providers = Options
.ValueProviders
.Select(type => (ServiceProvider.GetRequiredService(type) as IPermissionValueProvider)!)
.ToList();

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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,26 @@ public class FeatureChecker : FeatureCheckerBase
protected AbpFeatureOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
protected IFeatureDefinitionManager FeatureDefinitionManager { get; }
protected List<IFeatureValueProvider> Providers => _providers.Value;

private readonly Lazy<List<IFeatureValueProvider>> _providers;
protected IFeatureValueProviderManager FeatureValueProviderManager { get; }

public FeatureChecker(
IOptions<AbpFeatureOptions> options,
IServiceProvider serviceProvider,
IFeatureDefinitionManager featureDefinitionManager)
IFeatureDefinitionManager featureDefinitionManager,
IFeatureValueProviderManager featureValueProviderManager)
{
ServiceProvider = serviceProvider;
FeatureDefinitionManager = featureDefinitionManager;
FeatureValueProviderManager = featureValueProviderManager;

Options = options.Value;

_providers = new Lazy<List<IFeatureValueProvider>>(
() => Options
.ValueProviders
.Select(type => (ServiceProvider.GetRequiredService(type) as IFeatureValueProvider)!)
.ToList(),
true
);
}

public override async Task<string?> GetOrNullAsync(string name)
{
var featureDefinition = await FeatureDefinitionManager.GetAsync(name);
var providers = Enumerable
.Reverse(Providers);
var providers = FeatureValueProviderManager.ValueProviders
.Reverse();

if (featureDefinition.AllowedProviders.Any())
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
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<IFeatureValueProvider> ValueProviders => _lazyProviders.Value;
private readonly Lazy<List<IFeatureValueProvider>> _lazyProviders;

protected AbpFeatureOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }

public FeatureValueProviderManager(
IServiceProvider serviceProvider,
IOptions<AbpFeatureOptions> options)
{
Options = options.Value;
ServiceProvider = serviceProvider;

_lazyProviders = new Lazy<List<IFeatureValueProvider>>(GetProviders, true);
}

protected virtual List<IFeatureValueProvider> GetProviders()
{
var providers = Options
.ValueProviders
.Select(type => (ServiceProvider.GetRequiredService(type) as IFeatureValueProvider)!)
.ToList();

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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Collections.Generic;

namespace Volo.Abp.Features;

public interface IFeatureValueProviderManager
{
IReadOnlyList<IFeatureValueProvider> ValueProviders { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ namespace Volo.Abp.Settings;
public class SettingValueProviderManager : ISettingValueProviderManager, ISingletonDependency
{
public List<ISettingValueProvider> Providers => _lazyProviders.Value;

protected AbpSettingOptions Options { get; }
protected IServiceProvider ServiceProvider { get; }
private readonly Lazy<List<ISettingValueProvider>> _lazyProviders;

public SettingValueProviderManager(
Expand All @@ -19,13 +21,24 @@ public class SettingValueProviderManager : ISettingValueProviderManager, ISingle
{

Options = options.Value;
ServiceProvider = serviceProvider;

_lazyProviders = new Lazy<List<ISettingValueProvider>>(GetProviders, true);
}

protected virtual List<ISettingValueProvider> GetProviders()
{
var providers = Options
.ValueProviders
.Select(type => (ServiceProvider.GetRequiredService(type) as ISettingValueProvider)!)
.ToList();

var multipleProviders = providers.GroupBy(p => p.Name).FirstOrDefault(x => x.Count() > 1);
if(multipleProviders != null)
{
throw new AbpException($"Duplicate setting value provider name detected: {multipleProviders.Key}. Providers:{Environment.NewLine}{multipleProviders.Select(p => p.GetType().FullName!).JoinAsString(Environment.NewLine)}");
}

_lazyProviders = new Lazy<List<ISettingValueProvider>>(
() => Options
.ValueProviders
.Select(type => serviceProvider.GetRequiredService(type) as ISettingValueProvider)
.ToList()!,
true
);
return providers;
}
}
Original file line number Diff line number Diff line change
@@ -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<IPermissionValueProviderManager>();
}

protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.Services.Configure<AbpPermissionOptions>(permissionOptions =>
{
permissionOptions.ValueProviders.Add<TestDuplicatePermissionValueProvider>();
});
}

[Fact]
public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected()
{
var exception = Assert.Throws<AbpException>(() =>
{
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<PermissionGrantResult> CheckAsync(PermissionValueCheckContext context)
{
throw new NotImplementedException();
}

public override Task<MultiplePermissionGrantResult> CheckAsync(PermissionValuesCheckContext context)
{
throw new NotImplementedException();
}
}
Original file line number Diff line number Diff line change
@@ -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<IFeatureValueProviderManager>();
}

protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.Services.Configure<AbpFeatureOptions>(permissionOptions =>
{
permissionOptions.ValueProviders.Add<TestDuplicateFeatureValueProvider>();
});
}

[Fact]
public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected()
{
var exception = Assert.Throws<AbpException>(() =>
{
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<string> GetOrNullAsync(FeatureDefinition setting)
{
throw new NotImplementedException();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Testing;
using Xunit;

namespace Volo.Abp.Settings;

public class SettingValueProviderManager_Tests: AbpIntegratedTest<AbpSettingsTestModule>
{
private readonly ISettingValueProviderManager _settingValueProviderManager;

public SettingValueProviderManager_Tests()
{
_settingValueProviderManager = GetRequiredService<ISettingValueProviderManager>();
}

protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
options.Services.Configure<AbpSettingOptions>(settingOptions =>
{
settingOptions.ValueProviders.Add<TestDuplicateSettingValueProvider>();
});
}

[Fact]
public void Should_Throw_Exception_If_Duplicate_Provider_Name_Detected()
{
var exception = Assert.Throws<AbpException>(() =>
{
var providers = _settingValueProviderManager.Providers;
});

exception.Message.ShouldBe($"Duplicate setting value provider name detected: {TestDuplicateSettingValueProvider.ProviderName}. Providers:{Environment.NewLine}{typeof(TestDuplicateSettingValueProvider).FullName}{Environment.NewLine}{typeof(TestSettingValueProvider).FullName}");
}
}

public class TestDuplicateSettingValueProvider : ISettingValueProvider, ITransientDependency
{
public const string ProviderName = "Test";


public string Name => ProviderName;

public TestDuplicateSettingValueProvider()
{
}

public Task<string> GetOrNullAsync(SettingDefinition setting)
{
throw new NotImplementedException();
}

public Task<List<SettingValue>> GetAllAsync(SettingDefinition[] settings)
{
throw new NotImplementedException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public class FeatureManager : IFeatureManager, ISingletonDependency

if (!providers.Any())
{
return;
throw new AbpException($"Unknown feature value provider: {providerName}");
}

if (providers.Count > 1 && !forceToSet && value != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,15 @@

(await _featureManager.GetOrNullAsync(TestFeatureDefinitionProvider.BackupCount, TenantFeatureValueProvider.ProviderName, TestEditionIds.TenantId.ToString())).ShouldBe("0");
}

[Fact]
public async Task Set_Should_Throw_Exception_If_Provider_Not_Found()
{
var exception = await Assert.ThrowsAsync<AbpException>(async () =>
{
await _featureManager.SetAsync(TestFeatureDefinitionProvider.EmailSupport, "true", "UndefinedProvider", "Test");
});

Check warning on line 219 in modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs

View check run for this annotation

Codecov / codecov/patch

modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs#L215-L219

Added lines #L215 - L219 were not covered by tests

exception.Message.ShouldBe("Unknown feature value provider: UndefinedProvider");
}

Check warning on line 222 in modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs

View check run for this annotation

Codecov / codecov/patch

modules/feature-management/test/Volo.Abp.FeatureManagement.Domain.Tests/Volo/Abp/FeatureManagement/FeatureManager_Tests.cs#L221-L222

Added lines #L221 - L222 were not covered by tests
}