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;
        }
    }

 

到这里,我们的配置扩展就算完成了。在所有我们需要使用的地方都可以直接注入使用了。

posted @ 2017-12-19 10:57  Never.Net  阅读(1707)  评论(0编辑  收藏  举报