从DirectoryServices检索全局地址列表非常慢

时间:2015-08-20 21:22:49

标签: c# .net directoryservices directorysearcher

以下代码允许我从DirectoryServices中提取整个全局地址列表。代码是功能性的,因为它给了我我需要的东西。问题是返回1000个对象大约需要20秒。我有什么办法可以加快速度吗?

    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; }

    }

2 个答案:

答案 0 :(得分:0)

从您的代码中我可以看到您正在返回一个完全填充的列表。您可以在识别后立即修改此方法以获得返回值。要执行此操作,请将返回类型从List更改为Ienumerable,然后删除返回列表以及您添加到该列表的位置返回带有yeild return的新创建的对象

dotnetperls对于yeild语句有一个很好的定义。

你会有类似的东西......

public static IEnumerable<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";

            foreach (SearchResult i in searcher.FindAll())
            {
                var address = new Address
                {
                    DisplayName = (string)i.GetDirectoryEntry().Properties["displayName"].Value,
                    Mail = (string) i.GetDirectoryEntry().Properties["mail"].Value
                };
                yeild return address;
            }
        }
    }
}

您还应该查看Joes已接受的答案。

答案 1 :(得分:0)

事实证明GetDirectoryEntry()是问题所在。显然使用它是非常耗费资源的,因为它允许您在检索后实际更新Directory条目。换句话说,每次调用它都会在每次调用时对Active Directory进行额外调用。我只需要访问/读取属性而不更新它们,所以我重写了没有GetDirectoryEntry()的方法。它现在立即返回整个全局地址列表。解决我问题的代码如下。

    [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;
        }

    }