【权限的思考】(一)使用反射实现动态权限
发布日期:2021-09-04 21:35:44 浏览次数:2 分类:技术文章

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

 每一个业务系统都会根据业务需要配置各种各样的权限,实现方式也是千差万别,各有各的优缺点。今天我们

利用反射来做一个小的权限管理Demo。也可以说是插件化的权限管理,通用的插件化框架是实现一个接口或者协定,

我们的做法是先展示指定的数据,再去动态的加载需要用到的dll和功能。

  大致的思路是这样的,我们从服务或者从数据库里读取哪些dll需要加载,相应的dll下哪些页面可以调用。把这些内容

动态的添加到页面上,当点击页面上的元素时利用反射,匹配目录下的dll和dll内的页面,进行读取,并显示进行交互,

从面实现插件化动态加载内容。如下图所示:

     例:

》.首先我们先建一个工程ReflectionPermissionDemo

      再添加3个类库ReflectionPermissionDemo.A;ReflectionPermissionDemo.B;ReflectionPermissionDemo.C;

需要注意的是不要在ReflectionPermissionDemo引用后边新建好的3个类库。我们的目标是用反射去加载这些dll库,

而不是使用引用方式。

创建完后还需要修改他们的输出路径属性

ReflectionPermissionDemo就生成到bin目录下

其它ReflectionPermissionDemo.A;ReflectionPermissionDemo.B;ReflectionPermissionDemo.C三个都指向这个

目录下生成。这样的目的是让所有的dll都在同一个文件夹下。

》.创建一些页面

  ReflectionPermissionDemo项目里修改一下页面。在顶部添加一个Panel用来动态添加按钮,这些动态添加上的按钮就是我们利

用反射动态加载的dll库。在下边也添加一个Panel用于动态显示权限信息,对应是dll库里面有权限的页面。设置他们的

性Dock一个为Top下边的为Fill。并给他们命名上边的panelTop。叫下边的叫panelBody

 

  在ReflectionPermissionDemo.A;ReflectionPermissionDemo.B;ReflectionPermissionDemo.C各自创建一些页面,这些页面也

需要权限设置的允许才能打开。

  在每个页面上放一个标识,标明这个窗体与其它的窗体不同,可以根据个人需要,我这里放的是label写了一些文字标明每个窗体是

哪个项目的哪个窗体,如下图:

 

      

 》模拟权限数据

  写一个单例类,创建一些权限数据,用于模拟从服务器上返回的数据。返回的数据有模块id,模块名称,命名空间和父id。

我们可以把这些数结构想像成一棵树结构。

 

///     /// 模拟远程服务器    /// 返回拥有的权限    ///     public class RemoteService    {        public static readonly RemoteService PermissionService = new RemoteService();        public DataTable PermissionTable { get; private set; }        #region   字段名称        public readonly string ModuleId = @"ModuleID";        public readonly string ModuleName = @"ModuleName";        public readonly string PermissioniNameSpace = @"PermissioniNameSpace";        public readonly string ParentId = @"ParentID";        #endregion        private RemoteService()        {            AllPermision();        }        ///         /// 所有的权限        ///         /// 
private DataTable AllPermision() { PermissionTable = new DataTable(); #region Permission Page PermissionTable.Columns.AddRange(new[] { new DataColumn(ModuleId, typeof (Int32)), // 模块id new DataColumn(ModuleName, typeof (string)), // 模块名称 new DataColumn(PermissioniNameSpace, typeof (string)), // 命名空间 new DataColumn(ParentId, typeof (Int32)) // 父id }); #endregion #region A CreateNewRow(1001, @"A模块", @"A", -1); CreateNewRow(1002, @"A 页面1", @"A.AForm1", 1001); // 测试权限先注掉 //CreateNewRow(1003, @"A 页面2", @"A.AForm2", 1001); #endregion #region B 由于我们的例子只不需要B的权限,这里先注掉 //CreateNewRow(2001, @"B模块", @"B", -1); //CreateNewRow(2002, @"B 页面1", @"B.BForm1", 2001); #endregion #region C CreateNewRow(3001, @"C模块", @"C", -1); CreateNewRow(3002, @"C Page1", @"C.CForm1", 3001); CreateNewRow(3003, @"C Page2", @"C.CForm2", 3001); #endregion return null; } /// /// 添加行 /// /// /// /// /// private void CreateNewRow(int moduleId, string moduleName, string perNameSpace, int parentId) { var newRow = PermissionTable.NewRow(); newRow[ModuleId] = moduleId; newRow[ModuleName] = moduleName; newRow[PermissioniNameSpace] = perNameSpace; newRow[ParentId] = parentId; PermissionTable.Rows.Add(newRow); } }

 

》根据权限动态加载页面和利用反射去打开相应的页面

 先整理一下思路。

1.读取模拟的权限数据。

2.根据权限数据组织页面元素

  》有哪些dll可以被加载

  》相应的dll内有哪些页面可以被调用

3.点击页面元素根据保存的数据利用反射把页面展示出来。

——————————————————

 >先添加一些字段。

// 权限数据        readonly DataTable _permissionDt = RemoteService.PermissionService.PermissionTable;        // 可用权限动态生成的panel页面        readonly Dictionary
_pagePanels = new Dictionary
(); // 已加载过的页面 private readonly Dictionary
_formTypes = new Dictionary
();

 

>根据权限数据动态组织页面

private void Main_Load(object sender, EventArgs e)        {                        var query = _permissionDt.Rows.Cast
(); var parentData = query.Where(x => int.Parse(x[RemoteService.PermissionService.ParentId].ToString()) == -1); SettingDllButtons(parentData); } ///
/// 展示 dll的权限按钮 /// ///
private void SettingDllButtons(IEnumerable
drs) { int width = 80, height = 30, x = 0, y = 0; foreach (var dataRow in drs) { var btn = new Button { Text = dataRow[RemoteService.PermissionService.ModuleName].ToString(), Size = new Size(width, height), Location = new Point(x, y) }; var index = SettingPageButtons(dataRow); btn.Tag = index; btn.Click += btnDLL_Click; panelTop.Controls.Add(btn); x += width + 10; } } ///
/// 根据 datarow的父id去找到所有的子节点 /// 加载到相应的页面上组织成按钮 /// ///
///
private int SettingPageButtons(DataRow dr) { var index = _pagePanels.Count(); var panel = new FlowLayoutPanel { Dock = DockStyle.Fill, Location = new Point(0, 0), Visible = false }; panelBody.Controls.Add(panel); _pagePanels[index] = panel; #region Btns var query = _permissionDt.Rows.Cast
(); var data = query.Where( x => int.Parse(x[RemoteService.PermissionService.ParentId].ToString()) == int.Parse(dr[RemoteService.PermissionService.ModuleId].ToString())); if (!data.Any()) return index; int width = 80, height = 30; foreach (var dataRow in data) { var btn = new Button { Text = dataRow[RemoteService.PermissionService.ModuleName].ToString(), Size = new Size(width, height), Tag = dataRow[RemoteService.PermissionService.PermissioniNameSpace] }; btn.Click += btnPage_Click; panel.Controls.Add(btn); } #endregion return index; }

 

> 利用点击不同的元素展示相应的页面

///         /// 显示相应的页面元素        ///         ///         ///         private void btnDLL_Click(object sender, EventArgs e)        {            var index = int.Parse(((Button) sender).Tag.ToString());            foreach (KeyValuePair
flowLayoutPanel in _pagePanels) { flowLayoutPanel.Value.Visible = flowLayoutPanel.Key == index; } } ///
/// 打开相应的page /// ///
///
private void btnPage_Click(object sender, EventArgs e) { var name = ((Button) sender).Tag.ToString(); var form = GetModule(name) as Form; form.ShowDialog(); } #region ///
/// 利用反射去加载相应的页面 /// ///
///
///
private object GetModule(string path, string mainNamespace = "ReflectionPermissionDemo") { var curNamespace = ""; var index = path.IndexOf('.'); if (index > -1) { curNamespace = "." + path.Substring(0, index); } else { curNamespace = ""; } var assemblyPath = mainNamespace + curNamespace; var classPath = mainNamespace + "." + path; object module = null; if (_formTypes.ContainsKey(classPath)) { module = Activator.CreateInstance(_formTypes[classPath]); } else { try { module = Assembly.Load(assemblyPath).CreateInstance(classPath); if (module != null) _formTypes.Add(classPath, module.GetType()); } catch { // 查找当前已加载的dll。 Type type = null; foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { if (!assembly.FullName.Contains(mainNamespace)) continue; type = assembly.GetType(classPath, false); if (type != null) { break; } } if (type == null) { throw; } else { module = Activator.CreateInstance(type); if (module != null) { _formTypes.Add(classPath, type); } ; } } } return module; } #endregion

 

跑一下,看一下效果

 源码 : 

github 地址: 

本文转自lpxxn博客园博客,原文链接:http://www.cnblogs.com/li-peng/p/5644594.html,如需转载请自行联系原作者

转载地址:https://blog.csdn.net/weixin_34223655/article/details/90096692 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Struts2的声明式异常处理
下一篇:VICA 架构设计(1)

发表评论

最新留言

哈哈,博客排版真的漂亮呢~
[***.90.31.176]2024年04月07日 17时31分34秒