最近做一个广告系统,后台管理部分使用 ASP.NET,使用了 VS2008 + .Net 3.5,还是使用我写的 DbEntry 做数据库接口,页面部分大部分使用 ASP.NET Ajax 的 UpdatePanel 来进行更新,效果很不错,而且,速度上也感觉比普通的非 Ajax 页面快。
而对于权限部分,使用页面级访问控制,读取 Web.Config 的方式,导航使用 html 直接放在母板页中的方式,后来觉得这样,每增加一个页面或对页面改名,就需要修改两个地方,不是一个很好的解决方案。
以前,在做互联星空的一个项目时,曾经设计了使用 XML 做配置,导入 TreeView 做导航的方式,目前虽然不是使用 TreeView 做导航,应该也一样是适用的。不过,这一次,不想使用 XML,而是考虑直接在程序中使用 List 或 Directory 来表示这个数据结构。
试着写了一下这个结构,发现,还是使用类似数据库的结构比较简单。于是定义 Category 和 Link 类,另外定义 Navigation 类,增加两个静态字段 Categories 和 Links:
public class Category
{
private static int IdSeed = 1;
public int Id { get; set; }
public string Name { get; set; }
public Category()
{
Id = IdSeed++;
}
}
public class Link
{
private static int IdSeed = 1;
public int Id { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public int Permission { get; set; }
public bool Hide { get; set; }
public int Category_Id { get; set; }
public Link()
{
Id = IdSeed++;
}
}
public static class Navigation
{
public static readonly List<Category> Categories;
public static readonly List<Link> Links;
}
然后,在静态构造函数中初始化数据:
static Navigation()
{
Categories = new List<Category>()
{
new Category(){ Id = 1, Name = "设备管理" },
new Category(){ Id = 2, Name = "内容管理" },
new Category(){ Id = 3, Name = "计划" },
new Category(){ Id = 4, Name = "系统" },
};
int FullPermission = (int)(SysUserRole.管理员 | SysUserRole.编辑人员 | SysUserRole.审核人员);
Links = new List<Link>()
{
new Link(){ Url = "Default", Permission = FullPermission, Hide = true },
// 设备管理
new Link(){ Name = "新建设备", Url = "PlayerEdit", Permission = FullPermission, Category_Id = 1 },
new Link(){ Name = "设备列表", Url = "PlayerList", Permission = FullPermission, Category_Id = 1 },
new Link(){ Url = "PlayerManager", Permission = FullPermission, Hide = true, Category_Id = 1 },
new Link(){ Category_Id = 1 },
new Link(){ Name = "新建分组", Url = "PlayerGroupEdit", Permission = FullPermission, Category_Id = 1 },
new Link(){ Name = "分组列表", Url = "PlayerGroupList", Permission = FullPermission, Category_Id = 1 },
// 内容管理
......
// 计划
......
// 系统
new Link(){ Name = "新建帐户", Url = "SysUserEdit", Permission = FullPermission, Category_Id = 4 },
new Link(){ Name = "帐户列表", Url = "SysUserList", Permission = FullPermission, Category_Id = 4 },
new Link(){ Category_Id = 4 },
new Link(){ Name = "新建客户", Url = "CustomerEdit", Permission = FullPermission, Category_Id = 4 },
new Link(){ Name = "客户列表", Url = "CustomerList", Permission = FullPermission, Category_Id = 4 },
};
}
其中,空的 Link 表示显示一个 hr 标签,用来分组,Url 是去掉“.aspx”之后的名字,Permission 用来对页面可访问性进行授权,这种方式,对于 int32 而言,可以提供 32 种权限,应该是足够了,当然,各种权限应该按 2 的幂的方式递增,如 1、2、4、8。这样,在判断是否有权限的时候,只要用“(Permission & p) == p”来判断就可以了。
导航的 html 改在 Navigation 类中生成,然后填入母板页中的方式,使用 DbEntry 中的 HtmlBuilder 来生成 html 片段:
public static string BuildNavigator(int Permission)
{
HtmlBuilder hb = HtmlBuilder.New.div.id("accmenu").enter();
foreach (var c in Categories)
{
int count = 0;
var b = HtmlBuilder.New.tab.div.enter();
b.tab.tab.div.Class("acctitle").text(c.Name).end.enter();
b.tab.tab.div.enter();
var list = Links.Where(p => p.Category_Id == c.Id).ToList();
foreach (var n in list)
{
if (string.IsNullOrEmpty(n.Url))
{
b.include("\t\t\t<hr />\r\n");
}
else
{
if (!n.Hide && (n.Permission & Permission) == Permission)
{
count++;
b.include("\t\t\t<img src=\"images/h2.gif\" align=\"absmiddle\" /> ");
b.a(n.Url + ".aspx").text(n.Name).end.br.enter();
}
}
}
b.tab.tab.end.enter().tab.end.enter();
if (count > 0)
{
hb.include(b);
}
}
hb.end.enter();
return hb.ToString();
}
上面的代码,会生成类似以下的 html :
<div id="accmenu">
<div>
<div class="acctitle">设备管理</div>
<div>
<img src="images/h2.gif" align="absmiddle" /> <a href="PlayerEdit.aspx">新建设备</a><br />
<img src="images/h2.gif" align="absmiddle" /> <a href="PlayerList.aspx">设备列表</a><br />
<hr />
<img src="images/h2.gif" align="absmiddle" /> <a href="PlayerGroupEdit.aspx">新建分组</a><br />
<img src="images/h2.gif" align="absmiddle" /> <a href="PlayerGroupList.aspx">分组列表</a><br />
</div>
</div>
<div>
......
</div>
<div>
......
</div>
<div>
<div class="acctitle">系统</div>
<div>
<img src="images/h2.gif" align="absmiddle" /> <a href="SysUserEdit.aspx">新建帐户</a><br />
<img src="images/h2.gif" align="absmiddle" /> <a href="SysUserList.aspx">帐户列表</a><br />
<hr />
<img src="images/h2.gif" align="absmiddle" /> <a href="CustomerEdit.aspx">新建客户</a><br />
<img src="images/h2.gif" align="absmiddle" /> <a href="CustomerList.aspx">客户列表</a><br />
</div>
</div>
</div>
而,它的显示,使用的是 jQuery 的插件
jQuery Accordion ,按照自己想要风格配置 css,然后在母板页中加入:
jQuery().ready(function(){
var w = $('#accmenu').accordion({
header: 'div.acctitle',
animated: false
});
w.activate(CategoryIndex);
});
之所以要关闭动画效果,是为了根据当前页所在分类,自动激活相应的面板,自动激活的过程如果有动画,显得很奇怪,不过,还没有找到这个 jQuery 插件相关设置初始面板的方法......
Navigation 类提供取得指定 Url 权限的功能,使用基本的 Linq 语法:
public static int GetPermission(string Url)
{
var item = Links.Where(p => p.Url == Url).ToList();
if (item.Count > 0)
{
return item[0].Permission;
}
return 0;
}
因为,在生成 html 的时候,考虑了如果按照相应的权限,一个分类下没有任何项目,则不显示这个分类,所以,取 Index 要复杂一些,要根据相应的权限进行分组,所以相应的 Linq 语句也复杂一些,使用了 group by:
public static int GetIndex(string Url, int Permission)
{
int id = FindCategoryId(Url);
var item = from p in Links where (p.Permission & Permission) == Permission && p.Category_Id != 0
group p by p.Category_Id into g select new { Category_Id = g.Key };
var i = item.ToList().FindIndex(p => p.Category_Id == id);
return i < 0 ? 0 : i;
}
public static int FindCategoryId(string Url)
{
var item = Links.Where(p => p.Url == Url).ToList();
if (item.Count > 0)
{
return item[0].Category_Id;
}
return 0;
}
虽然我现在使用的是内存里的数据,不过,因为格式是很标准的数据库格式,所以,要把这个配置项放入数据库表里,或者序列化成 XML,也都是非常方便的 —— 虽然我认为这个必要性不高。
从实现来看,这个方法的速度应该不会很快,不过,因为数据量小,而且对于页面来说,这些在内存里做的手脚只能算小Case,所以没有明显感觉速度上有任何差异。
不过,目前对于这个方案,还有一些不满意,比如,Hide 参数考虑改成和 Permission 相似,则可以控制每一项在不同权限下的显示,比单纯的全局 Hide 要灵活得多。再比如,目前没有判断是否会出现两条分割线等等。
另外一种实现方案是,把数据的定义放在每一个页面里,这样的话,虽然设置分散到了每一个页面,但是却更符合实际情况,而且,页面 Url 也可以通过反射得到,删除页面或者页面改名都更简单,也许是更好的解决方案吧。
其实,我感觉很好的是,这个程序的页面风格、css 以及一些图片什么的,都是我做的,而且我感觉还挺漂亮的
,来个运行截图:
- 描述: 运行截图
- 大小: 175.9 KB
分享到:
相关推荐
第 4 章 ASP.NET 的网页代码模型及生命周期 4.1 ASP.NET 的网页代码模型 4.1.1 创建ASP.NET 网站 4.1.2 单文件页模型 4.1.3 代码隐藏页模型 4.1.4 创建ASP.NET Web Application 4.1.5 ASP.NET 网站和ASP.NET 应用...
第4章 ASP.NET的网页代码模型及生命周期 4.1 ASP.NET的网页代码模型 4.1.1 创建ASP.NET网站 4.1.2 单文件页模型 4.1.3 代码隐藏页模型 4.1.4 创建ASP.NET Web Application 4.1.5 ASP.NET网站和ASP.NET应用程序的区别...
第4章 ASP.NET的网页代码模型及生命周期 4.1 ASP.NET的网页代码模型 4.1.1 创建ASP.NET网站 4.1.2 单文件页模型 4.1.3 代码隐藏页模型 4.1.4 创建ASP.NET Web Application 4.1.5 ASP.NET网站和ASP.NET应用程序的区别...
第4章 ASP.NET的网页代码模型及生命周期 4.1 ASP.NET的网页代码模型 4.1.1 创建ASP.NET网站 4.1.2 单文件页模型 4.1.3 代码隐藏页模型 4.1.4 创建ASP.NET Web Application 4.1.5 ASP.NET网站和ASP.NET应用程序的区别...
第4章 ASP.NET的网页代码模型及生命周期 4.1 ASP.NET的网页代码模型 4.1.1 创建ASP.NET网站 4.1.2 单文件页模型 4.1.3 代码隐藏页模型 4.1.4 创建ASP.NET Web Application 4.1.5 ASP.NET网站和ASP.NET应用程序的区别...
第4章 ASP.NET的网页代码模型及生命周期 4.1 ASP.NET的网页代码模型 4.1.1 创建ASP.NET网站 4.1.2 单文件页模型 4.1.3 代码隐藏页模型 4.1.4 创建ASP.NET Web Application 4.1.5 ASP.NET网站和ASP.NET应用程序的区别...
ASP.NET 4.0技术概述、ASP.NET程序的编译模型、将ASP.NET程序开发服务器Port固定的技巧、C# 4.0语言新功能、对象初始化程序、LINQ架构概述、LINQ标准查询运算符、跨页发送、ASP.NET网页指令、My对象的内涵、C# 直接...
包括LINQ在SQL、Data Set、XML和Object等领域的实际应用,WPF动画界面设计,WCF多层数据架构通信、泛型应用、XML文件处理、多线程管理、程序异常拦截、文件压缩及解压缩、文件加密和解密、文件访问权限、API函数调用...
因权限只能到60MB,分卷压缩了,共3个压缩包,需下载完3个一起解压, ============================== ASP.NET 4高级程序设计(第4版)》【原版书为:Pro ASP.NET 4 in C# 2010】是ASP.NET领域的鸿篇巨制,全面讲解了...
2.2.1 解决方案资源管理器 28 2.2.2 文档窗口 29 2.2.3 工具箱 29 2.2.4 错误列表和任务列表 30 2.2.5 服务器资源管理器 31 2.3 代码编辑器 32 2.3.1 添加程序集引用 33 2.3.2 智能感知和大纲显示 ...
实例066 利用选择控件实现权限设置 83 实例067 利用选择控件实现复杂查询 85 2.6 ListView控件应用 87 实例068 ListView控件间的数据移动 87 实例069 将数据库数据添加到ListView控件 90 实例070 在ListView...
实例066 利用选择控件实现权限设置 83 实例067 利用选择控件实现复杂查询 85 2.6 ListView控件应用 87 实例068 ListView控件间的数据移动 87 实例069 将数据库数据添加到ListView控件 90 实例070 在ListView...
实例066 利用选择控件实现权限设置 83 实例067 利用选择控件实现复杂查询 85 2.6 ListView控件应用 87 实例068 ListView控件间的数据移动 87 实例069 将数据库数据添加到ListView控件 90 实例070 在ListView...