从 DirectoryServices 检索全局地址列表非常慢
Retrieving Global Address List from DirectoryServices is Extremely Slow
以下代码允许我从 DirectoryServices 中提取整个全局地址列表。该代码的功能在于它为我提供了我需要的东西。问题是 return 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; }
}
从您的代码中我可以看出您正在 return 填写一个完整的列表。您可以修改此方法以在识别出值后立即生成 return 值。为此,将 return 类型从 List 更改为 Ienumerable,然后删除 returning 列表以及您添加到该列表的位置 return 新创建的对象 return
dotnetperls 对 yield 语句有很好的定义。
你会有这样的东西...
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 已接受的答案。
事实证明问题出在 GetDirectoryEntry() 上。显然,使用它会占用大量资源,因为它允许您在检索目录条目后实际更新它。换句话说,每次调用它都会在每次调用时额外调用活动目录。我只需要 access/read 属性而不更新它们,所以我重写了没有 GetDirectoryEntry() 的方法。它现在 returns 整个全球地址列表立即。解决我问题的代码如下。
[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;
}
}
以下代码允许我从 DirectoryServices 中提取整个全局地址列表。该代码的功能在于它为我提供了我需要的东西。问题是 return 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; }
}
从您的代码中我可以看出您正在 return 填写一个完整的列表。您可以修改此方法以在识别出值后立即生成 return 值。为此,将 return 类型从 List 更改为 Ienumerable,然后删除 returning 列表以及您添加到该列表的位置 return 新创建的对象 return
dotnetperls 对 yield 语句有很好的定义。
你会有这样的东西...
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 已接受的答案。
事实证明问题出在 GetDirectoryEntry() 上。显然,使用它会占用大量资源,因为它允许您在检索目录条目后实际更新它。换句话说,每次调用它都会在每次调用时额外调用活动目录。我只需要 access/read 属性而不更新它们,所以我重写了没有 GetDirectoryEntry() 的方法。它现在 returns 整个全球地址列表立即。解决我问题的代码如下。
[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;
}
}