Abp扩展之【配置功能】
Abp的扩展功能非常强大,配合持久化可以很方便的配置系统、租户、用户的配置,关于ABP的配置请参考:
http://www.cnblogs.com/farb/p/ABPSettingManagement.html
虽然此方式配合静态KEY配置使用ISettingManager获取很方便,但是还是有很多不便,每个配置都需要去单独获取并指定类型
并且一次只能获取一个配置值,那么我们能不能直接就像使用ISettingManager来直接注入我们的配置呢,今天的扩展将实现此
功能以达到如下需求:
配置:
1 [AbpAuthorize] 2 public class ConfigurationAppService : XAppServiceBase, IConfigurationAppService 3 { 9 public XSettings GetXSettings() 10 { 11 var obj = IocManager.Instance.Resolve<XSettings>(); 12 return obj; 13 } 14 15 public async Task SaveXSettings(XSettings setting) 16 { 17 await setting.SaveAsync(); 18 } 19 }
使用:
1 public class DemoAppService : ApplicationService, IDemoAppService 2 { 3 public XSettings Settings { get; set; } 4 5 public void Test() 6 { 7 var size = this.Settings.PageSize; 8 } 9 }
上面代码的重点在XSettings这个类上,那么就从这个类说起,先看看这个配置类:
public class XSettings : SettingBase { [SettingDefinition("XProject")] [Required(ErrorMessage = "系统名称不能为空!")] public string SystemName { get; set; } [SettingDefinition(20, true)] public int PageSize { get; set; } //[SettingDefinition(true)] public bool IsOpen { get; set; } }
很简单的一个配置,但是有一个基类和一个特性,先看一下特性类
public class SettingDefinitionAttribute : Attribute { public string DefaultValue { get; private set; } public bool IsVisibleToClients { get; private set; } public SettingScopes Scopes { get; private set; } public SettingDefinitionAttribute(object defaultValue, bool isVisibleToClients = true, SettingScopes scopes = SettingScopes.Application) { this.DefaultValue = defaultValue?.ToString(); this.IsVisibleToClients = isVisibleToClients; this.Scopes = scopes; } }
我们的特性定义了该配置项的ABP配置功能,包括了默认值、是否显示到客户端、和使用域,这样就表示了配置类中的属性相关的ABP配置了
定义好了配置后,那我们怎么保存和获取呢?这就需要我们的基类出场了:
public abstract class SettingBase : ITransientDependency { private ISettingManager _SettingManager; private IAbpSession _Session; public SettingBase() { this._SettingManager = IocManager.Instance.Resolve<ISettingManager>(); this._Session = IocManager.Instance.Resolve<IAbpSession>(); var t = this.GetType(); var ps = t.GetProperties(); foreach (var p in ps) { var settingValue = _SettingManager.GetSettingValue($"{t.Name}.{p.Name}"); p.SetValue(this, Convert.ChangeType(settingValue, p.PropertyType)); } } public async Task SaveAsync() { var t = this.GetType(); var ps = t.GetProperties(); foreach (var p in ps) { var key = $"{t.Name}.{p.Name}"; var val = p.GetValue(this)?.ToString(); var attr = p.GetCustomAttribute<SettingDefinitionAttribute>(); if (attr != null) { if (attr.Scopes.HasFlag(SettingScopes.User) && this._Session.UserId.HasValue) await _SettingManager.ChangeSettingForUserAsync(this._Session.ToUserIdentifier(), key, val); else if (attr.Scopes.HasFlag(SettingScopes.Tenant) && this._Session.TenantId.HasValue) await _SettingManager.ChangeSettingForTenantAsync(this._Session.TenantId.Value, key, val); else await _SettingManager.ChangeSettingForApplicationAsync(key, val); } else await _SettingManager.ChangeSettingForApplicationAsync(key, val); } } public void Save() { AsyncHelper.RunSync(() => { return this.SaveAsync(); }); } }
基类中也很简单,就是初始化的时候,从ISettingManager中加载相应的配置设置到对应的属性上,并定义了两个保存方法来保存我们修改后的配置
这里我之前用过一种方式就是直接设置属性的时候就自动保存,不过后面又换成了现在需要调用一个save方法的方式了。
定义好配置加载和保存了,就只剩下初始化了,我们希望我定义好配置类以后就能在启动的时候自动初始化,所以定义了一个AutoSettingProvider
public class AutoSettingProvider : SettingProvider { public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context) { var settings = new List<SettingDefinition>(); var types = this.GetType().Assembly .GetTypes() .Where(t => t.IsClass && typeof(SettingBase).IsAssignableFrom(t)); foreach (var t in types) { var scopes = SettingScopes.All; foreach (var p in t.GetProperties()) { var key = $"{t.Name}.{p.Name}"; var isVisibleToClients = false; var defaultValue = p.PropertyType.IsValueType ? Activator.CreateInstance(p.PropertyType).ToString() : string.Empty; var attr = p.GetCustomAttribute<SettingDefinitionAttribute>(); if (attr != null) { scopes = attr.Scopes; defaultValue = attr.DefaultValue; isVisibleToClients = attr.IsVisibleToClients; } settings.Add(new SettingDefinition( name: key, defaultValue: defaultValue, scopes: scopes, isVisibleToClients: isVisibleToClients )); } } return settings; } }
到这里,我们的配置扩展就算完成了。在所有我们需要使用的地方都可以直接注入使用了。