Kandres22
Kandres22

Reputation: 717

System.DirectoryServices.DirectorySearcher caching improvement or FindAll() filtering

I am attempting to improve the performance of a searcher.FindAll() call to an active directory hierarchical group structure.

The code gets a SearchResultCollection of all of a user's groups, it then filters the groups on a search string. The SearchResultCollection collection has about 400 groups in it, and the filtered down version typically comes to 40. I am seeing no benefit from the built in cache during iterative calls (DirectorySearcher.CacheResults = True).

For example, if I call the code below 20 times in a row, the execution time is almost identical.

  1. I have seen this this link DirectorySearcher Filter and understand the DistinguishedName is unavailable for wildcard searching in the Searcher.Filter property (I have confirmed with tests, I would prefer the DirectorySearcher to handle the filtering)
  2. By default the DirectorySearcher object has caching enabled, but does not seem to help at all here (I set it to True anyways)
  3. The documentation states that the DirectorySearcher will decide NOT to cache if there is a large result, any idea what this threshold is?

The below code receives the same penalty for all 400 iterations of the SearchResult every time it executes.

 string groupFilter = "ExampleFilter";
 DirectoryEntry root = GetRootDirectoryEntry();
 string userPath = GetUserPath(username, root);
 var searcher = new DirectorySearcher(root)
 {
    SearchScope = SearchScope.Subtree,
    Filter =  string.Format("(member:XXXX:={0})", userPath) + ""
    //Any wildcard based search for distinguishedname like below returns no results, which is incorrect        
    //Filter =  string.Format("(& (member:XXXX:={0}) (distinguishedname=*{1}) )", userPath, groupFilter)  
 };

 searcher.PropertiesToLoad.Add("Name");
 searcher.PropertiesToLoad.Add("distinguishedname");   
 var groupResults = searcher.FindAll();

 var allFilteredGroups = new HashSet<string>();

 foreach (SearchResult gr in groupResults) //approx 400 in the groupResults, same time penalty for every iteration, every time
 {
      var isRelevant = gr.Path.Contains(groupFilter);
      if (isRelevant)
      {
          //Do Stuff
          allFilteredGroups.Add(value); 
      }
  }

  return allFilteredGroups.ToList(); //approx 40

Why does the cache not offer any improvements? Any suggestions on how I could reduce the penalty for iterating all of these groups I know I do not want?

Upvotes: 0

Views: 733

Answers (1)

Gabriel Luci
Gabriel Luci

Reputation: 41008

I assume you are trying to only include groups from a specific OU?

You are correct that you cannot filter by a partial distinguishedName. You can, however, search only in one specific OU by modifying the SearchRoot that you pass to DirectorySearcher. For example:

DirectoryEntry root = new DirectoryEntry("LDAP://OU=MyGroups,DC=example,DC=com");

That DirectoryEntry points to the MyGroups OU. So if you pass that to DirectorySearcher, then it will only search in that OU.

You can also set SearchScope to OneLevel if you don't want it to search the child OUs. Subtree is the default, so if that's what you want, you don't need to set it at all.

Even if you want to find groups in multiple OUs, you may be better off repeating the search for each OU you want, rather than asking for everything and discarding most of the results.

Upvotes: 0

Related Questions