原文及代码:
http://www.wimdows.net/articles/article.aspx?aid=13Active Directories Services Interface (ADSI) has always been a very effective way of dealing with users in a Windows network. As expected .NET reintroduced ADSI classes in Directory Services namespace which enables programmers to access ADSI objects using this single user interface.
This article aims to show how to view these objects in ASP.NET by using direct output to HTML or displaying in a DataGrid.Firstly we need to understand that everything in Active Directory can be considered to be an entry and each entry may be containers for other entries.
As you can see the entry Users is a container for groups and users of a Domain. The class DirectoryEntry in DirectoryServices namespace can be instantiated in order to point to a specific location in a Active directories folder:<% @Import Namespace="System.DirectoryServices" %>
<%
DirectoryEntry de = new DirectoryEntry("LDAP://CN=Users,DC=VBOX,DC=DEV,DC=AU" ,"administrator","client");
foreach(DirectoryEntry child in de.Children)

Response.Write("<BR>" + child.Name.ToString()); 
}
%>
 As we can see this entry will point to Users container by using a LDAP (Lightweight Directory Access Protocol) path with the proper username and password.
Once the object is instantiated we can iterate and access it’s members
Getting the following output:
With the last example we have child objects from the LDAP path provided which includes Security users and Groups. Further more we understand that we can filter these objects in order to distinguish between Groups and Users by implementing rudimentary selection against these objects but DirectoryServices exposes another class called DirectorySearcher that can elegantly find specific objects against a directory entry as followed:<% @Import Namespace="System.DirectoryServices" %>
<%
DirectoryEntry de = new DirectoryEntry("LDAP://CN=Users,DC=VBOX,DC=DEV,DC=AU" ,"administrator","client");
//New Directory Searcher object
DirectorySearcher src = new DirectorySearcher("(&(objectCategory=Person)(objectClass=user))");
//Point the Root search to the previous directory entry.
src.SearchRoot = de;
//Narrow the search scope to current subtree.
src.SearchScope = SearchScope.Subtree;
//Do the right thing.
foreach(SearchResult res in src.FindAll())
{
  Response.Write(res.Properties["Name"][0] + "<BR>");
}
%>
 With a DirectorySearcher instance we can perform a query to a directory entry specifying the entry we want to be pointing to then choose the type of search scope and safely getting all desired output by iterating the FindAll() method that returns all objects from the search query where is supposed to be objects with criteria of ObjectCategory of “Person” and ObjectClass “user”, printing only the property “Name” of these objects:It will be very handy to have a more sophisticated approach (or .NET oriented approach) to view ADSI objects, it can be in a WebControls such as Listbox or even Labels. Here will explore the possibility of a DataGrid control that will be bound to a DataSet pre-populated with ADSI information.Will start by adding two DataGrid to a ASP.NET one for master for the user object names and the second one to display its properties. The first DataGrid we add a column for select the row that will have properties in the details DataGrid.
Then we start with the code behind:private void createTable()
{
//DataTable for users
  DataTable tbUsers = new DataTable("users");
  //Create Columns for DataTable.
  tbUsers.Columns.Add("UserName",System.Type.GetType("System.String"));
  ds.Tables.Add(tbUsers);
  //DataTable for properties
  DataTable tbProperties = new DataTable("properties");
  //Create Columns for DataTable.
  tbProperties.Columns.Add("PropertyName",System.Type.GetType("System.String"));
  tbProperties.Columns.Add("PropertyValue",System.Type.GetType("System.String"));
  ds.Tables.Add(tbProperties);
}
 This method will merely create custom tables into a protected allocated DataSet named ds.On page load we add the following code:
DirectorySearcher src = new DirectorySearcher("(&(objectCategory=Person)(objectClass=user))");
createTable();
src.SearchRoot = de;
src.SearchScope = SearchScope.Subtree;
  
foreach(SearchResult res in src.FindAll())
{
  DataRow topRow = ds.Tables["users"].NewRow();
  topRow["UserName"] =res.Properties["Name"][0];
  ds.Tables["users"].Rows.Add(topRow);
}  
DataGrid1.DataSource = ds.Tables["users"];
DataGrid1.DataBind();
 Self explanatory at this point except for the way we hash across the properties collection extracting the values adding into the table.Now for displaying the detailed information about the properties in the details grid we add the following code at the event SelectedIndexChanged where will be fired when the selected button (or link) is clicked.
private void DataGrid1_SelectedIndexChanged(object sender, System.EventArgs e)
{
DirectorySearcher src = new DirectorySearcher("(&(objectCategory=Person)" +
      "(objectClass=user)(Name=" + DataGrid1.SelectedItem.Cells[1].Text + "))");
src.SearchRoot = de;
src.SearchScope = SearchScope.Subtree;
  
foreach(SearchResult res in src.FindAll())
{
IDictionaryEnumerator ien = res.Properties.GetEnumerator();
while(ien.MoveNext())
  {
    DataRow dt = ds.Tables["properties"].NewRow();
    dt["PropertyName"] =ien.Key.ToString();
    dt["PropertyValue"] = res.Properties[ien.Key.ToString()][0];
    ds.Tables["properties"].Rows.Add(dt);
}
}
DataGrid2.DataSource = ds.Tables["properties"];
DataGrid2.DataBind();
}
 Different from the previous method we need to hash across the properties IColletion in order to gather the object specific property name and value adding it to the detail grid:When selected the details grid will populate and show a huge amount of property names and values.Conclusion
For a simple administration tool ASP.NET exposes very important and necessary classes to manipulate LDAP specific Directories such as IIS, Exchange Server, Active Directory, etc…
Further functionality can be implemented to add, update and delete these objects.