More Active Directory nonsense

Published 11.03.2006 by ~mattg

Apparently, implementing an active directory connector for tens of thousands of users isn’t as easy as we had initially anticipated. Once we got through the basics of paging, we came to find that populating our keyset was taking about 10 minutes for 20,000 users, which is not acceptable.

As it turns out, I had no idea what I was doing. Our code used three classes to retrieve data from Active Directory:

  1. DirectorySearcher
  2. DirectoryEntry
  3. SearchResults (and SearchResultCollection)

The basic idea is simple: Create a DirectoryEntry that points to the top node of your AD structure, then use the DirectorySearcher (along with it’s filter and sort properties) to retrieve a SearchResultCollection full of SearchResult objects.

Our problem was we didn’t know what the SearchResult contained. We mistakenly thought it was simply a reference to a DirectoryEntry object. So, for example, our code to retrieve only a list of objectGUIDs looked like this:

using (DirectoryEntry directoryEntry = GetMyDirectoryEntry())
{
     using (DirectorySearcher directorySearcher = new DirectorySearcher(directoryEntry))
     {
          // Set our object filter and sorting here.
         directorySearcher.Filter = “(objectClass=user)”;
         directorySearcher.PropertiesToLoad.Add(“objectGUID”);
         directorySearcher.Sort.PropertyName = “sAMAccountName”;
         
          using (SearchResultCollection collectionResults = directorySearcher.FindAll())
          {
               foreach (SearchResult result in collectionResults)
               {
                    using (DirectoryEntry entry = result.GetDirectoryEntry())
                    {
                         listItems.Add(entry.Guid);
                    }
               }
          }
     }
}

The problem with this code is that result.GetDirectoryEntry() goes back to the server to get the live entry. Doing so over 20,000 SearchResults (which is our current testing size) is slow. So to speed it up, we replaced the inside of the foreach SearchResult result in collectionResults with the following code:

Guid guid = Guid.Empty;
     try
     {
          guid = new Guid((byte[]) result.Properties[“objectGUID”][0]);
     }
     catch (Exception ex)
     {
          System.Diagnostics.Debug.Assert(false, ex.Message);
          guid = Guid.Empty;
     }
     if (!guid.Equals(Guid.Empty)
          listItems.Add(guid);

That sped things up a little, but it was still taking a long time. It took us a bit of messing with the PageSize and SizeLimit values to determine that we had to make the PageSize rather large (I think we set it to 1000) to ensure that, as we iterate ove the SearchResultCollection, things don’t slow down. There is still some improvement to be made, but we’ve made a lot of improvement over the old system.

Filed under .NET Development

Comments (0)

Comments RSS - Trackback - Write Comment

No comments yet

Write Comment