程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 使用MEF實現通用參數設置,mef通用參數設置

使用MEF實現通用參數設置,mef通用參數設置

編輯:C#入門知識

使用MEF實現通用參數設置,mef通用參數設置


  通用後台管理系統必備功能模塊包含日志管理,權限管理,數據字典,參數配置等功能。參數設置主要用於設置系統運行所需的一些基礎性配置項,比如redis緩存,mq消息隊列,系統版本等信息。好的參數設置需要達到以下幾點1.使用簡單  2.功能強大,方便拓展 3.界面美觀。本篇將帶你實現通用參數設置,在閱讀之前你需要了解的知識,ASP.NET MVC,Entity Framework,MEF。在線預覽地址:http://config.myscloud.cn

閱讀目錄

  • 添加配置項及使用
  • 實現思路
  • 關鍵代碼解析
  • 總結
回到頂部

添加配置項及使用

 為了驗證系統實現了這幾個目標1.使用簡單  2.功能強大,方便拓展 3.界面美觀,這裡先通過實例來演示如何添加配置項以及怎麼使用該配置項。

  1.添加配置項組

  只需添加一個繼承於ConfigOption抽象類的類,這裡我們稱繼承於ConfigOption的類為配置項組

    /// <summary>
    /// 測試配置信息
    /// </summary>
    [Export(typeof(ConfigOption))]

    [ConfigType(Group = "TestConfig", GroupCn = "測試配置項", ImmediateUpdate = true)]
    public class TestConfig : ConfigOption
    {
        /// <summary>
        /// 是否記錄執行SQL
        /// </summary>
        [Config(Name = "記錄執行SQL", DefaultValue = false)]
        public static bool IfLogSQL { get; set; }
    }
  注意點:繼承ConfigOption抽象類,添加ConfigTypeAttribute屬性描述(Group:分組  GroupCn:分組名稱,用於顯示在界面)     2.添加配置項   配置項組裡面的每個靜態屬性稱為配置項
  /// <summary>
  /// 是否記錄執行SQL
  /// </summary>
  [Config(Name = "記錄執行SQL", DefaultValue = false)]
  public static bool IfLogSQL { get; set; }
  注意點:ConfigAttribute屬性描述中 Name:對應配置項中文說明  DefaultValue:默認值  ConfigValueType:bool類型會顯示成單選radio,更多設置可參考ConfigAttribute類         3.可選步驟  實現個性化業務   
  /// <summary>
  /// 保存前校驗
  /// </summary>
  /// <param name="value"></param>
  /// <returns>bool</returns>
  public override bool BeforeSave(OptionViewModel value)
  {
    foreach(var item in value.ListOptions)
    {
      switch (item.Key)
      {
        case "IfLogSQL":
                if (string.IsNullOrEmpty(item.Value))
                {
                    return false;
                 }
                 break;
        default:
           break;
      }
    }
    return base.BeforeSave(value);
  }

     public override void AfterSave(List<Options> ListOptions)   {   foreach (Options item in ListOptions)   {       switch (item.Key)       {         case "IfLogSQL":           //開啟或者關閉EF日志記錄           bool curValue = Convert.ToBoolean(item.Value);           if (curValue != TestConfig.IfLogSQL)           {             //EfLogConfig.ManagerEFLog(curValue);           }           break;         default:           break;       }     }   }

  



  使用BeforeSave和AfterSave方法可以實現個性化業務     

4.參數使用

        public ActionResult Index()
        {
            ViewBag.Title = SystemConfig.SystemTitle;
            return View();
        }    

   由於定義的是靜態屬性,所以可以直接使用

  小結:只需通過添加配置項類,無需修改其它東西,所需的保存邏輯和界面都已經完成。這裡留個疑問,我是如何知道前台界面渲染的時候該用radio,text,password中哪種控件的呢? 回到頂部

實現思路

 通用配置管理達到以下目標

   1.使用簡單

     通過添加配置項類,無需額外操作即可完成工作

   2.功能強大,方便拓展

    界面等其它工作都已經由框架完成,對於個性化的配置比如需要實現校驗,或者額外工作,可以通過beforesave,aftersave進行拓展

   3.界面美觀

   基於bootstrap實現,整體效果還是挺不錯的

  

 系統的類圖

系統主流程

  回到頂部

關鍵代碼解析

 1.初始化(Global.asax.cs)

//1.MEF初始化
MefConfig.Init();
//2.EF初始化
EFInitializer.UnSafeInit();
//3.初始化系統參數配置
ConfigManager configManager =MefConfig.TryResolve<ConfigManager>();
configManager.Init();
 MefConfig.Init()               方法初始化組合容器  EFInitializer.UnSafeInit()   Entity Framework數據庫連接和類型初始化  configManager.Init()         讀取所有配置項 從數據庫讀取所有配置項值進行賦值    2.關鍵類ConfigManager
  /// <summary>
  /// 系統所有配置信息
  /// </summary>
  [ImportMany(typeof(ConfigOption))]
  public IEnumerable<ConfigOption> AllConfig
  {
    get
    {
      return _allConfig;
    }
    set
    {
      if (_allConfig == null)
      {
         _allConfig = value;
      }
    }
  }
 通過MEF導入器讀取所有配置項組,存儲在靜態變量 _allConfig 中
      /// <summary>
        /// 初始化系統參數配置信息
        /// </summary>
        public void Init()
        {
            //所有選項值
            List<Options> listOption = ConfigService.GetAllOptions();

            ConfigDescription desc = null;
            //代碼現有配置項
            foreach (ConfigOption item in AllConfig)
            {
                //反射讀取配置項ConfigTypeAttribute  ConfigAttribute 信息
                desc = ConfigDescriptionCache.GetTypeDiscription(item.GetType());

                //設置當前配置項的GroupType
                desc.GroupTypePropertyInfo.SetValue(item, Convert.ChangeType(desc.Group, desc.GroupTypePropertyInfo.PropertyType), null);

                //每項值信息
                List<Options> itemOptions = listOption.Where(e => e.OptionType.Equals(desc.Group, StringComparison.OrdinalIgnoreCase)).ToList();
                Options op = null;
                ConfigAttribute ca = null;
                foreach (PropertyInfo prop in desc.StaticPropertyInfo)
                {
                    op = itemOptions.FirstOrDefault(e1 => e1.Key.Equals(prop.Name, StringComparison.OrdinalIgnoreCase));
                    ca = desc.MemberDict[prop.Name];
                    if (op == null)
                    {
                        //設置默認值
                        prop.SetValue(null, Convert.ChangeType(ca.DefaultValue, prop.PropertyType), null);
                    }
                    else
                    {
                        prop.SetValue(null, Convert.ChangeType(op.Value, prop.PropertyType), null);
                    }
                }
            }
        }

 ConfigService.GetAllOptions()從數據庫中讀取所有選項值,通過ConfigDescriptionCache.GetTypeDiscription(item.GetType())反射讀取所有靜態屬性的相關值

屬性類型和前台控件映射關系

        /// <summary>
        /// 設置默認項數值類型-根據屬性類型進行轉換
        /// </summary>
        /// <param name="configAttr"></param>
        /// <param name="propertyType">屬性類型</param>
        private static void SetConfigValueType(ConfigAttribute configAttr,Type propertyType)
        {
            switch (propertyType.ToString()) {
                case "System.String":
                    configAttr.ValueType = ConfigValueType.String; //文本框
                    break;
                case "System.Boolean":
                    configAttr.ValueType = ConfigValueType.Bool;  //對應前台 radio
                    break;
                case "System.Int32":
                case "System.Double":
                    configAttr.ValueType = ConfigValueType.Number; //對應數值輸入框
                    break;
                default:
                    configAttr.ValueType = ConfigValueType.String;
                    break;
            }
        }

 密碼類型的可以自行進行指定

        /// <summary>
        /// MQ連接密碼
        /// </summary>
        [Config(Name = "密碼", ValueType = ConfigValueType.Password)]
        public static string Password { get; set; }

 提供的獲取配置項的接口

        /// <summary>
        /// 獲取所有配置信息
        /// </summary>
        /// <returns>所有配置信息</returns>
        public List<OptionViewModel> GetAllOption(string GroupType = "")
        /// <summary>
        /// 獲取指定項配置信息
        /// </summary>
        /// <param name="GroupType">分組項</param>
        /// <returns>所有配置信息</returns>
        public OptionViewModel GetOptionByGroup(string GroupType)
        /// <summary>
        /// 獲取指定項配置信息
        /// </summary>
        /// <param name="GroupType">分組項</param>
        /// <returns>所有配置信息</returns>
        public Options GetOptionByGroupAndKey(string GroupType, string key){}

保存方法實現

        /// <summary>
        /// 保存配置信息
        /// </summary>
        /// <param name="value">配置信息</param>
        public ApiResult<string> Save(OptionViewModel value)
        {
            ApiResult<string> result = new ApiResult<string>();
            result.HasError = true;
            string GroupType = value.Group.GroupType;
            if (value.Group == null || string.IsNullOrEmpty(GroupType) || value.ListOptions == null)
            {
                result.Message = "保存參數配置時發生參數空異常";
                return result;
            }
            //調用保存前處理事件
            ConfigOption curConfigOption = AllConfig.FirstOrDefault(e => e.GroupType.Equals(GroupType, StringComparison.OrdinalIgnoreCase));
            if (curConfigOption == null)
            {
                //如果沒有找到匹配項
                result.Message = string.Format("當前保存配置信息{0}不對應後台的任務配置類", GroupType);
                return result;
            }
       //調用配置項的保存前校驗事件 if (!curConfigOption.BeforeSave(value)) { result.Message = "當前配置項不允許保存"; return result; } //保存數據 try { using (CommonDbContext cdb = new CommonDbContext()) { var dbSet = cdb.Set<Options>(); var delObjs=dbSet.Where(e => e.OptionType == GroupType).ToList(); //刪除原有數據 foreach (var item in delObjs) { cdb.Entry(item).State = EntityState.Deleted; } //保存數據 foreach (var item in value.ListOptions) { item.OptionId = Guid.NewGuid().ToString("N"); } dbSet.AddRange(value.ListOptions); cdb.SaveChanges(); } } catch (Exception ex) { result.Message = ex.Message; return result; } //對當前配置項進行賦值 SetValue(curConfigOption, value.ListOptions); result.HasError = false; return result; } /// <summary> /// 保存時 對當前配置項進行賦值 /// </summary> /// <param name="item">當前配置項</param> /// <param name="ListOptions">配置項值</param> public void SetValue(ConfigOption item, List<Options> ListOptions) { //調用保存後處理事件 item.AfterSave(ListOptions); var desc = ConfigDescriptionCache.GetTypeDiscription(item.GetType()); Options option = null; foreach (PropertyInfo prop in desc.StaticPropertyInfo) { option = ListOptions.First(e => e.Key.Equals(prop.Name, StringComparison.OrdinalIgnoreCase)); if (option == null) { //不存在該配置項,則清空當前值 prop.SetValue(null, Convert.ChangeType(null, prop.PropertyType), null); } else { prop.SetValue(null, Convert.ChangeType(option.Value, prop.PropertyType), null); } } }
 前台渲染邏輯(config.js)
   //初始化數據
    initData = function () {
        $.ajax({
            type: "get",
            url: "/Config/GetAllOption",  //調用後台獲取所有配置項接口
            dataType: "json",
            beforeSend: function () {
                //加載等待層
                index = layer.load(0);
            },
            complete: function () {
                layer.close(index);
            },
            success: function (data) {
                BaseData = data;
                drawConfig(BaseData);  //繪制界面
            }
        });
    }

 

回到頂部

總結

      該參數配置可以很簡單的移植到自己系統裡面,在TaskManagerV2.0這邊博客中使用的參數配置功能就是直接移植的該系統的代碼。另外使用的時候記得修改Web.config中的數據庫連接字符串,本篇寫到這裡就完結了,在介紹一下與文章無關的內容。我在博客上添加的打賞功能,分別位於公告和文章結尾處,歡迎資助我持續寫作!下篇將結合參數配置介紹消息隊列RabbitMQ的使用,敬請期待!

  源代碼下載地址:http://files.cnblogs.com/files/yanweidie/CommonParamConfig.rar,svn源碼地址http://code.taobao.org/svn/commonparamconfig。

 

如果,您認為閱讀這篇博客讓您有些收獲,不妨點擊一下右下角的【推薦】按鈕。
如果,您希望更容易地發現我的新博客,不妨點擊一下綠色通道的【關注我】。

如果,想給予我更多的鼓勵,求打

因為,我的寫作熱情也離不開您的肯定支持。

感謝您的閱讀,如果您對我的博客所講述的內容有興趣,請繼續關注我的後續博客,我是焰尾迭 。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved