【權限的思考】(一)使用反射實現動態權限


  每一個業務系統都會根據業務需要配置各種各樣的權限,實現方式也是千差萬別,各有各的優缺點。今天我們

利用反射來做一個小的權限管理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。

我們可以把這些數結構想像成一棵樹結構。

 

 /// <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);
        }

       
    }

 

》根據權限動態加載頁面和利用反射去打開相應的頁面

 先整理一下思路。

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

 

跑一下,看一下效果

 源碼 : ReflectionPermissionDemo.zip

github 地址: https://github.com/lpxxn/ReflectionPermissionDemo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM