ABP开发框架前后端开发系列---(12)配置模块的管理
一般来说,一个系统或多或少都会涉及到一些系统参数或者用户信息的配置,而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)配置模块的管理的更多相关文章
- ABP开发框架前后端开发系列---(14)基于Winform的ABP快速开发框架
前面介绍了很多ABP系列的文章,一步一步的把我们日常开发中涉及到的Web API服务构建.登录日志和操作审计日志.字典管理模块.省份城市的信息维护.权限管理模块中的组织机构.用户.角色.权限.菜单等内 ...
- ABP开发框架前后端开发系列---(2)框架的初步介绍
在前面随笔<ABP开发框架前后端开发系列---(1)框架的总体介绍>大概介绍了这个ABP框架的主要特点,以及介绍了我对这框架的Web API应用优先的一些看法,本篇继续探讨ABP框架的初步 ...
- ABP开发框架前后端开发系列---(4)Web API调用类的封装和使用
在前面随笔介绍ABP应用框架的项目组织情况,以及项目中领域层各个类代码组织,以及简化了ABP框架的各个层的内容,使得我们项目结构更加清晰.上篇随笔已经介绍了字典模块中应用服务层接口的实现情况,并且通过 ...
- ABP开发框架前后端开发系列---(11)菜单的动态管理
在前面随笔<ABP开发框架前后端开发系列---(9)ABP框架的权限控制管理>中介绍了基于ABP框架服务构建的Winform客户端,客户端通过Web API调用的方式进行获取数据,从而实现 ...
- ABP开发框架前后端开发系列---(9)ABP框架的权限控制管理
在前面两篇随笔<ABP开发框架前后端开发系列---(7)系统审计日志和登录日志的管理>和<ABP开发框架前后端开发系列---(8)ABP框架之Winform界面的开发过程>开始 ...
- ABP开发框架前后端开发系列---(8)ABP框架之Winform界面的开发过程
在前面随笔介绍的<ABP开发框架前后端开发系列---(7)系统审计日志和登录日志的管理>里面,介绍了如何改进和完善审计日志和登录日志的应用服务端和Winform客户端,由于篇幅限制,没有进 ...
- ABP开发框架前后端开发系列---(3)框架的分层和文件组织
在前面随笔<ABP开发框架前后端开发系列---(2)框架的初步介绍>中,我介绍了ABP应用框架的项目组织情况,以及项目中领域层各个类代码组织,以便基于数据库应用的简化处理.本篇随笔进一步对 ...
- ABP开发框架前后端开发系列---(10)Web API调用类的简化处理
在较早期的随笔<ABP开发框架前后端开发系列---(5)Web API调用类在Winform项目中的使用>已经介绍了Web API调用类的封装处理,虽然这些调用类我们可以使用代码生成工具快 ...
- ABP开发框架前后端开发系列---(5)Web API调用类在Winform项目中的使用
在前面几篇随笔介绍了我对ABP框架的改造,包括对ABP总体的介绍,以及对各个业务分层的简化,Web API 客户端封装层的设计,使得我们基于ABP框架的整体方案越来越清晰化, 也越来越接近实际的项目开 ...
随机推荐
- 设置npm淘宝镜像
npm config set registry https://registry.npm.taobao.org
- 在WPF窗体中重绘
原文:在WPF窗体中重绘 写这篇主要是为了验证任何元素自身都具备绘图功能. 在默认Window中重写OnRender方法 protected override void OnRender(Draw ...
- 扪心自问,强大的UI框架,给我们带来了什么?(作者因此写了一个GuiLite)
MFC, QT, MINIGUI, ANDROID, IOS,如果这些平台,你都使用过,在下真心佩服,也相信你对这篇文章最具有发言权,真心期待你的回复和建议. 这些著名的UI说出来都让人如雷贯耳,如果 ...
- Linux性能测试 netstat命令
功能说明:Netstat用于显示与IP.TCP.UDP和ICMP协议相关的统计数据,一般用于检验本机各端口的网络连接情况.语 法:netstat [-acCeFghilMnNoprstuvVwx][- ...
- WPF与缓动(四) 弧形缓动
原文:WPF与缓动(四) 弧形缓动 WPF与缓动(四) 弧形缓动 ...
- 微信nodejs开发模块指南
1.微信消息处理 node-weixin-message wechat 2.微信加密 node-weixin-crypto wechat-crypto 3.微信支付 node-weixin-pay w ...
- Java之java.lang.IllegalMonitorStateException
今天又中彩了, 原本很简单的多线程程序, 蓦然间冒了个"java.lang.IllegalMonitorStateException" , 杀了个措手不及. 一直纳闷, 为什么为什 ...
- WPF特效-鱼游动动画2
原文:WPF特效-鱼游动动画2 纯代码撸动画实践2: 原图:(png格式) ...
- MultiBinding
<StackPanel> <Slider x:Name="sl1" Minimum="10" Maximum="100"/ ...
- 日志文件 清理or压缩
1.操作前请断开所有数据库连接. 2.分离数据库 分离数据库:企业管理器->服务器->数据库->cwbase1->右键->分离数据库 分离后,cwbase1数据库被删除, ...