ABP开发框架先后端开发系列---(12)配置模块的管理

通常来讲,一个系统或多或少都会涉及到一些系统参数或者用户信息的配置,而ABP框架也提供了一套配置信息的管理模块,ABP框架的配置信息,必须提早定义好配置的各项内容,而后才能在系统中初始化或者经过接口查询来使用,本篇随笔引入了另一种配置信息的定义,实现更加简化的处理,本篇随笔着重介绍二者之间的差别和不一样的地方。html

一、ABP框架的配置管理

以下面是邮件配置信息,配置信息通常先继承自SettingProvider,初始化定义后,才能被系统所使用。数据库

EmailSettingProvider:继承自SettingProvider, 将SMTP的各项设置封装成SettingDefinition,并以数组形式返回后端

配置的管理类,主要经过接口ISettingManager来进行统一管理的,底层协同了SettingStore配置存储和SetttingDefinitionMananger的配置定义管理两个部分。数组

这种方式的配置信息,糅合了配置项的定义(强制性),以及多语言特性的处理,根据不一样的语言返回不一样的配置名称,同时也整合了缓存信息的处理,以减小系统的一些消耗。 缓存

不过从上面的图示咱们也能够看到,整个配置模块因为引入这些内容,致使处理起来必须循序渐进的建立配置管理类,定义配置信息,从新编译系统后,而后才能进行信息的调用,所以这些配置信息必须预约义。并且管理起来协同这些类的处理,也略显得有点复杂化。服务器

在ABP核心模块的启动过程当中,会预先初始化这些配置管理类,以下代码所示框架

而后在AddSettingProviders中加入预先定义好的配置类。async

接着在完成初始化过程当中,有配置定义类统一根据这些配置对象,进行定义的初始化,这样才能在系统中进行使用。ide

配置定义的管理类接口,能够用下面这个图示进行说明。函数

以上就是在ABP框架中,基于配置模块的管理过程。

通常状况下,若是咱们须要在Web API端中对这些接口进行调用管理,如对用户或者系统Email配置信息的获取和修改,那么咱们须要定义一个配置接口服务(默认下载的ABP框架中没有公布这个接口定义和实现)。

以下咱们定义一个SettingsAppService和他的接口

而后咱们能够实现它的获取信息和修改信息的接口,以下所示是对系统级别的邮件参数进行配置管理。

        /// <summary>
        /// 获取应用程序级别的邮件配置(系统邮件配置)
        /// </summary>
        /// <returns></returns>
        public async Task<EmailSettingsEditDto> GetEmailSettingsForApplication()
        {
            var smtpPassword = await SettingManager.GetSettingValueForApplicationAsync(EmailSettingNames.Smtp.Password);

            return new EmailSettingsEditDto
            {
                DefaultFromAddress = await SettingManager.GetSettingValueForApplicationAsync(EmailSettingNames.DefaultFromAddress),
                DefaultFromDisplayName = await SettingManager.GetSettingValueForApplicationAsync(EmailSettingNames.DefaultFromDisplayName),
                SmtpHost = await SettingManager.GetSettingValueForApplicationAsync(EmailSettingNames.Smtp.Host),
                SmtpPort = await SettingManager.GetSettingValueForApplicationAsync<int>(EmailSettingNames.Smtp.Port),
                SmtpUserName = await SettingManager.GetSettingValueForApplicationAsync(EmailSettingNames.Smtp.UserName),
                SmtpPassword = SimpleStringCipher.Instance.Decrypt(smtpPassword),
                SmtpDomain = await SettingManager.GetSettingValueForApplicationAsync(EmailSettingNames.Smtp.Domain),
                SmtpEnableSsl = await SettingManager.GetSettingValueForApplicationAsync<bool>(EmailSettingNames.Smtp.EnableSsl),
                SmtpUseDefaultCredentials = await SettingManager.GetSettingValueForApplicationAsync<bool>(EmailSettingNames.Smtp.UseDefaultCredentials)
            };
        }

        /// <summary>
        /// 更新应用程序级别的邮件配置(系统邮件配置)
        /// </summary>
        /// <returns></returns>
        public async Task UpdateEmailSettingsForApplication(EmailSettingsEditDto input)
        {
            await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.DefaultFromAddress, input.DefaultFromAddress);
            await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.DefaultFromDisplayName, input.DefaultFromDisplayName);
            await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.Host, input.SmtpHost);
            await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.Port, input.SmtpPort.ToString(CultureInfo.InvariantCulture));
            await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.UserName, input.SmtpUserName);
            await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.Password, SimpleStringCipher.Instance.Encrypt(input.SmtpPassword));
            await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.Domain, input.SmtpDomain);
            await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.EnableSsl, input.SmtpEnableSsl.ToString().ToLowerInvariant());
            await SettingManager.ChangeSettingForApplicationAsync(EmailSettingNames.Smtp.UseDefaultCredentials, input.SmtpUseDefaultCredentials.ToString().ToLowerInvariant());
        }

 

二、使用自定义的参数配置管理

我在较早的随笔《Winform开发框架之参数配置管理功能实现-基于SettingsProvider.net的构建》中介绍过对配置信息的管理实现,这种配置参数方式一直很好的应用在个人各个框架上,定义和使用都相对比较简单,可以知足绝大多数的应用场景,相对ABP框架的配置模块来讲,简单易用。

首先咱们定义一个用来存储通用配置信息的表,以下所示。

这个配置表的主要特色也是以键为操做对象,而后内容是JSON序列化后的内容,能够存储用户自定义的类的序列号字符串,这个是它的灵魂所在。和ABP框架仅仅存储简单类型的值有所不一样。

和其余模块的定义同样,咱们能够先根据常规表的方式,使用代码快速生成类的结构,以下所示。

    /// <summary>
    /// 用户参数配置,应用层服务接口实现
    /// </summary>
    [AbpAuthorize]
    public class UserParameterAppService : MyAsyncServiceBase<UserParameter, UserParameterDto, string, UserParameterPagedDto, CreateUserParameterDto, UserParameterDto>, IUserParameterAppService
    {
        private readonly IRepository<UserParameter, string> _repository;

        public UserParameterAppService(IRepository<UserParameter, string> repository) : base(repository)
        {
            _repository = repository;
        }

而后定义几个用于用户级别和系统程序级别的接口实现,如获取信息,修改信息等。

而后,在生成的Caller层类里面,增长以上的Web API接口调用的实现代码,以下所示

 

    /// <summary>
    /// 用户参数配置的Web API调用处理
    /// </summary>
    public class UserParameterApiCaller : AsyncCrudApiCaller<UserParameterDto, string, UserParameterPagedDto, CreateUserParameterDto, UserParameterDto>, IUserParameterAppService
    {
        /// <summary>
        /// 提供单件对象使用
        /// </summary>
        public static UserParameterApiCaller Instance
        {
            get
            {
                return Singleton<UserParameterApiCaller>.Instance;
            }
        }

        /// <summary>
        /// 默认构造函数
        /// </summary>
        public UserParameterApiCaller()
        {
            this.DomainName = "UserParameter";//指定域对象名称,用于组装接口地址
        }

        public async Task<UserParameterDto> GetSettingForUser(NameInputDto input)
        {
            return await DoActionAsync<UserParameterDto>(MethodBase.GetCurrentMethod(), input);
        }

        public async Task ChangeSettingForUser(NameValueDto input)
        {
            await DoActionAsync(MethodBase.GetCurrentMethod(), input);
        }

        public async Task<UserParameterDto> GetSettingForApplication(NameInputDto input)
        {
            return await DoActionAsync<UserParameterDto>(MethodBase.GetCurrentMethod(), input);
        }

        public async Task ChangeSettingForApplication(NameValueDto input)
        {
            await DoActionAsync(MethodBase.GetCurrentMethod(), input);
        }
    }

若是对于上面的DoActionAsyn的处理有疑问,能够参考以前随笔《ABP开发框架先后端开发系列---(10)Web API调用类的简化处理》进行了解。

我在以前介绍过的配置模块里面,结合过FireFoxDialog界面效果,实现较好的参数配置管理功能,以下界面所示。

 咱们本次使用这两个不一样的配置模块,也但愿使用这个来展示一下,以便更好的理解。

因为整合了SettingsProvider.net组件,咱们只须要封装一下对数据库的存储获取方式就能够了。

    /// <summary>
    /// 数据库参数存储设置
    /// </summary>
    public class DatabaseStorage : JsonSettingsStoreBase
    {
        /// <summary>
        /// 配置级别
        /// </summary>
        public SettingScopes Scope { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public DatabaseStorage()
        {
            this.Scope = SettingScopes.User;
        }

        /// <summary>
        /// 参数构造函数
        /// </summary>
        /// <param name="scope">配置级别</param>
        public DatabaseStorage(SettingScopes scope)
        {
            this.Scope = scope;
        }

        /// <summary>
        /// 保存到数据库
        /// </summary>
        /// <param name="filename">文件名称(类型名称)</param>
        /// <param name="fileContents">参数内容</param>
        protected override void WriteTextFile(string filename, string fileContents)
        {
            var info = new NameValueDto(filename, fileContents);
            if (this.Scope == SettingScopes.Application)
            {
                AsyncContext.Run(()=> UserParameterApiCaller.Instance.ChangeSettingForApplication(info));
            }
            else
            {
                AsyncContext.Run(() => UserParameterApiCaller.Instance.ChangeSettingForUser(info));
            }
        }

        /// <summary>
        /// 从数据库读取
        /// </summary>
        /// <param name="filename">文件名称(类型名称)</param>
        /// <returns></returns>
        protected override string ReadTextFile(string filename)
        {
            var info = new NameInputDto(filename);

            UserParameterDto result = null;
            if (this.Scope == SettingScopes.Application)
            {
                result = AsyncContext.Run(() => UserParameterApiCaller.Instance.GetSettingForApplication(info));
            }
            else
            {
                result = AsyncContext.Run(() => UserParameterApiCaller.Instance.GetSettingForUser(info));
            }

            return result != null ? result.Content : null;
        }
    }

有了这个实现,这样在操做上,就不用管理这些内容如何获取和更新了,和以前的使用配置管理方式一致了。能够处理各类不一样的配置对象信息。

先来看看默认ABP的配置处理方式,管理界面以下所示。

这里的配置存储咋ABP的AbpSettings表里面,以下所示,每项内容是以字符串方式独立存储的。

它的调用主要就是SettingsApiCaller的内容了,注意这个邮件配置,必须在EmailSettingProvider中提早定义好对象的信息。

        private EmailSettingsEditDto GetParameter()
        {
            EmailSettingsEditDto param =  AsyncContext.Run(() => SettingsApiCaller.Instance.GetEmailSettingsForApplication());
            if(param == null)
            {
                param = new EmailSettingsEditDto();
            }
            return param;
        }

        public override void OnInit()
        {
            var parameter = GetParameter();
            if (parameter != null)
            {
                this.txtEmail.Text = parameter.DefaultFromAddress;
                this.txtLoginId.Text = parameter.SmtpUserName;
                this.txtPassword.Text = parameter.SmtpPassword;
                this.txtPassword.Tag = parameter.SmtpPassword;
                this.txtSmtpPort.Value = parameter.SmtpPort;
                this.txtSmtpServer.Text = parameter.SmtpHost;
                this.txtUseSSL.Checked = parameter.SmtpEnableSsl;
            }
        }

下面咱们再来看看自定义的配置管理方式。以下是自定义配置模块获取显示的内容。

这个配置是系统级别的,它的获取方式以下所示。

    public partial class PageEmailApplication : PropertyPage
    {
        private SettingsProvider settings;
        private ISettingsStorage store;

        public PageEmailApplication()
        {
            InitializeComponent();

            if (!this.DesignMode)
            {
                store = new DatabaseStorage(SettingScopes.Application);
                settings = new SettingsProvider(store);
            }
        }

        public override void OnInit()
        {
            EmailParameter parameter = settings.GetSettings<EmailParameter>();
            if (parameter != null)
            {
                this.txtEmail.Text = parameter.Email;
                this.txtLoginId.Text = parameter.LoginId;
                this.txtPassword.Text = parameter.Password;
                this.txtPassword.Tag = parameter.Password;
                this.txtPop3Port.Value = parameter.Pop3Port;
                this.txtPop3Server.Text = parameter.Pop3Server;
                this.txtSmtpPort.Value = parameter.SmtpPort;
                this.txtSmtpServer.Text = parameter.SmtpServer;
                this.txtUseSSL.Checked = parameter.UseSSL;
            }
        }

以上是标准的SettingsProvider.net的组件调用方式,咱们不用知道具体的数据存储,只须要把内容直接GetSetting方式获取出来便可。

而保存内容,直接经过使用SaveSettings保存便可。

                EmailParameter parameter = settings.GetSettings<EmailParameter>();
                if (parameter != null)
                {                    
                    parameter.Email = this.txtEmail.Text;
                    parameter.LoginId = this.txtLoginId.Text;
                    parameter.Password = this.txtPassword.Text;
                    parameter.Pop3Port = Convert.ToInt32(this.txtPop3Port.Value);
                    parameter.Pop3Server = this.txtPop3Server.Text;
                    parameter.SmtpPort = Convert.ToInt32(this.txtSmtpPort.Value);
                    parameter.SmtpServer = this.txtSmtpServer.Text;
                    parameter.UseSSL = this.txtUseSSL.Checked;

                    settings.SaveSettings<EmailParameter>(parameter);
                }

其中 EmailParameter 类是咱们定义的一个类,用来承载相关的配置信息,以下所示。它支持默认值,加密处理等设置。

    /// <summary>
    /// 邮箱设置
    /// </summary>
    public class EmailParameter
    {
        /// <summary>
        /// 邮件帐号
        /// </summary>
        //[DefaultValue("wuhuacong@163.com")]
        public string Email { get; set; }

        /// <summary>
        /// POP3服务器
        /// </summary>
        [DefaultValue("pop.163.com")]
        public string Pop3Server { get; set; }

        /// <summary>
        /// POP3端口
        /// </summary>
        [DefaultValue(110)]
        public int Pop3Port { get; set; }

        /// <summary>
        /// SMTP服务器
        /// </summary>
        [DefaultValue("smtp.163.com")]
        public string SmtpServer { get; set; }

        /// <summary>
        /// SMTP端口
        /// </summary>
        [DefaultValue(25)]
        public int SmtpPort { get; set; }

        /// <summary>
        /// 登录帐号
        /// </summary>
        public string LoginId { get; set; }

        /// <summary>
        /// 登录密码
        /// </summary>
        [ProtectedString]
        public string Password { get; set; }

        /// <summary>
        /// 使用SSL加密
        /// </summary>
        [DefaultValue(false)]
        public bool UseSSL { get; set; }
    }

 

因为SettingsProvider.net组件的支持,咱们还能够把配置信息当成本地文件存储起来,对于一些须要存为文件的方式的配置,很是不错。

    public partial class PageReport : PropertyPage
    {
        private SettingsProvider settings;
        private ISettingsStorage store;

        public PageReport()
        {
            InitializeComponent();

            if (!this.DesignMode)
            {
                // PortableStorage: 在运行程序目录建立一个setting的文件记录参数数据
                store = new PortableStorage();
                settings = new SettingsProvider(store);
            }
        }

以上就是介绍了ABP配置管理模块的实现原理和客户端的调用,以及使用自定义配置管理模块的方式进行处理更加动态化或者灵活一点的配置信息,使用自定义配置信息管理服务,整合了SettingProvider.net的支持,能够实现更好的参数配置管理体验。 

相关文章
相关标签/搜索