在开发Web应用程序时,经常需要处理用户角色和权限。本文将介绍如何使用LINQ(Language Integrated Query)在ASP.NET应用程序中过滤用户角色和权限数据,以提高代码的效率和可读性。
假设有一个Web页面,用于显示应用程序中的用户角色及其权限。
有些权限(如“允许访问站点/用户/角色维护”)没有列出的角色被批准。对于这些角色来说,这些权限是无关紧要的。在页面上显示它们只会混淆用户,并引发支持问题。
目标是过滤掉至少有一个角色未批准的行。这样,就可以确保只显示与用户角色相关的权限,从而避免混淆。
数据是通过ASP.NET的GridView控件显示的,该控件绑定到了一个DataSet对象。为了过滤掉不需要的行,决定在设置GridView的DataSource属性并调用其DataBind方法之前,先过滤DataSet。
GridView的第一列将包含权限描述的字符串,每个后续列将包含一个布尔值,指定该角色是否被批准该权限。从图中不容易看出的是,角色的数量是由数据库驱动的,而不是静态的。如果向应用程序添加另一个角色,这里将添加另一个列,不希望修改代码以适应额外的角色。
以下是调用过滤DataSet的方法的代码:
C# DataSet ds = GetMyRoleData();
FilterRows(ds);
RoleComparisonView.DataSource = ds;
RoleComparisonView.DataBind();
GetMyRoleData是一个虚拟方法,用于获取所需的数据,这里不展示。然后调用FilterRows方法,该方法将删除所有没有角色批准该行权限的DataSet中的行。然后设置GridView的DataSource属性并调用DataBind方法。到目前为止,没有什么特别的。
接下来是实际过滤不需要的行的方法。通过枚举每一行,然后枚举行的每一列,这是非常简单的。如果每一列都设置为false,则删除该行。或者,如果任何列是true,则不删除该行。后者将更有效,因为可以在第一个列有一个true值时停止检查。
但是,与其枚举每一列并检查其值,不如使用LINQ使代码更简单。为什么不使用Any运算符呢?如果行的项目数组中的任何元素是true,那么就不希望删除该行。或者,可以使用All运算符,并确保它们都设置为false,但这将效率更低,需要检查每个项目。使用Any运算符而不是All运算符允许代码在项目是true时停止。
还有一个最后的复杂性,那就是每个DataRow的第一列是一个字符串,用于权限描述,而不是布尔值,用于角色。这可以通过OfType运算符轻松克服。只需在项目数组ItemArray上调用OfType运算符,并指定只返回布尔值类型的元素。就是这么简单。以下是代码:
private void FilterRows(DataSet ds)
{
bool someRoleHasPermission;
foreach (DataRow dr in ds.Tables[0].Rows)
{
someRoleHasPermission = dr.ItemArray.OfType().Any(b => b == true);
if (!someRoleHasPermission)
{
dr.Delete();
}
}
}
枚举DataTable的Rows集合中的每个DataRow。然后,调用行的ItemArray的OfType运算符,以返回布尔值类型的项目。最后,调用Any运算符,并提供一个lambda表达式,如果任何项目设置为true,则返回true。非常简单。然后,如果LINQ查询返回false,调用DataRow的Delete方法。就这样,权限已经被过滤了。