当我们构建好参数的定义之后,我们要设置某个参数的值,或者说获取某个参数的值应该怎么操作呢?查看相关的单元测试,看到了 ABP vNext 自身是注入 ISettingProvider ,调用它的 GetOrNullAsync() 获取参数值。
private readonly ISettingProvider _settingProvider; var settingValue = await _settingProvider.GetOrNullAsync("WebSite.Title")跳转到接口,发现它有两个实现,这里我们只讲解一下 SettingProvider 类的实现。
2.3.1 获取参数值直奔主题,来看一下 ISettingProvider.GetOrNullAsync(string) 方法是怎么来获取参数值的。
public class SettingProvider : ISettingProvider, ITransientDependency { protected ISettingDefinitionManager SettingDefinitionManager { get; } protected ISettingEncryptionService SettingEncryptionService { get; } protected ISettingValueProviderManager SettingValueProviderManager { get; } public SettingProvider( ISettingDefinitionManager settingDefinitionManager, ISettingEncryptionService settingEncryptionService, ISettingValueProviderManager settingValueProviderManager) { SettingDefinitionManager = settingDefinitionManager; SettingEncryptionService = settingEncryptionService; SettingValueProviderManager = settingValueProviderManager; } public virtual async Task<string> GetOrNullAsync(string name) { // 根据名称获取参数定义。 var setting = SettingDefinitionManager.Get(name); // 从参数值提供者管理器,获得一堆参数值提供者。 var providers = Enumerable .Reverse(SettingValueProviderManager.Providers); // 过滤符合参数定义的提供者,这里就是用到了之前参数定义的 List<string> Providers 属性。 if (setting.Providers.Any()) { providers = providers.Where(p => setting.Providers.Contains(p.Name)); } //TODO: How to implement setting.IsInherited? //TODO: 如何实现 setting.IsInherited 功能? var value = await GetOrNullValueFromProvidersAsync(providers, setting); // 如果参数是加密的,则需要进行解密操作。 if (setting.IsEncrypted) { value = SettingEncryptionService.Decrypt(setting, value); } return value; } protected virtual async Task<string> GetOrNullValueFromProvidersAsync(IEnumerable<ISettingValueProvider> providers, SettingDefinition setting) { // 只要从任意 Provider 中,读取到了参数值,就直接进行返回。 foreach (var provider in providers) { var value = await provider.GetOrNullAsync(setting); if (value != null) { return value; } } return null; } // ... }所以真正干活的还是 ISettingValueProviderManager 里面存放的一堆 ISettingValueProvider ,这个 参数值管理器 的接口很简单,只提供了一个 List<ISettingValueProvider> Providers { get; } 的定义。
它会从模块配置的 ValueProviders 属性内部,通过 IoC 实例化对应的参数值提供者。
_lazyProviders = new Lazy<List<ISettingValueProvider>>( () => Options .ValueProviders .Select(type => serviceProvider.GetRequiredService(type) as ISettingValueProvider) .ToList(), true 2.3.2 参数值提供者参数值提供者的接口定义是 ISettingValueProvider,它定义了一个名称和 GetOrNullAsync(SettingDefinition) 方法,后者可以通过参数定义获取存储的值。
public interface ISettingValueProvider { string Name { get; } Task<string> GetOrNullAsync([NotNull] SettingDefinition setting); }注意这里的返回值是 Task<string> ,也就是说我们的参数值类型必须是 string 类型的,如果需要存储其他的类型可能就需要从 string 进行类型转换了。
在这里的 SettingValueProvider 其实类似于我们之前讲过的 权限提供者。因为 ABP vNext 考虑到了多种情况,我们的参数值有可能是根据用户获取的,同时也有可能是根据不同的租户进行获取的。所以 ABP vNext 为我们预先定义了四种参数值提供器,他们分别是 DefaultValueSettingValueProvider、GlobalSettingValueProvider、TenantSettingValueProvider、UserSettingValueProvider 。
下面我们就来讲讲这几个不同的参数提供者有啥不一样。
DefaultValueSettingValueProvider:
顾名思义,默认值参数提供者就是使用的参数定义里面的 DefaultValue 属性,当你查询某个参数值的时候,就直接返回了。
public override Task<string> GetOrNullAsync(SettingDefinition setting) { return Task.FromResult(setting.DefaultValue); }GlobalSettingValueProvider: