ABP框架系列之四十六:(Setting-Management-设置管理)
Introduction
Every application need to store some settings and use these settings in somewhere in the application. ASP.NET Boilerplate provides a strong infrastructure to store/retrieve application, tenant and user level settings usable both in server and client sides.
每个应用程序都需要存储一些设置,并在应用程序的某处使用这些设置。ASP.NET样板提供了强大的基础设施来存储/检索应用程序,租户和用户级别的设置均可用的服务器和客户端。
A setting is a name-value string pair that is generally stored in a database (or another source). We can store non-string values by converting to string.
设置是一个名称值字符串对,通常存储在数据库中(或另一个源)。我们可以通过转换字符串来存储非字符串值。
About ISettingStore
ISettingStore interface must be implemented in order to use setting system. While you can implement it in your own way, it's fully implemented in module-zero project. If it's not implemented, settings are read from application's configuration file (web.config or app.config) but can not change any setting. Also, scoping will not work.
isettingstore接口必须实现为了使用系统设置。虽然可以以自己的方式实现它,但它完全在module-zero的项目中实现。如果不实施,设置是从应用程序的配置文件的读取(Web.config或应用程序配置)但不能改变任何设置。同时,范围将不工作。
Defining settings
A setting must be defined before usage. ASP.NET Boilerplate is designed to be modular. So, different modules can have different settings. A module should create a class derived from SettingProvider in order to define it's settings. An example setting provider is shown below:
设置必须在使用前定义。ASP.NET样板的设计是模块化的。因此,不同的模块可以有不同的设置。一个模块应该创建一个类的派生类settingprovider为了定义它的设置。示例设置提供程序如下所示:
public class MySettingProvider : SettingProvider { public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context) { return new[] { new SettingDefinition( "SmtpServerAddress", "127.0.0.1" ), new SettingDefinition( "PassiveUsersCanNotLogin", "true", scopes: SettingScopes.Application | SettingScopes.Tenant ), new SettingDefinition( "SiteColorPreference", "red", scopes: SettingScopes.User, isVisibleToClients: true ) }; } }
GetSettingDefinitions method should return SettingDefinition objects. SettingDefinition class has some parameters in it's constructor:
- Name (required): A setting must have a system-wide unique name. It's good idea to define a const string for a setting name instead of a magic string.
- Default value: A setting may have a default value. This value can be null or empty string.
- Scopes: A setting should define it's scope (see below).
- Display name: A localizable string that can be used to show setting's name later in UI.
- Description: A localizable string that can be used to show setting's description later in UI.
- Group: Can be used to group settings. This is just for UI, not used in setting management.
- IsVisibleToClients: Set true to make a setting usable on the client side.
- isInherited: Used to set if this setting is inherited by tenant and users (See setting scope section).
- customData: Can be used to set a custom data for this setting definition.
-
名称(必填):设置必须具有全系统唯一名称。为一个设置名称而不是一个魔术字符串定义一个常量字符串是一个好主意。
默认值:设置可能具有默认值。此值可以是空字符串或空字符串。
范围:一个设置应该定义它的作用域(见下文)。
显示名称:可本地化的字符串,可以用来显示设置的名字后来在UI。
描述:可本地化的字符串,可以用来显示设置的描述后来在UI。
组:可用于组设置。这只是用于UI,而不是用于设置管理。
对客户端可见:使设置可用的客户端。
来源:用来设置如果设置是由承租人和用户继承(见设置范围部分)。
自定义数据:可以用于此设置定义设置自定义数据。
After creating a setting provider, we should register it in PreIntialize method of our module:
Configuration.Settings.Providers.Add<MySettingProvider>();
Setting providers are registered to dependency injection automatically. So, a setting provider can inject any dependency (like a repository) to build setting definitions using some other sources.
设置提供者自动注册为依赖注入。因此,设置提供程序可以注入任何依赖项(如存储库)以使用其他源构建设置定义。
Setting scope
There are three setting scopes (or levels) defined in SettingScopes enum:
- Application: An application scoped setting is used for user/tenant independed settings. For example, we can define a setting named "SmtpServerAddress" to get server's IP address when sending emails. If this setting has a single value (not changes based on users), then we can define it as Application scoped.
- Tenant: If the application is multi-tenant, we can define tenant-specific settings.
- User: We can use a user scoped setting to store/get value of the setting specific to each user.
-
应用范围:应用范围设置用于用户/租户独立设置。例如,我们可以定义一个名为“smtpserveraddress”获得服务器的IP地址发送邮件时。如果此设置一个值(不改变基于用户),那么我们可以把它定义为应用程序范围。
租户:如果应用程序是多租户,我们可以定义特定于租户的设置。
用户:我们可以用一个用户范围的设置存储到设置特定于每个用户的价值。
SettingScopes enum has Flags attribute, so we can define a setting with more than one scopes.
Setting scope is hierarchic by default (unless you set isInherited to false). For example, if we define a setting's scope as "Application | Tenant | User" and try to get current value of the the setting;
- We get the user-specific value if it's defined (overrided) for the user.
- If not, we get the tenant-specific value if it's defined (overrided) for the tenant.
- If not, we get the application value if it's defined.
- If not, we get the default value.
Default value can be null or empty string. It's adviced to provide default values for settings where it's possible.
Overriding Setting Definitions(重写设置定义)
context.Manager can be used to get a setting definition to change it's values. In this way, you can manipulate setting definitions of depended modules.
Getting setting values
After defining a setting, we can get it's current value both in server and client.
Server side
ISettingManager is used to perform setting operations. We can inject and use it anywhere in the application. ISettingManager defines many methods to get a setting's value.
Most used method is GetSettingValue (or GetSettingValueAsync for async call). It returns current value of the setting based on default value, application, tenant and user settings (as described in Setting scope section before). Examples:
isettingmanager进行设置操作。我们可以在应用程序的任何地方注入和使用它。isettingmanager定义了许多方法来设置的值。
最常用的方法是getsettingvalue(或getsettingvalueasync异步调用)。它返回基于默认值、应用程序、租户和用户设置的当前值(如前面设置范围部分所述)。实例:
//Getting a boolean value (async call) var value1 = await SettingManager.GetSettingValueAsync<bool>("PassiveUsersCanNotLogin"); //Getting a string value (sync call) var value2 = SettingManager.GetSettingValue("SmtpServerAddress");
GetSettingValue has generic and async versions as shown above. There are also methods to get a specific tenant or user's setting value or list of all setting values.
Since ISettingManager is widely used, some special base classes (like ApplicationService, DomainService and AbpController) has a property named SettingManager. If we derived from these classes, no need to explicitly inject it.
getsettingvalue具有通用的异步版本,如上图所示。还有一些方法可以获得特定的租户或用户的设置值或所有设置值的列表。
自从ISettingManager被广泛使用,一些特殊的基类(如应用服务,按和AbpController)有一个属性叫settingmanager。如果我们从这些类派生,不需要显式地注入它。
Client side
If you set IsVisibleToClients as true while defining a setting, then you can get it's current value in the client side using javascript. abp.setting namespace defines needed functions and objects. Example:
var currentColor = abp.setting.get("SiteColorPreference");
There is also getInt and getBoolean methods. You can get all values using abp.setting.values object. Note that; If you change a setting in server side, clienct can not know this change unless page is refreshed, settings are somehow reloaded or it's manually updated by code.
因此,有getboolean GetInt的和方法。你可以得到所有的abp.setting.values对象的值使用。注意,如果你更改一个设置在服务器端,需要变更,除非专门clienct CAN这是refreshed设置页,它是不知何故重装或手动更新的代码。
Changing settings
ISettingManager defines ChangeSettingForApplicationAsync, ChangeSettingForTenantAsync and ChangeSettingForUserAsync methods (and sync versions) to change settings for the application, for a tenant and for a user respectively.
isettingmanager定义changesettingforapplicationasync,ChangeSettingForTenantAsync和ChangeSettingForUserAsync的方法(和同步版本)更改应用程序设置,为租户和用户分别。
About caching
Setting Manager caches settings on the server side. So, we should not directly change a setting value using repository or database update query.
设置管理器缓存服务器端的设置。因此,我们不应该直接使用存储库或数据库更新查询更改设置值。