Abp 扩展设置

在ABP 框架中,已经自带了设置管理。包括读取,存储和修改。


不过,设置管理 都是 以 设置名称(name) 来读取控制的。在一些情况下,我希望 将设置的一类值放在一起,以单独的一个类(实体) 来读取访问,来更好的控制。

比如:我需要保存网站用于发送邮件的SMTP信息。我不想使用这种默认的方法来读取,因为太麻烦了,并且有可能 会造成错误。

//读取
string host = await SettingManager.GetSettingValueForApplicationAsync("smtp_host");
string username = await SettingManager.GetSettingValueForApplicationAsync("smtp_username");
string password = await SettingManager.GetSettingValueForApplicationAsync("smtp_password");
string email = await SettingManager.GetSettingValueForApplicationAsync("smtp_userPassword");
int port = await SettingManager.GetSettingValueForApplicationAsync<int>("smtp_port");
bool ssl = await SettingManager.GetSettingValueForApplicationAsync<bool>("smtp_ssl");

// 保存
await SettingManager.ChangeSettingForApplicationAsync("smtp_host", "smtp.qq.com");
// ...
像这样,在抹些情况下,很容易出错。
然而,我希望将这一组信息独立到一个类里面(实体)。
/// <summary>
/// SMTP 设置
/// </summary>
public class SmtpSetting 
{
    /// <summary>
    /// 主机
    /// </summary>
    public string Host { get; set; }
    /// <summary>
    /// Email
    /// </summary>
    public string Email { get; set; }
    /// <summary>
    /// 端口
    /// </summary>
    public int Port { get; set; }
    /// <summary>
    /// 使用SSL
    /// </summary>
    public bool UseSsl { get; set; }
    /// <summary>
    /// 用户名
    /// </summary>
    public string Username { get; set; }
    /// <summary>
    /// 密码
    /// </summary>
    public string Password { get; set; }

    public bool IsEnable()
    {
        return !string.IsNullOrEmpty(Host) && !string.IsNullOrEmpty(Email) && !string.IsNullOrEmpty(Username) && !string.IsNullOrEmpty(Password);
    } 
}

但是,我在 ABP 的 SettingManager 中并没有找到对应的方法(也许是我没找到),,,为此: 我扩展了 SettingManager 的方法,使 SettingManager 可以直接读取和修改 一个 类设置。

首先,定义一个类设置接口,其中并没有任何定义。
/// <summary>
/// 只是一个标记
/// </summary>
public interface IEntitySetting
{
}
第二步,扩展 SettingManager 的方法:
    public static class SettingManagerExtensions
    { 
        public static async Task<T> GetEntitySettingValueAsync<T>(this ISettingManager settingManager) where T : IEntitySetting, new()
        {
            var settings = Activator.CreateInstance<T>();
            var propes = typeof(T).GetProperties().Where(t => t.CanRead && t.CanWrite);
            foreach (var p in propes)
            {
                var key = string.Format("{0}.{1}", typeof(T).Name, p.Name);

                string setting = await settingManager.GetSettingValueAsync(key);
                if (setting == null)
                    continue;

                if (!TypeDescriptor.GetConverter(p.PropertyType).CanConvertFrom(typeof(string)))
                    continue;
                if (!TypeDescriptor.GetConverter(p.PropertyType).IsValid(setting))
                    continue;

                object value = TypeDescriptor.GetConverter(p.PropertyType).ConvertFromInvariantString(setting);

                p.SetValue(settings, value);
            }

            return settings;
        }

        public static async Task ChangeEntitySettingForApplicationAsync<T>(this ISettingManager settingManager, T setting) where T : IEntitySetting
        {
            var propes = typeof(T).GetProperties().Where(t => t.CanRead && t.CanWrite);
            foreach (var p in propes)
            {
                var key = string.Format("{0}.{1}", typeof(T).Name, p.Name);

                if (!TypeDescriptor.GetConverter(p.PropertyType).CanConvertFrom(typeof(string)))
                    continue;

                object value = p.GetValue(setting, null);
                if (value != null)
                    await settingManager.ChangeSettingForApplicationAsync(key, value.ToString());
                else
                    await settingManager.ChangeSettingForApplicationAsync(key, "");
            }
        }

        public static async Task ChangeEntitySettingForUserAsync<T>(this ISettingManager settingManager, T setting, long userId) where T : IEntitySetting
        {
            var propes = typeof(T).GetProperties().Where(t => t.CanRead && t.CanWrite);
            foreach (var p in propes)
            {
                var key = string.Format("{0}.{1}", typeof(T).Name, p.Name);

                if (!TypeDescriptor.GetConverter(p.PropertyType).CanConvertFrom(typeof(string)))
                    continue;

                dynamic value = p.GetValue(setting, null);
                if (value != null)
                    await settingManager.ChangeSettingForUserAsync(userId, key, (string)value);
                else
                    await settingManager.ChangeSettingForUserAsync(userId, key, "");
            }
        }

        public static async Task ChangeEntitySettingForTenantAsync<T>(this ISettingManager settingManager, T setting, int tenantId) where T : IEntitySetting
        {
            var propes = typeof(T).GetProperties().Where(t => t.CanRead && t.CanWrite);
            foreach (var p in propes)
            {
                var key = string.Format("{0}.{1}", typeof(T).Name, p.Name);

                if (!TypeDescriptor.GetConverter(p.PropertyType).CanConvertFrom(typeof(string)))
                    continue;

                dynamic value = p.GetValue(setting, null);
                if (value != null)
                    await settingManager.ChangeSettingForTenantAsync(tenantId, key, (string)value);
                else
                    await settingManager.ChangeSettingForTenantAsync(tenantId, key, "");
            }
        }
    }
第三步,添加 一个 SettingProvider ,因为, ABP 中的 setting 必须 要先定义 SettingDefinition ,才能使用。
    public class EntitySettingProvider : SettingProvider
    {
        public override IEnumerable<SettingDefinition> GetSettingDefinitions(SettingDefinitionProviderContext context)
        {
            var types = Assembly.GetAssembly(typeof(IEntitySetting)).GetTypes().Where(t => typeof(IEntitySetting).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface);

            var result = new List<SettingDefinition>();

            foreach (var type in types)
            {
                var settings = Activator.CreateInstance(type);

                var propes = type.GetProperties().Where(t => t.CanRead && t.CanWrite);
                foreach (var p in propes)
                {
                    string name = string.Format("{0}.{1}", type.Name, p.Name);

                    var setting = new SettingDefinition(name, "");

                    // 取初始值
                    if (TypeDescriptor.GetConverter(p.PropertyType).CanConvertFrom(typeof(string)))
                    {
                        object value = p.GetValue(settings, null);

                        if (value != null)
                            setting = new SettingDefinition(name, value.ToString());
                    }

                    result.Add(setting);
                }
            }

            return result;
        }
    }
第四步,将 EntitySettingProvider 添加到 Configuration 中的 Settings 里面。
// Settings
Configuration.Settings.Providers.Add<EntitySettingProvider>();


OK , 好了!。

将一开始的 SmtpSetting 修改下。

/// <summary>
/// SMTP 设置
/// </summary>
public class SmtpSetting : IEntitySetting
{
    // ... 
}
获取设置:
var settingEntity = await SettingManager.GetEntitySettingValueAsync<SmtpSetting>();

修改设置:

await SettingManager.ChangeEntitySettingForApplicationAsync(new SmtpSetting(){ Host = "smtp.qq.com"  });