Search code examples
c#.netdirectoryservicesdirectorysearcher

Retrieving Global Address List from DirectoryServices is Extremely Slow


The following code allows me to extract the entire Global Address List from DirectoryServices. The code is functional in that it gives me what I need. The problem is that it takes about 20 seconds to return 1000 objects. Is there anything that I can do to speed this up?

    public static List<Address> GetGlobalAddressList()
    {
        using (var searcher = new DirectorySearcher())
        {
            using (var entry = new DirectoryEntry(searcher.SearchRoot.Path, "*****", "*****"))
            {
                searcher.Filter = "(&(mailnickname=*)(objectClass=user))";
                searcher.PropertiesToLoad.Add("cn");
                searcher.PropertyNamesOnly = true;
                searcher.SearchScope = SearchScope.Subtree;
                searcher.Sort.Direction = SortDirection.Ascending;
                searcher.Sort.PropertyName = "cn";
                var results = searcher.FindAll();
                var addressList = new List<Address>();
                foreach (SearchResult i in results)
                {
                    var address = new Address
                    {
                        DisplayName = (string)i.GetDirectoryEntry().Properties["displayName"].Value,
                        Mail = (string) i.GetDirectoryEntry().Properties["mail"].Value
                    };
                    addressList.Add(address);

                }
                return addressList;
            }
        }
    }

    public class Address
    {
        public string DisplayName { get; set; }
        public string Mail { get; set; }

    }

Solution

  • It turns out that GetDirectoryEntry() is the problem. Apparently using it is very resource intensive because it allows you to actually update the Directory entry after retrieving it. In other words, every call to it does an additional call to active directory every time it is called. I just need to access/read the properties not update them, so I rewrote the method without GetDirectoryEntry(). It now returns the entire global address list instantly. The code that solved my problem is below.

        [WebMethod()]
        public static List<Address> GetAddresses()
        {
            using (var objsearch = new DirectorySearcher())
            {
                objsearch.Filter = "(& (mailnickname=*)(objectClass=user))";
                objsearch.SearchScope = SearchScope.Subtree;
                objsearch.PropertiesToLoad.Add("cn");                
                objsearch.PropertiesToLoad.Add("mail");
                objsearch.PropertyNamesOnly = false;
                objsearch.Sort.Direction = SortDirection.Ascending;
                objsearch.Sort.PropertyName = "cn";
                objsearch.PageSize = 5000;
                var colresults = objsearch.FindAll();
                var addressList = new List<Address>();
                foreach (SearchResult objresult in colresults)
                {
                    var address = new Address();
    
                    var cn = objresult.Properties["cn"];
                    if (cn.Count >= 1) address.DisplayName = (cn[0]) as string;
    
                    var mail = objresult.Properties["mail"];
                    if (mail.Count >= 1) address.Mail = (mail[0]) as string;
    
                    addressList.Add(address);
                }
                return addressList;
            }
    
        }