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

1、ABP框架的配置管理

如下面是邮件配置信息,配置信息一般先继承自SettingProvider,初始化定义后,才能被系统所使用。

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

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

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

不过从上面的图示我们也可以看到,整个配置模块由于引入这些内容,导致处理起来必须按部就班的创建配置管理类,定义配置信息,重新编译系统后,然后才能进行信息的调用,因此这些配置信息必须预定义。而且管理起来协同这些类的处理,也略显得有点复杂化。

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

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

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

配置定义的管理类接口,可以用下面这个图示进行说明。

以上就是在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());
}

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

我在较早的随笔《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()]
public int Pop3Port { get; set; } /// <summary>
/// SMTP服务器
/// </summary>
[DefaultValue("smtp.163.com")]
public string SmtpServer { get; set; } /// <summary>
/// SMTP端口
/// </summary>
[DefaultValue()]
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的支持,可以实现更好的参数配置管理体验。

ABP开发框架前后端开发系列---(12)配置模块的管理的更多相关文章

  1. ABP开发框架前后端开发系列---(14)基于Winform的ABP快速开发框架

    前面介绍了很多ABP系列的文章,一步一步的把我们日常开发中涉及到的Web API服务构建.登录日志和操作审计日志.字典管理模块.省份城市的信息维护.权限管理模块中的组织机构.用户.角色.权限.菜单等内 ...

  2. ABP开发框架前后端开发系列---(2)框架的初步介绍

    在前面随笔<ABP开发框架前后端开发系列---(1)框架的总体介绍>大概介绍了这个ABP框架的主要特点,以及介绍了我对这框架的Web API应用优先的一些看法,本篇继续探讨ABP框架的初步 ...

  3. ABP开发框架前后端开发系列---(4)Web API调用类的封装和使用

    在前面随笔介绍ABP应用框架的项目组织情况,以及项目中领域层各个类代码组织,以及简化了ABP框架的各个层的内容,使得我们项目结构更加清晰.上篇随笔已经介绍了字典模块中应用服务层接口的实现情况,并且通过 ...

  4. ABP开发框架前后端开发系列---(11)菜单的动态管理

    在前面随笔<ABP开发框架前后端开发系列---(9)ABP框架的权限控制管理>中介绍了基于ABP框架服务构建的Winform客户端,客户端通过Web API调用的方式进行获取数据,从而实现 ...

  5. ABP开发框架前后端开发系列---(9)ABP框架的权限控制管理

    在前面两篇随笔<ABP开发框架前后端开发系列---(7)系统审计日志和登录日志的管理>和<ABP开发框架前后端开发系列---(8)ABP框架之Winform界面的开发过程>开始 ...

  6. ABP开发框架前后端开发系列---(8)ABP框架之Winform界面的开发过程

    在前面随笔介绍的<ABP开发框架前后端开发系列---(7)系统审计日志和登录日志的管理>里面,介绍了如何改进和完善审计日志和登录日志的应用服务端和Winform客户端,由于篇幅限制,没有进 ...

  7. ABP开发框架前后端开发系列---(3)框架的分层和文件组织

    在前面随笔<ABP开发框架前后端开发系列---(2)框架的初步介绍>中,我介绍了ABP应用框架的项目组织情况,以及项目中领域层各个类代码组织,以便基于数据库应用的简化处理.本篇随笔进一步对 ...

  8. ABP开发框架前后端开发系列---(10)Web API调用类的简化处理

    在较早期的随笔<ABP开发框架前后端开发系列---(5)Web API调用类在Winform项目中的使用>已经介绍了Web API调用类的封装处理,虽然这些调用类我们可以使用代码生成工具快 ...

  9. ABP开发框架前后端开发系列---(5)Web API调用类在Winform项目中的使用

    在前面几篇随笔介绍了我对ABP框架的改造,包括对ABP总体的介绍,以及对各个业务分层的简化,Web API 客户端封装层的设计,使得我们基于ABP框架的整体方案越来越清晰化, 也越来越接近实际的项目开 ...

随机推荐

  1. WPF 曲线图表控件(自制)(一)

    原文:WPF 曲线图表控件(自制)(一) 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/koloumi/article/details/775092 ...

  2. WPF 实现跑马灯效果的Label控件,数据绑定方式实现

    原文:WPF 实现跑马灯效果的Label控件,数据绑定方式实现 项目中需要使用数据绑定的方式实现跑马灯效果的Label,故重构了Label控件:具体代码如下 using System; using S ...

  3. NFC学习一个记录

    用电子钱包等似提出要求,最近几年NFC(near field communication 近场通信)我们开始慢慢普及.因为需要工作,今天是学习NFC相关知识,第一NFC一些基本列表的什么,做好记录. ...

  4. python 教程 第二十二章、 其它应用

    第二十二章. 其它应用 1)    Web服务 ##代码 s 000063.SZ ##开盘 o 26.60 ##最高 h 27.05 ##最低 g 26.52 ##最新 l1 26.66 ##涨跌 c ...

  5. wpf Storyboard 不存在可解析名称“ ”的适用名称领域 No applicable name scope exists to resolve the name

    原文:wpf Storyboard 不存在可解析名称“ ”的适用名称领域 No applicable name scope exists to resolve the name 写了一个 Storyb ...

  6. UWP 应用中的Back button(TitleBar) 的处理

    后退按钮是一项系统提供的 UI 提示,可以在后退堆栈或用户导航历史记录中支持向后导航. 用起来其实也是很简单的,只需要在App.xaml.cs 中修改(添加)如下红色代码,便可实现.. sealed ...

  7. swagger ui 值类型形参加文字注释

    例: @ApiImplicitParams({ @ApiImplicitParam(paramType = "query", name = "indexCondition ...

  8. [转]更改ejs模板后缀.ejs为.html

    三种写法 1,express老写法,3.*已经不支持 app.register('.html', require('ejs')); app.set('view engine', 'ejs'); 2, ...

  9. 自定义函数Function

    定义 对于SQL Server来讲,我们声明一个变量的方式是用@变量名,而且相对于编程来讲,SQL Server声明的方式跟我们开了个玩笑,是先变量后面才是类型.对于需要传参跟不需要传参的方式,其实跟 ...

  10. 多线程Parallel和Task

    不管是Parallel还是Task,最里面都是线程池(里面是线程)当开启多个任务后,系统会根据当前的线程池的资源进行分配,任务则进行等待Parallel可以对系统的CPU进行设置,可以最大程度上榨干系 ...