C# C/S结构数据库系统框架详解(二) ModuleManager详解[vjsdn]

一个大的应用程序由大量模块构成, 因人而异模块的理解和分类各有不同. 在C/S框架内我将模块(Module)定义为一个DLL程序(Class Library). 而每个DLL程序按业务分类. 如进销存系统我们可定义3个模块:采购模块(Purchase Module),销售模块(Sales Module)和库存模块(Inventory Module).而每个模块的业务代码封装在
DLL Class Library内. 则构成3个独立的DLL和一个可执行EXE文件. 如要细分还有公共模块(Common Module), 数据访问层(Data Access Layer Module),系统安全(System Security Module)和系统设置模块(System Setups Module)等模块. 这样就构成一个简单的多模块系统框架了.

C/S框架内定义了8个模块(DLL)和一个主程序(EXE).

2010072311573044.png

从设计角度上讲模块也要分类,可分为系统模块和业务模块.

系统模块是框架组成部分,如Business.dll,Common.dll,DataAccess.dll,Library.dll,Models.dll.
业务模块封装核心业务,包括业务窗体,图片资源等信息. 如上所述的进销存系统:进,销,存3个模块为业务模块.

我们对模块有了初步认识. 由此可见一个系统是由很多模块构成的,而系统越大分的模块越多,模块越多程序越复杂和难以控制.当然安全问题也应运而生了.

假设A用户仅能使用采购模块(Purchase Module),另两个模块不可见, 在设计上我们可以这么做:
1.设计权限,隐藏其它两个模块.
2.在客户机仅发布exe和purchase.dll
3.其它设计.

假设不按业务独立模块,我想设计权限来隐藏其它两个模块是件复杂而危险的事. 可想而知你需要在每个窗体每个业务类都要判断A用户是否有Sales和Inventory的权限,成百上千种判断会使你疯狂!

但是只给客户机安装一个purchase.dll,即使在设计上不判断权限也用不着Sales和Inventory任何功能!

假设我们选择第2种方法, 因客户不同发布的dll也不同,这里牵涉到动态加载dll的问题!本文的重点就是介绍如何动态加载模块.下面且看相关源代码:

ModuleID类:模块编号,给每个模块一个唯一编号.

 

 
  
/// <summary>
/// 模块编号,给每个模块一个唯一编号.
/// </summary>
public enum ModuleID
{
None
= 0 ,
TestModule1
= 1 , // 测试模块1
TestModule2 = 2 , // 测试模块2
SystemManage = 3 , // 系统管理模块
}

 

模块信息类:实体类,封装与模块相关信息.

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 模块信息类
/// </summary>
public class ModuleInfo
{
private Assembly _ModuleAssembly = null ;
private ModuleID _ModuleID = ModuleID.None;
private string _ModuleName = string .Empty;
private string _ModuleFile = string .Empty;

/// <summary>
/// 构造器
/// </summary>
public ModuleInfo(Assembly asm, ModuleID id, string name, string file)
{
_ModuleAssembly
= asm;
_ModuleFile
= file;
_ModuleID
= id;
_ModuleName
= name;
}

/// <summary>
/// 加载DLL文件后程序集指针
/// </summary>
public Assembly ModuleAssembly
{
get { return _ModuleAssembly; }
set { _ModuleAssembly = value; }
}

/// <summary>
/// 模块文件(*.dll)
/// </summary>
public string ModuleFile
{
get { return _ModuleFile; }
set { _ModuleFile = value; }
}

/// <summary>
/// 模块名称
/// </summary>
public string ModuleName
{
get { return _ModuleName; }
set { _ModuleName = value; }
}

/// <summary>
/// 模块编号
/// </summary>
public ModuleID ModuleID
{
get { return _ModuleID; }
set { _ModuleID = value; }
}
}

转载请注明来自易学网 www.vjsdn.net 易学原创作品

 

ModuleLoader:模块加载器. 通过ModuleLoader类动态加载模块dll, 将程序集Assembly保存在
_ModuleAssembly变量.

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 模块加载器
/// </summary>
public class ModuleLoader
{
private string _ModuleFileName; // DLL 文件名
private frmModuleBase _ModuleMainForm; // 如果加載了模塊. 返回該模塊的主窗體對象.
private Assembly _ModuleAssembly;

public static readonly string MODULE_FILTER = " 易学网C/S系统框架模块|VJSDN C/S Modules|*.dll " ;
public static readonly string MODULE_PATH = Application.StartupPath;

public ModuleLoader()
{
//
}

/// <summary>
/// 模块所在的程序集
/// </summary>
public Assembly ModuleAssembly
{
get { return _ModuleAssembly; }
}

/// <summary>
/// 返回AssemblyModuleEntry,自定义模块特性
/// </summary>
public string GetCurrentModuleName()
{
return ModuleLoader.GetModuleEntry(_ModuleAssembly).ModuleName;
}

/// <summary>
/// 模块主窗体
/// </summary>
public frmModuleBase ModuleMainForm
{
get { return _ModuleMainForm; }
}

/// <summary>
/// 加载模块的菜单
/// </summary>
/// <param name="menuStrip"> 程序主窗体的菜单 </param>
public void LoadMenu(MenuStrip menuStrip)
{
if (_ModuleMainForm != null && _ModuleMainForm.GetModuleMenu() != null )
{
menuStrip.Items.Insert(menuStrip.Items.Count
- 1 , _ModuleMainForm.GetModuleMenu().Items[ 0 ]);
}
}

/// <summary>
/// 加载模块主方法
/// </summary>
/// <param name="moduleinfo"> 模块信息 </param>
/// <returns></returns>
public bool LoadModule(ModuleInfo moduleinfo)
{
_ModuleFileName
= moduleinfo.ModuleFile;
_ModuleAssembly
= moduleinfo.ModuleAssembly;
string entry = GetModuleEntryNameSpace(_ModuleAssembly);
if ( string .Empty == entry) return false ;

Form form
= (Form)_ModuleAssembly.CreateInstance(entry);
_ModuleMainForm
= null ;

if (form is IModuleBase)
_ModuleMainForm
= (frmModuleBase)form;

return _ModuleMainForm != null ;
}

/// <summary>
/// 获取模块列表,转换为ModuleInfo集合.
/// </summary>
public IList < ModuleInfo > GetModuleList()
{
try
{
string [] files = null ; // 模塊文件(*.dll)
IList < ModuleInfo > list = new List < ModuleInfo > ();

if (Directory.Exists(MODULE_PATH))
files
= Directory.GetFiles(MODULE_PATH, " *.dll " );

foreach ( string mod in files)
{
Assembly asm
= null ;
try
{
// .net framework dll
asm = Assembly.LoadFile(mod);
}
catch { continue ; }

ModuleID id
= GetModuleID(asm);
string name = GetCurrentModuleName();
if (id != ModuleID.None)
{
ModuleInfo m
= new ModuleInfo(asm, id, name, mod);
list.Add(m);
}
}

SortModule(list);
// 模塊排序.

return list;
}
catch (Exception ex)
{
Msg.ShowException(ex);
return null ;
}
}

/// <summary>
/// 获取程序集自定义特性。是否用户自定义模块由AssemblyModuleEntry特性确定。
/// </summary>
/// <returns></returns>
public AssemblyModuleEntry GetModuleEntry()
{
return ModuleLoader.GetModuleEntry(_ModuleAssembly);
}

/// <summary>
/// 判断加载的文件是否模块文件,因目录下可能有不同类别的DLL文件。
/// 判断DLL为模块的条件是检查Assembly特性。
/// </summary>
public bool IsModuleFile( string moduleFile)
{
try
{
Assembly asm
= Assembly.LoadFile(moduleFile);
return (ModuleLoader.GetModuleID(asm) != ModuleID.None);
}
catch { return false ; }
}

/// <summary>
/// 每一个模块对应一个XtraTabPage,然后將模块主窗体的Panel容器放置在XtraTabPage内。
/// 因此,所有加载的模块主窗体的Panel容器都嵌套在主窗体的XtraTabControl内。
/// </summary>
public void LoadGUI(XtraTabControl mainTabControl)
{
try
{
IModuleBase moduleBase
= _ModuleMainForm as IModuleBase;

Panel container
= moduleBase.GetContainer(); // 模块主窗体的Panel容器
if ( null != container)
{
container.Dock
= DockStyle.Fill;
XtraTabPage page
= new XtraTabPage();
page.Text
= this .GetCurrentModuleName();
page.Controls.Add(container);
mainTabControl.TabPages.Add(page);
}
}
catch (Exception ex) { Msg.ShowException(ex); }
}

/// <summary>
/// 模块排序
/// </summary>
/// <param name="list"></param>
public void SortModule(IList < ModuleInfo > list)
{
int i, j;
ModuleInfo temp;
bool done = false ;
j
= 1 ;
while ((j < list.Count) && ( ! done))
{
done
= true ;
for (i = 0 ; i < list.Count - j; i ++ )
{
if ((list[i] as ModuleInfo).ModuleID > (list[i + 1 ] as ModuleInfo).ModuleID)
{
done
= false ;
temp
= list[i];
list[i]
= list[i + 1 ];
list[i
+ 1 ] = temp;
}
}
}
}

#region 类公共表态方法

/// <summary>
/// 查找子菜单,深度搜索
/// </summary>
public static ToolStripMenuItem GetMenuItem(ToolStrip mainMenu, string menuName)
{
ToolStripItem[] items
= mainMenu.Items.Find(menuName, true );
if (items.Length > 0 && items[ 0 ] is ToolStripMenuItem)
return (ToolStripMenuItem)items[ 0 ];
else
return null ;
}

/// <summary>
/// 获取程序集自定义特性。是否用户自定义模块由AssemblyModuleEntry特性确定。
/// </summary>
public static AssemblyModuleEntry GetModuleEntry(Assembly asm)
{
AssemblyModuleEntry temp
= new AssemblyModuleEntry(ModuleID.None, "" , "" );
if (asm == null ) return temp;

object [] list = asm.GetCustomAttributes( typeof (AssemblyModuleEntry), false );
if (list.Length > 0 )
return (AssemblyModuleEntry)list[ 0 ];
else
return temp;
}

/// <summary>
/// 获取模块主窗体名字空间
/// </summary>
public static string GetModuleEntryNameSpace(Assembly asm)
{
return GetModuleEntry(asm).ModuleEntryNameSpace;
}

/// <summary>
/// 獲取模塊編號
/// </summary>
public static ModuleID GetModuleID(Assembly asm)
{
return ModuleLoader.GetModuleEntry(asm).ModuleID;
}

#endregion
}
转载请注明来自易学网 www.vjsdn.net 易学原创作品


 

模块控制类
1.管理ModuleLoader加载的模块.
2.动态创建菜单及导航条按钮.
3.将所有模块主窗体组合在XtraTabControl 控件内. 每个XtraTabPage对应一个模块.

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 模块管理器
/// </summary>
public class ModuleManager
{
// 程序主窗体的TabControl,用于放置模块主窗体
private XtraTabControl _tabControlModules = null ;

// 程序主窗体
private Form _MDIMainForm = null ;

private static IList < ModuleInfo > _Modules = null ;

/// <summary>
/// 获取回载的模块
/// </summary>
public static IList < ModuleInfo > GetAvailableModules()
{
return _Modules;
}

/// <summary>
/// 构造器
/// </summary>
public ModuleManager(Form mdiMainForm, XtraTabControl tabControlModules)
{
_tabControlModules
= tabControlModules;
_MDIMainForm
= mdiMainForm;
}

/// <summary>
/// Navigator bar 导航条按鈕事件.
/// </summary>
public static void OnNavBarLinkClick( object sender, NavBarLinkEventArgs e)
{
if (e.Link.Item.Tag is ToolStripItem)
{
ToolStripItem item
= (ToolStripItem)(e.Link.Item.Tag);
if ( null != item) item.PerformClick(); // 執行菜單事件.
}
}

/// <summary>
/// 是否有子菜單.
/// </summary>
private bool IsSubMenuOwner(ToolStripItem item)
{
if (item is ToolStripMenuItem)
{
if (((ToolStripMenuItem)item).DropDownItems.Count > 0 )
return true ;
}
return false ;
}

/// <summary>
/// 由菜单创建导航条控件按钮
/// </summary>
private NavBarItem CreateNavBarItem(NavBarControl navBar, ToolStripItem item)
{
NavBarItem newItem
= new NavBarItem();
newItem.Caption
= item.Text;
newItem.Tag
= item; // 綁定一個菜單項,newItem.Click事件會使用這個菜單項
newItem.LinkClicked += new NavBarLinkEventHandler(ModuleManager.OnNavBarLinkClick);
navBar.Items.Add(newItem);
return newItem;
}

/// <summary>
/// 导航条控件按钮分组
/// </summary>
private NavBarGroup CreateNavBarGroup(NavBarControl navBar, string caption)
{
NavBarGroup group
= navBar.Groups.Add(); // 增加一個Button組.
group.Caption = caption; // 模塊的顯示名稱
group.LargeImageIndex = 0 ;
if (group.Caption.Equals( string .Empty)) group.Caption = " Unknown Name " ;
return group;
}

/// <summary>
/// 当点击导航条分组按钮时触发该事件
/// </summary>
private void OnActiveGroupChanged( object sender, DevExpress.XtraNavBar.NavBarGroupEventArgs e)
{
try
{
string moduleName = e.Group.Caption.ToString();
this .ActiveModule(moduleName);
}
catch (Exception ex) { Msg.ShowException(ex); }
}

/// <summary>
/// 显示指定的模块主窗体
/// </summary>
public void ActiveModule( string moduleDisplayName)
{
foreach (XtraTabPage page in this ._tabControlModules.TabPages)
{
if (page.Text.Equals(moduleDisplayName))
{
_tabControlModules.SelectedTabPage
= page;
return ;
}
}
}

/// <summary>
/// 创建导航条分组按钮 Navigator NavBarGroup
/// </summary>
/// <param name="navBar"> NavBarControl对象 </param>
/// <param name="moduleMenu"> 模块主菜单 </param>
/// <param name="moduleDisplayName"> 模块名称 </param>
public NavBarGroup CreateNavBarButton(NavBarControl navBar, ToolStripMenuItem moduleMenu, string moduleDisplayName)
{
navBar.ActiveGroupChanged
+= new NavBarGroupEventHandler(OnActiveGroupChanged);

NavBarGroup group
= CreateNavBarGroup(navBar, moduleDisplayName); // 根据模块名称创建Group
if (moduleMenu == null ) return group; // 组没有菜单则返回,实为一个空组无子按钮.

foreach (ToolStripItem menuItem in moduleMenu.DropDownItems)
{
if (menuItem is ToolStripSeparator) continue ;
if (IsSubMenuOwner(menuItem)) continue ;
if (menuItem.Enabled)
{
NavBarItem item
= CreateNavBarItem(navBar, menuItem);
item.SmallImageIndex
= 1 ; // Sub Function
group.ItemLinks.Add(item);
}
}
return group;
}

/// <summary>
/// 初始化NavBar控件.绑定组NavGroup.ActiveGroupChanged事件
/// </summary>
public void CreateNavBarButtons(NavBarControl navBar, MenuStrip mainMenu)
{
try
{
navBar.SuspendLayout();
navBar.Items.Clear();
navBar.Groups.Clear();
foreach (XtraTabPage page in this ._tabControlModules.TabPages)
{
// 取主窗体对应的顶级菜单
ToolStripMenuItem moduleMenu = FindMenuItemByText(mainMenu, page.Text);

if (moduleMenu != null && moduleMenu.Enabled) // 创建该模块的NavBarButton.
this .CreateNavBarButton(navBar, moduleMenu, page.Text);
}
navBar.ResumeLayout();
}
catch (Exception ex) { Msg.ShowException(ex); }
}

private ToolStripMenuItem FindMenuItemByText(MenuStrip mainMenu, string text)
{
foreach (ToolStripMenuItem item in mainMenu.Items)
if (item.Text == text) return (ToolStripMenuItem)item;
return null ;
}

/// <summary>
/// 加载模块主方法
/// </summary>
public void LoadModules(StatusLable msg)
{
try
{
ModuleLoader loader
= new ModuleLoader();
_Modules
= loader.GetModuleList(); // 從目錄裝載模塊
foreach (ModuleInfo m in _Modules) // 枚舉文件名列表.
{
if ( ! loader.LoadModule(m)) continue ;

msg.UpdateMessage(
" 正在加载: " + loader.GetCurrentModuleName());
loader.LoadGUI(_tabControlModules);
loader.LoadMenu(_MDIMainForm.MainMenuStrip);
loader.ModuleMainForm.MdiParent
= _MDIMainForm; // 设置模块主窗体的父窗体.
}
GC.Collect();
}
catch (Exception ex) { Msg.ShowException(ex); }
}
}
转载请注明来自易学网 www.vjsdn.net 易学原创作品

 

为了规范模块共有的特性,设计一个模块主窗体接口.

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 模块主窗体接口
/// </summary>
public interface IModuleBase
{
ModuleID GetModuleID();
// 获取模块编号
ModuleInfo GetModuleInfo(); //
Panel GetContainer(); // 模块主窗体容器
MenuStrip GetModuleMenu();

void InitButton();
void InitMenu();
}
转载请注明来自易学网 www.vjsdn.net 易学原创作品

 

定义一个模块主窗体基类来实现这个接口.

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
/// <summary>
/// 模块主窗体基类
/// </summary>
public partial class frmModuleBase : frmBase, IModuleBase
{
public frmModuleBase()
{
InitializeComponent();
}

#region IModuleBase Members

// 模块的主菜单
public virtual MenuStrip GetModuleMenu()
{
return null ;
}

// 模块编号
public virtual ModuleID GetModuleID()
{
return ModuleID.None;
}

// 模块信息
public virtual ModuleInfo GetModuleInfo()
{
return null ;
}

// 模块主窗体容器
public virtual Panel GetContainer()
{
return this .pnlContainer;
}

// 初始化按钮
public virtual void InitButton()
{
}

// 初始化菜单
public virtual void InitMenu()
{
}

#endregion
}
转载请注明来自易学网 www.vjsdn.net 易学原创作品


 

 

 

全部链接:
1.C/S结构数据库系统框架详解
http://www.vjsdn.net/bbs/bbsTopicDetails.aspx?pid=109201218

2.ModuleManager详解
http://www.vjsdn.net/bbs/bbsTopicDetails.aspx?pid=109201219

3.如何新建一个模块
http://www.vjsdn.net/bbs/bbsTopicDetails.aspx?pid=109201220

4.C/S结构数据库系统框架源代码
http://www.vjsdn.net/bbs/bbsTopicDetails.aspx?pid=109201221

转载于:https://www.cnblogs.com/raychn/archive/2010/07/23/1783615.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值