设置
配置系统是在应用程序启动时进行配置的好方法。除了配置,ABP还提供了另一种设置和获取应用程序设置的方式。
设置是一个以名称-值对形式存储在动态数据源(通常是数据库)中的项。设置系统是可扩展的,并且为用户、租户、全局和默认提供了预构建的提供程序。
定义设置
在使用一个设置之前必须先定义它。ABP被设计为模块化,因此不同的模块可以有不同的设置。一个模块必须创建一个派生自SettingDefinitionProvider的类来定义其设置。下面是一个设置定义提供程序的示例:
public class EmailSettingProvider : SettingDefinitionProvider
{
public override void Define(ISettingDefinitionContext context)
{
context.Add(
new SettingDefinition("Smtp.Host", "127.0.0.1"),
new SettingDefinition("Smtp.Port", "25"),
new SettingDefinition("Smtp.UserName"),
new SettingDefinition("Smtp.Password", isEncrypted: true),
new SettingDefinition("Smtp.EnableSsl", "false")
);
}
}
如果你正在开发一个 DDD模块,通常会在
Domain层创建这个类,当然,这并不是强制性的。
ABP会自动发现这个类并注册设置定义。
SettingDefinition
SettingDefinition类具有以下属性:
- Name: 设置在应用程序中的唯一名称。这是唯一必需的属性。用于在应用程序代码中获取/设置此设置的值(为设置名称定义一个常量字符串而不是使用魔术字符串是个好主意)。
- DefaultValue: 设置可以有一个默认值。
- DisplayName: 一个可本地化的字符串,可用于在UI上显示设置名称。
- Description: 一个可本地化的字符串,可用于在UI上显示设置描述。
- IsVisibleToClients: 一个布尔值,指示此设置值是否在客户端可用。默认值为
false,以防止意外发布内部关键设置值。 - IsInherited: 一个布尔值,指示此设置值是否从其他提供程序继承。默认值为
true,如果未为请求的提供程序设置设置值,则会回退到下一个提供程序(更多信息请参见设置值提供程序部分)。 - IsEncrypted: 一个布尔值,指示此设置值在保存时是否应加密,在读取时是否应解密。这使得在数据库中保护设置值成为可能。
- Providers: 可用于限制特定设置可用的提供程序(更多信息请参见设置值提供程序部分)。
- Properties: 一个名称/值集合,用于设置有关此设置的自定义属性,这些属性稍后可在应用程序代码中使用。
修改依赖模块的设置定义
在某些情况下,你可能希望更改应用程序/模块所依赖的其他模块中定义的某些设置的属性。一个设置定义提供程序可以查询和更新设置定义。
以下示例获取由Volo.Abp.Emailing包定义的设置并更改其属性:
public class MySettingDefinitionProvider : SettingDefinitionProvider
{
public override void Define(ISettingDefinitionContext context)
{
var smtpHost = context.GetOrNull("Abp.Mailing.Smtp.Host");
if (smtpHost != null)
{
smtpHost.DefaultValue = "mail.mydomain.com";
smtpHost.DisplayName =
new LocalizableString(
typeof(MyLocalizationResource),
"SmtpServer_DisplayName"
);
}
}
}
为设置名称使用常量是一个好习惯,ABP包也是如此。
Abp.Mailing.Smtp.Host设置名称是由EmailSettingNames类(在Volo.Abp.Emailing命名空间中)定义的常量。
读取设置值
ISettingProvider
ISettingProvider用于获取一个设置的值或获取所有设置的值。使用示例:
public class MyService
{
private readonly ISettingProvider _settingProvider;
//在构造函数中注入ISettingProvider
public MyService(ISettingProvider settingProvider)
{
_settingProvider = settingProvider;
}
public async Task FooAsync()
{
//以字符串形式获取值。
string userName = await _settingProvider.GetOrNullAsync("Smtp.UserName");
//获取布尔值,如果未设置则回退到默认值(false)。
bool enableSsl = await _settingProvider.GetAsync<bool>("Smtp.EnableSsl");
//获取布尔值,如果未设置则回退到提供的默认值(true)。
bool enableSsl = await _settingProvider.GetAsync<bool>(
"Smtp.EnableSsl", defaultValue: true);
//使用IsTrueAsync快捷扩展方法获取布尔值
bool enableSsl = await _settingProvider.IsTrueAsync("Smtp.EnableSsl");
//获取整数值,如果未设置则使用默认值(0)
int port = (await _settingProvider.GetAsync<int>("Smtp.Port"));
//获取整数值,如果未提供则返回null
int? port = (await _settingProvider.GetOrNullAsync("Smtp.Port"))?.To<int>();
}
}
ISettingProvider是一个非常常见的服务,一些基类(如IApplicationService)已经通过属性注入了它。在这种情况下,你可以直接使用SettingProvider属性。
在客户端读取设置值
如果一个设置被允许在客户端可见,那么也可以在客户端代码中读取该设置的当前值。请参阅以下文档以了解如何在不同UI类型中获取设置值:
设置值提供程序
设置系统是可扩展的,你可以通过定义设置值提供程序来从任何源和基于任何条件获取设置值,从而扩展它。
ISettingProvider使用设置值提供程序来获取设置值。如果一个值提供程序无法获取设置值,它会回退到下一个值提供程序。
有5个预构建的设置值提供程序按以下顺序注册:
DefaultValueSettingValueProvider:从设置定义的默认值获取值(如果已设置,请参见上面的SettingDefinition部分)。ConfigurationSettingValueProvider:从IConfiguration服务获取值。GlobalSettingValueProvider:获取设置的全局(系统范围)值(如果已设置)。TenantSettingValueProvider:获取当前租户的设置值(如果已设置,请参见多租户文档)。UserSettingValueProvider:获取当前用户的设置值(如果已设置,请参见当前用户文档)。
设置回退系统的工作方式是从下(用户)到上(默认)。
全局、租户和用户设置值提供程序使用ISettingStore从数据源读取值(参见下面的部分)。
在应用程序配置中设置值
如前一节所述,ConfigurationSettingValueProvider从IConfiguration服务读取设置,该服务默认可以从appsettings.json读取值。因此,配置设置值的最简单方法是在appsettings.json文件中定义它们。
例如,你可以如下配置IEmailSender设置:
{
"Settings": {
"Abp.Mailing.DefaultFromAddress": "noreply@mydomain.com",
"Abp.Mailing.DefaultFromDisplayName": "My Application",
"Abp.Mailing.Smtp.Host": "mail.mydomain.com",
"Abp.Mailing.Smtp.Port": "547",
"Abp.Mailing.Smtp.UserName": "myusername",
"Abp.Mailing.Smtp.Password": "mySecretPassW00rd",
"Abp.Mailing.Smtp.EnableSsl": "True"
}
}
设置值应该像本例一样在Settings部分下配置。
IConfiguration是.NET Core服务,它不仅可以从appsettings.json读取值,还可以从环境变量、用户机密等读取值。更多信息请参见微软的文档。
在应用程序配置中加密设置值
当设置定义的IsEncrypted属性设置为true时(意味着设置值应在appsettings.json中加密),你必须使用ISettingEncryptionService来加密设置值。
将ISettingEncryptionService注入类中并加密明文的示例:
public class MyService
{
private readonly ISettingEncryptionService _encryptionService;
public MyService(ISettingEncryptionService encryptionService)
{
_encryptionService = encryptionService;
}
public void EncryptValue(string plainText)
{
var ciphertext = _encryptionService.Encrypt(plainText);
}
}
然后,将ENCRYPTED_VALUE_HERE替换为ISettingEncryptionService.Encrypt方法生成的密文。
{
"Settings": {
"MySetting": "ENCRYPTED_VALUE_HERE"
}
}
自定义设置值提供程序
如果你需要扩展设置系统,可以定义一个派生自SettingValueProvider的类。示例:
public class CustomSettingValueProvider : SettingValueProvider
{
public override string Name => "Custom";
public CustomSettingValueProvider(ISettingStore settingStore)
: base(settingStore)
{
}
public override Task<string> GetOrNullAsync(SettingDefinition setting)
{
/* 返回设置值或null
使用SettingStore或其他数据源 */
}
}
或者,你可以实现
ISettingValueProvider接口。在这种情况下,请记住将其注册到依赖注入。
每个提供程序必须有一个唯一的名称(这里为"Custom")。内置提供程序使用给定的名称:
DefaultValueSettingValueProvider: "D"ConfigurationSettingValueProvider: "C"GlobalSettingValueProvider: "G"TenantSettingValueProvider: "T"UserSettingValueProvider: "U"
优先选择单字母名称是为了减少数据库中的数据大小(提供程序名称在每一行中重复)。
定义自定义设置值提供程序后,需要显式地将其注册到AbpSettingOptions:
Configure<AbpSettingOptions>(options =>
{
options.ValueProviders.Add<CustomSettingValueProvider>();
});
这个例子将其添加为最后一项,因此它将是ISettingProvider使用的第一个值提供程序。你也可以将其添加到options.ValueProviders列表中的其他索引位置。
ISettingStore
虽然设置值提供程序可以自由使用任何源来获取设置值,但ISettingStore服务是设置值的默认源。全局、租户和用户设置值提供程序使用它。
ISettingEncryptionService
当设置定义的IsEncrypted属性设置为true时,ISettingEncryptionService用于加密/解密设置值。
你可以在依赖注入系统中替换此服务以自定义加密/解密过程。默认实现使用StringEncryptionService,该服务默认使用AES算法实现(更多信息请参见字符串加密文档)。
设置管理模块
核心设置系统非常独立,并且不对你如何管理(更改)设置值做出任何假设。甚至默认的ISettingStore实现是NullSettingStore,它为所有设置值返回null。
设置管理模块通过管理数据库中的设置值来完善它(并实现ISettingStore)。更多信息请参见设置管理模块文档。
抠丁客


