你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 编程语言
2.18 在.NET环境下用Treeview遍历活动目录
 

微软活动目录是管理网络资源的一种有效技术,它使用户、系统管理员和应用程序开发者能以前所未有的方法使用操作系统,进一步模糊各网络之间的界限,提供了一种针对网络资源安全可靠、方便快捷的全新概念的综合管理工具;与此同时,信息化的今天,网络资源的浏览和操作离不开Web技术,它具有信息共享高、易用性、易维护和安全性好的优点,是互联网的主流技术;假如把活动目录和 Web 技术相互结合,必能使网络应用上新台阶。

一、活动目录

活动目录(Active Directory)是面向Windows Standard ServerWindows Enterprise Server以及 Windows Datacenter Server的目录服务。

Active Directory存储了有关网络对象的信息,并且让管理员和用户能够轻松地查找和使用这些信息,使用了一种结构化的数据存储方式,并以此作为基础对目录信息进行合乎逻辑的分层组织。

Active Directory支持标准的LDAP(轻型目录访问协议),它是一种工业标准服务协议,在大多数平台和大多数开发语言中都可以进行访问。

活动目录是存储用户信息、打印机、网络服务和定制数据的目录服务,它是一个树型结构,树枝为组织单元(OU),它可以是国家、公司和组织等,而树叶是对象(CN),它可以是组、用户和网络资源等,组织单元可以包括组织单元和树叶;一个对象可有多个属性,属性包括:姓名、电话号码和单位等。组可包括不同组织单元的多个用户,这些都可实现文件和URL授权的判断条件。

二、TreeView控件

树形图用于显示按照树形结构进行组织的数据,其用途比较广泛,如计算机中的文件系统(Windows中的资源管理器)、企业或公司的组成结构等。在WindowsVBPBDelphi等工具提供了一个功能很强的树型控件TreeView,利用Treeview控件可以方便地开发树形图。然而在网页上实现树形图就不那么容易了,现在在ASP.NET中利用微软提供的Internet  Explorer  WebControls使得网页上的树形图开发与在Windows下一样方便,甚至更灵活。

三、访问活动目录

.NET中,微软为我们提供了System.DirectoryServices命名空间,它使用了活动目录服务接口(ADSI)。 ADSI是通过编程与许多不同的目录服务提供者交互的方式,也就是一种编程接口。

DirectoryEntry System.DirectoryServices 命名空间中最有用的一个类。它的实例代表活动目录中的对象,DirectorySearcher 主要用于属性的搜索。

通过LDAP协议的方式连接到活动目录中:

DirectoryEntry entry1 = new DirectoryEntry("LDAP://ptr.petrochina/ OU=第四采油厂,OU=大庆油田有限责任公司,OU=大庆油田,DC=ptr,DC=petrochin ", mailuser, passwd, AuthenticationTypes.ServerBind);

其中DCDomain Component(域组件)的缩写,它只用于表示域的根。OUOrganizational Unit(组织单元)的缩写。OU是容器对象,它主要从逻辑的角度来管理和组织活动目录域。AuthenticationTypes是连接到活动目录的认证方式,这里使用的是AuthenticationTypes.ServerBind的方式。

下面是一个获取某个OU节点下所有的组织单元和用户的例子:

public static void GetAll()

 {

            DirectoryEntry entry = new DirectoryEntry("domainADsPath");

            DirectorySearcher mySearcher = new DirectorySearcher(entry);

// mySearcher.Filter   =   ("(objectClass=organizationalUnit)"); 

// 查询条件是所有的组织单元

            mySearcher.Filter = "(|(objectClass=user)(objectClass=organizationalUnit))";

           mySearcher.PageSize = 20000;

            foreach(SearchResult resEnt in mySearcher.FindAll())

             {

Response.Write ("  <b>Name:</b> "+resEnt.GetDirectoryEntry().Name.ToString());

Response.Write ("  <b>Path: </b> +resEnt.GetDirectoryEntry().Path.ToString()+"<br>");

}

  }

参数domainADsPath是活动目录的域名,使用类似“LDAP://域名”的形式, mySearcher.Filter是过滤条件,基本上有以下三个选择:

1. objectClass=organizationalUnit   查询条件是所有的组织单元(OU

2. objectClass=group   查询条件是所有的组(GROUP  

3. objectClass=user   查询条件是所有的用户(USER 

而且mySearcher.Filter支持多种条件的组合,如本文中的例子"(|(objectClass=user)(objectClass=organizationalUnit))"是查询所有的用户和组织单元,注意这个表达式的写法,逻辑运算符是前置的。

mySearcher.PageSize = 20000此参数可以任意设置,但不能不设置,如不设置读取AD数据最多为999条数据,设置后可以读取大于1000条数据。

这样读取出活动目录上某一节点的一些属性,如name(姓名)、 mail(邮箱)、samaccountname(帐号)等信息。把这些信息读出后,可以通过遍历的方式捆绑到Treeview的节点上。

四、Treeview的生成

为了生成Treeview的树形结构,必须再从上面节点读取到的属性中,构造一个可以构造Treeview中父子节点关系的字段,经过测试找到了distinguishedname这个属性。Distinguishedname中存放的是从活动目录根节点到当前节点的组织单元,使用逗号进行分割。可以看出下面例子的节点是一个叫信息中心的组织单元,它的上级节点是第四采油厂。

distinguishedname =

OU=信息中心,OU=第四采油厂,OU=大庆油田有限责任公司,OU=大庆油田,DC=ptr,DC=petrochina

通过构造截取字符串的函数,可以把一个节点的父节点的信息取道,通过一个递归的函数,可以找到这个父节点,这样在遍历活动目录的同时,把当前的节点不断地插入到Treeview中,最后就生成了Treeview的树形结构了。实现的核心代码如下:

// 设置Treeview根节点,就是遍历活动目录开始的起点

// path 是根节点的distinguishedname

    path = "OU=第四采油厂,OU=大庆油田有限责任公司,OU=大庆油田,DC=ptr,DC=petrochina";

    string root=path.Split(',')[0].ToString().Substring(3);

    TreeNode node1 = new TreeNode();

    node1.Text = root;

    node1.NodeData=path;

    node1.ImageUrl="images/folder.gif";

    node1.ExpandedImageUrl="images/folderopen.gif";

    ADTree.Nodes.Add(node1);   // ADTree 是我们定义的 Treeview

    ADTree.ExpandLevel = 1;  // 展开树

// 把组织单元和用户节点捆绑到Treeview

public void GetAll()

{

  System.DirectoryServices.DirectoryEntry   entry   =   new   System.DirectoryServices.DirectoryEntry("LDAP://ptr.petrochina/"   +   path, mailuser, passwd, AuthenticationTypes.ServerBind);

System.DirectoryServices.DirectorySearcher   mySearcher =  new   System.DirectoryServices.DirectorySearcher(entry);  

mySearcher.Filter   =   "(|(objectClass=user)(objectClass=organizationalUnit))";

    mySearcher.PageSize = 20000;

foreach(System.DirectoryServices.SearchResult   resEnt   in   mySearcher.FindAll())  

{  

System.DirectoryServices.DirectoryEntry   de=resEnt.GetDirectoryEntry();  

       string test=de.Properties["distinguishedname"].Value.ToString();

       string fjdstr=test.Substring(test.Split(',')[0].ToString().Length+1);

        TreeNode tmpNd = new TreeNode();

        tmpNd.Text=de.Properties["name"].Value.ToString();

      //  NodeData 属性中存放 当前节点的distinguishedname的值

        tmpNd.NodeData=test;

// 通过objectcategory属性判断节点是组织单元还是用户,并设置不同的Treeview节点显示图片

if ( de.Properties["objectcategory"].Value.ToString().Split(',')[0].ToString()=="CN=Organizational-Unit" )

    {

    tmpNd.ImageUrl="images/folder.gif";

    tmpNd.ExpandedImageUrl="images/folderopen.gif";

    }

    else

    {

        tmpNd.ImageUrl="images/user.gif";

        tmpNd.ExpandedImageUrl="images/user.gif";

    }              

   // 递归遍历Treeview找当前节点的父节点,把当前节点插入到Treeview

try 

{

FindNode(ADTree.Nodes[0],fjdstr).Nodes.Add(tmpNd);

}

    catch(Exception   e)  

    {

   }  

}  

}

截取当前节点的父节点的方法是,先用Split()函数把distinguishedname属性按逗号分割成几段,test.Split(',')[0].ToString().Length是当前节点第一逗号前的长度,加上后面的逗号,所以开始截取字符串的长度是test.Split(‘,')[0].ToString().Length+1,使用截取字符串函数Substring(),很容易就找到当前节点的父节点了。

在上面的代码中使用了一个寻找父节点的递归函数FindNode(ADTree.Nodes[0],fjdstr),这个函数使用了深度优先算法,其原理是截取 distinguishedname属性的字符串,获取到上级节点的distinguishedname值,通过比较存放在TreeNode节点上NodeData中的distinguishedname值,找到当前节点的父节点,递归函数返回当前节点的父节点,通过Nodes.Add()的方法把当前节点插入到父节点下。

// 查找到父节点的递归函数

private TreeNode FindNode( TreeNode tnParent, string strValue)

{

    if( tnParent == null ) return null;

        if( tnParent.NodeData.ToString() == strValue )  return tnParent;

            TreeNode tnRet = null;

        foreach( TreeNode tn in tnParent.Nodes )

        {

           tnRet = FindNode( tn, strValue);

           if( tnRet != null ) break;

        }

        return tnRet;

}

应用上面的算法,可以得到一个包含组织单元和用户的树型结构,下图是程序运行结果的演示。


五、结语

本文给出了一个利用活动目录节点的属性生成Treeview结构的算法,这个算法利用截取活动目录节点中的distinguishedname属性,获得上层的父节点的distinguishedname属性,然后通过递归的方法找到Treeview中父节点,然后把当前节点都插入到Treeview中。所给出程序在遍历活动目录节点数不多的时候,速度还可以,但遍历一个大型的活动目录,如果有上千个节点的时候,效率就会很低,因为在Treeview中每查找一个节点就要遍历一次整个Treeview。所以在生成Treeview的算法上还应有更高效的方法,比如可以把活动目录节点的属性读出后,把满足生成Treeview的字段放到数据库中,最后由数据库生成Treeview

 

 

 

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089