配置系统(Configuration System)是一个不错方式在应用 Startup配置,ABP提供另一种方式获取和配置应用设置
配置是一个Name-Vaule键值对,设置系统是可扩展,内置提供 user, a tenant, global and default等方式,
ISettingProvider,通常用于获取和设置设置值,常用方法:GetOrNullAsync,GetAllAsync
在IApplicationService已经属性注入
string userName = await _settingProvider.GetOrNullAsync("Smtp.UserName"); //Get a bool value and fallback to the default value (false) if not set. bool enableSsl = await _settingProvider.GetAsync<bool>("Smtp.EnableSsl"); //Get a bool value and fallback to the provided default value (true) if not set. bool enableSsl = await _settingProvider.GetAsync<bool>( "Smtp.EnableSsl", defaultValue: true); //Get a bool value with the IsTrueAsync shortcut extension method bool enableSsl = await _settingProvider.IsTrueAsync("Smtp.EnableSsl"); //Get an int value or the default value (0) if not set int port = (await _settingProvider.GetAsync<int>("Smtp.Port")); //Get an int value or null if not provided int? port = (await _settingProvider.GetOrNullAsync("Smtp.Port"))?.To<int>();
一、配置的初始化
SettingOptions有集合列表:DefinitionProviders,ValueProviders,配置方法见下
1、在模块PreConfigureServices只需实现了ISettingDefinitionProvider,自动添加到设置的定义DefinitionProviders里。是自定义配置定义的settingdefinition的方法
2、ISettingValueProvider 提供了4个自定义的获取设置值的提供方法,实现基类SettingValueProvider,分别是默认值提供者,全局值提供者,租户值提供,用户值提供;是获取提供参数的ProviderName = Global,Tenant,User(取第一个字母)给SettingStore,而providerKey分别是,null,CurrentTenant.Id?.ToString(),CurrentUser.Id.ToString()
public override void PreConfigureServices(ServiceConfigurationContext context) { AutoAddDefinitionProviders(context.Services); } public override void ConfigureServices(ServiceConfigurationContext context) { Configure(options => { options.ValueProviders.Add (); options.ValueProviders.Add (); options.ValueProviders.Add (); options.ValueProviders.Add (); }); }
private static void AutoAddDefinitionProviders(IServiceCollection services) { var definitionProviders = new List(); services.OnRegistred(context => { if (typeof(ISettingDefinitionProvider).IsAssignableFrom(context.ImplementationType)) { definitionProviders.Add(context.ImplementationType); } }); services.Configure (options => { options.DefinitionProviders.AddIfNotContains(definitionProviders); }); }
3、settingdefinition配置定义,如名字(唯一、强制属性),默认值,显示值(本地化在UI显示),描述,是否对客户端可显示,是否继承,
提供列表(掼定提供者),用户自定义属性,是否加密
4、SettingDefinitionProvider提供者,定义配置的上下文Define(ISettingDefinitionContext context),存储配置字典的定义 Dictionary
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, "[email protected]"), new SettingDefinition(EmailSettingNames.DefaultFromDisplayName, "ABP application") ); } }
5、在SettingDefinitionManager的构造函数,遍历Options.DefinitionProviders,填充成字典new Dictionary
用于AbpApplicationConfigurationAppService生成所有设置字段
用于ISettingProvider,得到SettingDefinition
public SettingDefinitionManager( IOptionsoptions, IServiceProvider serviceProvider) { ServiceProvider = serviceProvider; Options = options.Value; SettingDefinitions = new Lazy >(CreateSettingDefinitions, true); } protected virtual IDictionary CreateSettingDefinitions() { var settings = new Dictionary (); 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; }
6、ISettingValueProviderManager,使用List
public SettingValueProviderManager( IServiceProvider serviceProvider, IOptionsoptions) { Options = options.Value; _lazyProviders = new Lazy >( () => Options .ValueProviders .Select(type => serviceProvider.GetRequiredService(type) as ISettingValueProvider) .ToList(), true ); }
二、ISettingProvider是提供获取设置值方法服务,其实现构造函数有options,serviceProvider,settingDefinitionManager,settingEncryptionService
ISettingValueProvider的Reverse,表明顺序是:用户》租户》全局》默认;setting.Providers是允许的提供者
public virtual async TaskGetOrNullAsync(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 TaskGetOrNullValueFromProvidersAsync( IEnumerable 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
public async TaskGetOrNullAsync(string name, string providerName, string providerKey) { var cacheItem = await GetCacheItemAsync(name, providerName, providerKey); return cacheItem.Value; } protected virtual async Task 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 TaskFindAsync(string name, string providerName, string providerKey) { return await DbSet .FirstOrDefaultAsync( s => s.Name == name && s.ProviderName == providerName && s.ProviderKey == providerKey ); }