开发者

Retrieve AD Custom Attribute in One Batch

Is it possible to use the System.DirectoryServices.AccountManagement library and the PrincipalSearcher class to retrieve a custom attribute for all Principals returned from the call to FindAll()?

I'm currently using this example: http://msdn.microsoft.com/en-us/library/bb552835%28v=vs.90%29.aspx.

However, when accessing my custom property/attribute, it seems to be making an additional trip to the AD store. I would like it t开发者_如何学编程o eagerly load this property at the initial call to FindAll().


Yes, it is possible to eagerly load the custom attribute for all principals at the initial call to FindAll(). You only have to specify your custom attributes as described in the Microsoft sample using [DirectoryProperty("YOUR_PROP_NAME")] attribute.

By accessing the underlying DirectorySearcher's property PropertiesToLoad using the GetUnderlyingSearcher() method of the UserPrincipal class you can see that your custom attribute is included in the collection of properties to load. You can examine the PropertiesToLoad collection in the debugger.

On my machine the collection contains a total of 68 properties.

And here begins the problem and the performance penalty. The more properties are included in this collection the more round trips to Active Directory are necessary to retrieve them.

I did some performance tests:

Using the Microsoft sample to retrieve 200 InetOrgPerson objects took about 500ms.

Using the DirectorySearcher class directly and only requesting the properties of interest took only 70ms (see sample below).

using (DirectoryEntry e = new DirectoryEntry("LDAP://server10/CN=users,DC=treyresearch,DC=net", 
                                         "treyresearch\\administrator", "P@$$W0rd", AuthenticationTypes.FastBind | AuthenticationTypes.Secure))
  {
    using (DirectorySearcher ds = new DirectorySearcher(e, "(&(objectCategory=inetorgperson)(logonCount=0))"))
    {
      ds.SearchScope = SearchScope.OneLevel;
      ds.PropertiesToLoad.Clear();
      ds.PropertiesToLoad.Add("logonCount");
      ds.PropertiesToLoad.Add("sAMAccountName");


      Stopwatch sw = new Stopwatch();
      sw.Start();
      int countPerson = 0;
      using (SearchResultCollection searchResultCol = ds.FindAll())
      {
        foreach (SearchResult sr in searchResultCol)
        {
          ResultPropertyValueCollection propCol = sr.Properties["logonCount"];

          if (propCol.Count > 0)
          {
            countPerson++;
            object cou = propCol[0];
          }
        }
        sw.Stop();
        Console.Out.WriteLine(sw.ElapsedMilliseconds);
        Console.Out.WriteLine(countPerson);
      }
    }
  }

By the same token I've used objectCategory in the search filter instead of objectClass because objectCategory is a so called indexed property. Accessing indexed properties is faster than accessing non indexed properties.

Furthermore I've specified AuthenticationTypes.FastBind to improve performance.

To further improve performance see this article on MSDN describing how to create efficient search queries.

To summarize, using DirectorySearcher class and specifing only the properties you are interested in creatly improves the performance of your search (reducing round trips to Active Directory).

Hope, this helps.


Yes, you can; Cast GetUnderlyingObject() for each Principal object to DirectoryEntry, then you may access the custom attribute like oDE.Properties[YOUR_CUSTOM_ATTRIBUTE].Value.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜