博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
使用MEF实现通用参数设置
阅读量:6305 次
发布时间:2019-06-22

本文共 10220 字,大约阅读时间需要 34 分钟。

  通用后台管理系统必备功能模块包含日志管理,权限管理,数据字典,参数配置等功能。参数设置主要用于设置系统运行所需的一些基础性配置项,比如redis缓存,mq消息队列,系统版本等信息。好的参数设置需要达到以下几点1.使用简单  2.功能强大,方便拓展 3.界面美观。本篇将带你实现通用参数设置,在阅读之前你需要了解的知识,ASP.NET MVC,Entity Framework,MEF。在线预览地址:

阅读目录

添加配置项及使用

 为了验证系统实现了这几个目标1.使用简单  2.功能强大,方便拓展 3.界面美观,这里先通过实例来演示如何添加配置项以及怎么使用该配置项。

  1.添加配置项组

  只需添加一个继承于ConfigOption抽象类的类,这里我们称继承于ConfigOption的类为配置项组

///     /// 测试配置信息    ///     [Export(typeof(ConfigOption))]    [ConfigType(Group = "TestConfig", GroupCn = "测试配置项", ImmediateUpdate = true)]    public class TestConfig : ConfigOption    {        ///         /// 是否记录执行SQL        ///         [Config(Name = "记录执行SQL", DefaultValue = false)]        public static bool IfLogSQL { get; set; }    }
  注意点:继承ConfigOption抽象类,添加ConfigTypeAttribute属性描述(Group:分组  GroupCn:分组名称,用于显示在界面)
 
  2.添加配置项
  配置项组里面的每个静态属性称为
配置项
  ///   /// 是否记录执行SQL  ///   [Config(Name = "记录执行SQL", DefaultValue = false)]  public static bool IfLogSQL { get; set; }
  注意点:ConfigAttribute属性描述中 Name:对应配置项中文说明  DefaultValue:默认值  ConfigValueType:bool类型会显示成单选radio,更多设置可参考ConfigAttribute类
  
     3.可选步骤  实现个性化业务
   
  ///   /// 保存前校验  ///   ///   /// 
bool
  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
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.Init();
 MefConfig.Init()               方法初始化组合容器
 EFInitializer.UnSafeInit()   Entity Framework数据库连接和类型初始化
 configManager.Init()         读取所有配置项 从数据库读取所有配置项值进行赋值
 
 2.关键类ConfigManager
  ///   /// 系统所有配置信息  ///   [ImportMany(typeof(ConfigOption))]  public IEnumerable
AllConfig  {    get    {      return _allConfig;    }    set    {      if (_allConfig == null)      {         _allConfig = value;      }    }  }
 通过MEF导入器读取所有配置项组,存储在静态变量 _allConfig 中
      ///         /// 初始化系统参数配置信息        ///         public void Init()        {            //所有选项值            List
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
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())反射读取所有静态属性的相关值

属性类型和前台控件映射关系

///         /// 设置默认项数值类型-根据属性类型进行转换        ///         ///         /// 属性类型        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;            }        }

 密码类型的可以自行进行指定

///         /// MQ连接密码        ///         [Config(Name = "密码", ValueType = ConfigValueType.Password)]        public static string Password { get; set; }

 提供的获取配置项的接口

///         /// 获取所有配置信息        ///         /// 
所有配置信息
public List
GetAllOption(string GroupType = "")
///         /// 获取指定项配置信息        ///         /// 分组项        /// 
所有配置信息
public OptionViewModel GetOptionByGroup(string GroupType)
///         /// 获取指定项配置信息        ///         /// 分组项        /// 
所有配置信息
public Options GetOptionByGroupAndKey(string GroupType, string key){}

保存方法实现

///         /// 保存配置信息        ///         /// 配置信息        public ApiResult
Save(OptionViewModel value) { ApiResult
result = new ApiResult
(); 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
(); 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; } ///
/// 保存时 对当前配置项进行赋值 /// ///
当前配置项 ///
配置项值 public void SetValue(ConfigOption item, List
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);  //绘制界面            }        });    }

 

总结

      该参数配置可以很简单的移植到自己系统里面,在这边博客中使用的参数配置功能就是直接移植的该系统的代码。另外使用的时候记得修改Web.config中的数据库连接字符串,本篇写到这里就完结了,在介绍一下与文章无关的内容。我在博客上添加的打赏功能,分别位于公告和文章结尾处,欢迎资助我持续写作!下篇将结合参数配置介绍消息队列RabbitMQ的使用,敬请期待!

  源代码下载地址:,svn源码地址。

 

转载于:https://www.cnblogs.com/yanweidie/p/5659015.html

你可能感兴趣的文章
修改mysql数据库的默认编码方式 .
查看>>
zip
查看>>
How to recover from root.sh on 11.2 Grid Infrastructure Failed
查看>>
rhel6下安装配置Squid过程
查看>>
《树莓派开发实战(第2版)》——1.1 选择树莓派型号
查看>>
在 Linux 下使用 fdisk 扩展分区容量
查看>>
结合AlphaGo算法和大数据的量化基本面分析法探讨
查看>>
如何在 Ubuntu Linux 16.04 LTS 中使用多个连接加速 apt-get/apt
查看>>
《OpenACC并行编程实战》—— 导读
查看>>
机器学习:用初等数学解读逻辑回归
查看>>
如何在 Ubuntu 中管理和使用逻辑卷管理 LVM
查看>>
Oracle原厂老兵:从负面案例看Hint的最佳使用方式
查看>>
把自己Github上的代码添加Cocoapods支持
查看>>
C语言OJ项目参考(2493)四则运算
查看>>
零基础入门深度学习(二):神经网络和反向传播算法
查看>>
find和xargs
查看>>
数据结构例程—— 交换排序之快速排序
查看>>
WKWebView代理方法解析
查看>>
IOS定位服务的应用
查看>>
[SMS&WAP]实例讲解制作OTA短信来自动配置手机WAP书签[附源码]
查看>>