一般來說,一個系統或多或少都會涉及到一些系統參數或者用戶信息的配置,而ABP框架也提供了一套配置信息的管理模塊,ABP框架的配置信息,必須提前定義好配置的各項內容,然後才能在系統中初始化或者通過介面查詢來使用,本篇隨筆引入了另外一種配置信息的定義,實現更加簡化的處理,本篇隨筆著重介紹兩者之間的差異和... ...
一般來說,一個系統或多或少都會涉及到一些系統參數或者用戶信息的配置,而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("[email protected]")] 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的支持,可以實現更好的參數配置管理體驗。