一、配置的初始化
SettingOptions有集合列表:DefinitionProviders,ValueProviders,配置方法见下
1、在模块PreConfigureServices只需实现了ISettingDefinitionProvider,自动添加到设置的定义DefinitionProviders里。是自定义配置定义的settingdefinition的方法
2、ISettingValueProvider 提供了4个自定义的获取设置值的提供方法,分别是默认值提供者,全局值提供者,租户值提供,用户值提供;是获取提供参数的不同
public override void PreConfigureServices(ServiceConfigurationContext context)
{
AutoAddDefinitionProviders(context.Services);
}
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<SettingOptions>(options =>
{
options.ValueProviders.Add<DefaultValueSettingValueProvider>();
options.ValueProviders.Add<GlobalSettingValueProvider>();
options.ValueProviders.Add<TenantSettingValueProvider>();
options.ValueProviders.Add<UserSettingValueProvider>();
});
}
private static void AutoAddDefinitionProviders(IServiceCollection services)
{
var definitionProviders = new List<Type>();
services.OnRegistred(context =>
{
if (typeof(ISettingDefinitionProvider).IsAssignableFrom(context.ImplementationType))
{
definitionProviders.Add(context.ImplementationType);
}
});
services.Configure<SettingOptions>(options =>
{
options.DefinitionProviders.AddIfNotContains(definitionProviders);
});
}
3、settingdefinition配置定义,如名字,显示值,描述,默认值,是否对客户端可显示,提供列表,用户自定义属性,是否加密
4、SettingDefinitionProvider提供者,定义配置的上下文Define(ISettingDefinitionContext context),存储配置字典的定义 Dictionary<string, SettingDefinition>
key值为definition.Name,value值为definition。比如邮件设置的上下文
internal class EmailSettingProvider : SettingDefinitionProvider { public override void Define(ISettingDefinitionContext context) { context.Add( new SettingDefinition(EmailSettingNames.Smtp.Host, "127.0.0.1"), new SettingDefinition(EmailSettingNames.Smtp.Port, "25"), new SettingDefinition(EmailSettingNames.Smtp.UserName), new SettingDefinition(EmailSettingNames.Smtp.Password, isEncrypted: true), new SettingDefinition(EmailSettingNames.Smtp.Domain), new SettingDefinition(EmailSettingNames.Smtp.EnableSsl, "false"), new SettingDefinition(EmailSettingNames.Smtp.UseDefaultCredentials, "true"), new SettingDefinition(EmailSettingNames.DefaultFromAddress, "noreply@abp.io"), new SettingDefinition(EmailSettingNames.DefaultFromDisplayName, "ABP application") ); } }
5、在SettingDefinitionManager的构造函数,遍历Options.DefinitionProviders,填充成字典new Dictionary<string, SettingDefinition>()
public SettingDefinitionManager(
IOptions<SettingOptions> options,
IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider;
Options = options.Value;
SettingDefinitions = new Lazy<IDictionary<string, SettingDefinition>>(CreateSettingDefinitions, true);
}
protected virtual IDictionary<string, SettingDefinition> CreateSettingDefinitions()
{
var settings = new Dictionary<string, SettingDefinition>();
using (var scope = ServiceProvider.CreateScope())
{
var providers = Options
.DefinitionProviders
.Select(p => scope.ServiceProvider.GetRequiredService(p) as ISettingDefinitionProvider)
.ToList();
foreach (var provider in providers)
{
provider.Define(new SettingDefinitionContext(settings));
}
}
return settings;
}
二、ISettingProvider是提供获取设置值方法服务,其实现构造函数有options,serviceProvider,settingDefinitionManager,settingEncryptionService
ISettingValueProvider的Reverse,表明顺序是:用户》租户》全局》默认;setting.Providers是允许的提供者
public virtual async Task<string> GetOrNullAsync(string name)
{
//获取属性值
var setting = SettingDefinitionManager.Get(name);
var providers = Enumerable
.Reverse(Providers.Value);
if (setting.Providers.Any())
{
providers = providers.Where(p => setting.Providers.Contains(p.Name));
}
//TODO: How to implement 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)
{
//遍历对应值提供Providers,获取对应的值
foreach (var provider in providers)
{
var value = await provider.GetOrNullAsync(setting);
if (value != null)
{
return value;
}
}
return null;
}
配置值的提供者ISettingValueProvider,有多个提供者,
1)默认提供者,获取配置定义的值,即SettingDefinition.DefaultValue
2)全局提供者,从ISettingStore获取值,ProviderName = "Global"
3)租户提供者,从ISettingStore获取值,providerName=Tenant,providerKey=CurrentTenant.Id?.ToString()
4)用户提供者,从ISettingStore获取值,providerName=User,providerKey=CurrentUser.Id.ToString()
ISettingStore的实现在 Volo.Abp.SettingManagement,使用ISettingManagementStore得GetOrNullAsync方法
优先从获取IDistributedCache<SettingCacheItem> Cache 里面缓存,若没有则设置缓存
public async Task<string> GetOrNullAsync(string name, string providerName, string providerKey)
{
var cacheItem = await GetCacheItemAsync(name, providerName, providerKey);
return cacheItem.Value;
}
protected virtual async Task<SettingCacheItem> GetCacheItemAsync(string name, string providerName, string providerKey)
{
var cacheKey = CalculateCacheKey(name, providerName, providerKey);
var cacheItem = await Cache.GetAsync(cacheKey);
if (cacheItem != null)
{
return cacheItem;
}
var setting = await SettingRepository.FindAsync(name, providerName, providerKey);
cacheItem = new SettingCacheItem(setting?.Value);
await Cache.SetAsync(
cacheKey,
cacheItem
);
return cacheItem;
}
protected virtual string CalculateCacheKey(string name, string providerName, string providerKey)
{
return SettingCacheItem.CalculateCacheKey(name, providerName, providerKey);
}
public static string CalculateCacheKey(string name, string providerName, string providerKey)
{
return "pn:" + providerName + ",pk:" + providerKey + ",n:" + name;
}
Volo.Abp.SettingManagement.EntityFrameworkCore
public async Task<Setting> FindAsync(string name, string providerName, string providerKey)
{
return await DbSet
.FirstOrDefaultAsync(
s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey
);
}