使用反射实现动态权限

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

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

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

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

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

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

例:

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

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

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

而不是使用引用方式。

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

ReflectionPermissionDemo就生成到bin目录下

其它ReflectionPermissionDemo.A;http://item.taobao.com/item.htm?id=41222768202;ReflectionPermissionDemo.C三个都指向这个

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

》.创建一些页面

  http://item.taobao.com/item.htm?id=41222768202项目里修改一下页面。在顶部添加一个Panel用来动态添加按钮,这些动态添加上的按钮就是我们利

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

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

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

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

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

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

     

》模拟权限数据

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

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

 /// <summary>
    /// 模拟远程服务器
    /// 返回拥有的权限
    /// </summary>
    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();
        }

        /// <summary>
        /// 所有的权限
        /// </summary>
        /// <returns></returns>
        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;
        }

        /// <summary>
        /// 添加行
        /// </summary>
        /// <param name="moduleId"></param>
        /// <param name="moduleName"></param>
        /// <param name="perNameSpace"></param>
        /// <param name="parentId"></param>
        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);
        }

    }

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

先整理一下思路。http://item.taobao.com/item.htm?id=41222768202

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

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

  》有哪些dll可以被加载

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

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

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

>先添加一些字段。

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

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

        private void Main_Load(object sender, EventArgs e)
        {
            var query = _permissionDt.Rows.Cast<DataRow>();
            var parentData = query.Where(x => int.Parse(x[RemoteService.PermissionService.ParentId].ToString()) == -1);
            SettingDllButtons(parentData);

        }

        /// <summary>
        /// 展示 dll的权限按钮
        /// </summary>
        /// <param name="dt"></param>
        private void SettingDllButtons(IEnumerable<DataRow> 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;
            }
        }
        /// <summary>
        /// 根据 datarow的父id去找到所有的子节点
        /// 加载到相应的页面上组织成按钮
        /// </summary>
        /// <param name="dr"></param>
        /// <returns></returns>
        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<DataRow>();
            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;
        }   

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

        /// <summary>
        /// 显示相应的页面元素
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDLL_Click(object sender, EventArgs e)
        {
            var index = int.Parse(((Button) sender).Tag.ToString());
            foreach (KeyValuePair<int, FlowLayoutPanel> flowLayoutPanel in _pagePanels)
            {
                flowLayoutPanel.Value.Visible = flowLayoutPanel.Key == index;
            }
        }

        /// <summary>
        /// 打开相应的page
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnPage_Click(object sender, EventArgs e)
        {
            var name = ((Button) sender).Tag.ToString();
            var form = GetModule(name) as Form;
            form.ShowDialog();
        }

        #region
        /// <summary>
        /// 利用反射去加载相应的页面
        /// </summary>
        /// <param name="path"></param>
        /// <param name="mainNamespace"></param>
        /// <returns></returns>
        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
时间: 2024-08-30 07:48:16

使用反射实现动态权限的相关文章

【权限的思考】(一)使用反射实现动态权限

每一个业务系统都会根据业务需要配置各种各样的权限,实现方式也是千差万别,各有各的优缺点.今天我们 利用反射来做一个小的权限管理Demo.也可以说是插件化的权限管理,通用的插件化框架是实现一个接口或者协定, 我们的做法是先展示指定的数据,再去动态的加载需要用到的dll和功能. 大致的思路是这样的,我们从服务或者从数据库里读取哪些dll需要加载,相应的dll下哪些页面可以调用.把这些内容 动小态的添加到页面上,当点击页面上的元素时利用反射 匹配目录下的dll和dll内的页面,进行读取,并显示进行交互

Java开发人员必懂的基础——反射与动态代理

Java的反射与动态代理是java体系结构中较为底层的知识,初学者可能觉得没有太大的用处,但他们确实著名Spring框架IOC和AOP所用的最重要的内容.当我们需要开发更基础,更广泛的的代码时,就会用到这学知识了. 在此之前,我们先来了解一下java的类加载机制 JVM与类加载机制: /* * 1.JVM:当调用java命令来运行某个java程序时,该命令会启动一个java虚拟机进程,同一个JVM中的所有线程,所有变量都处于同一个进程里,都使用该JVM的内存区 * 2.JVM:运行下面两个测试类

通过AOP的思想 打造万能动态权限申请框架Demo完全解析

AOP优雅权限框架详解(以及更多面试题) https://github.com/xiangjiana/Android-MS gradle配置 在project的 build.gradle 添加 aspectJ gradle插件 } dependencise { classpath 'com.android.tools.build:gradle:3.5.0' //1_1.grade-android-plugin-aspectjx classpath 'com.hujiang.aspectjx:gr

Java反射以及动态代理(上)

在常用的各种框架中,反射与动态代理很常见,也很重要.本篇就对这一小节的内容基础性地总结. 首先需要了解什么是类型信息,以及RTTI与反射的关系与区别. Java中,使用Class对象来表示所有类的对象.利用Class对象来获取类中的成员变量,构造函数以及方法,这些内容我们称之为类型信息.RTTI的含义是,在运行时识别一个对象的类型,但有一个前提,就是类型在编译时必须已知,这样才能用RTTI识别,并利用这些信息做一些有用的事情.但是如果在编译时,程序没有办法获知到这个对象所属的类,怎样才能使用这个

java反射与动态代理

Java反射与动态代理 Java反射机制可以动态地获取类的结构,动态地调用对象的方法,是java语言一个动态化的机制.java动态代理可以在不改变被调用对象源码的前提下,在被调用方法前后增加自己的操作,极大地降低了模块之间的耦合性.这些都是java的基础知识,要想成为一名合格的程序猿,必须掌握! Java反射机制 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为

Android 6.0 - 动态权限管理的解决方案(转)

转自:http://www.cnblogs.com/dubo-/p/6018262.html Android 6.0 - 动态权限管理的解决方案 转载请标注 Android 6.0版本(Api 23)推出了很多新的特性, 大幅提升了用户体验, 同时也为程序员带来新的负担. 动态权限管理就是这样, 一方面让用户更加容易的控制自己的隐私, 一方面需要重新适配应用权限. 时代总是不断发展, 程序总是以人为本, 让我们为应用添加动态权限管理吧! 这里提供了一个非常不错的解决方案, 提供源码, 项目可以直

[转] 通过反射实现动态功能模块加载

原文 如何通过反射实现动态功能模块加载 程序集包含模块,而模块包含类型,类型又包含成员.反射则提供了封装程序集.模块和类型的对象.您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型.然后,可以调用类型的方法或访问其字段和属性. 下面我们将介绍如何通过不使用反射的方式和使用反射的方式加载功能模块.实现效果: 1. WinForm 主程序 主程序我们使用Winform程序,VS2008 工具C#语言开发.包括工具栏.状态栏及TabControl控件.我们使用TabCon

反射之动态创建对象

前言 C#有关反射的话题已经是个老生常谈的话题,也许园友一看这标题都不屑去看了,但是既然拿出来讲必有讲之道理,当然,不喜勿喷,高手请绕道!直入话题. 讨论 定义一个Person类代码如下 1 public class Person 2 { 3 4 /// <summary> 5 /// 年龄 6 /// </summary> 7 public int Age { get; set; } 8 9 /// <summary> 10 /// 姓名 11 /// </su

JAVA学习--反射之动态代理模式

1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 5 //动态代理的使用,体会反射是动态语言的关键 6 interface Subject { 7 void action(); 8 } 9 10 // 被代理类 11 class RealSubject implements Subject { 12 public