1

下面的代码允许我从 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; }

    }
4

2 回答 2

0

事实证明 GetDirectoryEntry() 是问题所在。显然使用它是非常耗费资源的,因为它允许您在检索目录条目后实际更新它。换句话说,每次调用它都会对 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;
        }

    }
于 2015-08-24T14:27:55.930 回答
0

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

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接受的答案。

于 2015-08-20T21:57:22.970 回答