ABP開發框架前後端開發系列---(12)配置模塊的管理

来源:https://www.cnblogs.com/wuhuacong/archive/2019/07/01/11113040.html
-Advertisement-
Play Games

一般來說,一個系統或多或少都會涉及到一些系統參數或者用戶信息的配置,而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的支持,可以實現更好的參數配置管理體驗。 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一 概要 二進位序列化是公司內部自研微服務框架的主要的數據傳輸處理方式,但是普通的開發人員對於二進位的學習和瞭解並不深入,容易導致使用過程中出現了問題卻沒有分析解決的思路。本文從一次生產環境的事故引入這個話題,通過對於事故的分析過程,探討了平時沒有關註到的一些技術要點。二進位序列化結果並不像Json ...
  • using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.Threading; using System.Windows.Forms; using System; namespace Conso... ...
  • surging 微服務引擎從2017年6月至今已經有兩年的時間,這兩年時間有多家公司使用surging 服務引擎,並且有公司搭建了CI/CD,並且使用了k8s 集群,這裡我可以說下幾家公司的服務搭建情況,公司名不便透露,我們就以字母標識 A公司:40多個服務提供者,一個服務提供者擴展了四五個實例節點 ...
  • 前言: 看到一個名詞:搜商(SQ),還挺有趣。講的是在互聯網時代,怎麼能夠快速找到自己所需信息或資源,成為一種能力,並將其提升到類似智商、情商的概念。在以後工作過程中,儘量提高自己獲取、辨別、處理信息的能力,提高競爭力,成為高SQ的人。 官方文檔的重要性 搜索一下,各種資料文檔就以既定的演算法給展現出 ...
  • 小白開學Asp.Net Core《三》 ——界面 我胡漢三再次又回來了(距離上篇時間有點長),今天抽時間將最近對框架採用的後臺界面做個記錄 1、先上圖 (圖一) (圖二) 2、界面說明 後臺採用X-Admin2.2、layui 3、圖二使用了Layui Table的模塊 (對於我一個不太懂前端的人來 ...
  • Join和GroupJoin的區別 Join 官方釋義:基於匹配鍵對兩個序列的元素進行關聯。使用預設的相等比較器對鍵進行比較。 這個與資料庫中的INNER JOIN很類似,就是使用一個鍵(TKey)將兩個集合關聯起來,並對這兩個集合的元素進行選擇,作為結果輸出。 GroupJoin 官方釋義: 基於 ...
  • 前面三章已經把MVC啟動過程以及源代碼做了講解,本章開始正式MVC,mvc全稱叫model view controller,也就是把表現層又細分三層,官網的圖片描述: 預設創建了一個.net core web 項目,把Startup類中的代碼改成下麵這樣 我們.net core mvc是基於約定的一 ...
  • 1.冒泡排序(o(n2)) 這個演算法的名字由來是因為越大的元素會經由交換慢慢“浮”到數列的頂端(升序或降序排列),就如同碳酸飲料中二氧化碳的氣泡最終會上浮到頂端一樣,故名“冒泡排序”。 冒泡排序過程分析:把最大的放到最後 有哨兵和沒有哨兵的運行結果分析,並不是每次有哨兵的都小於沒有哨兵的,相反有哨兵 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...