根据这篇文章:DirectorySearcher.FindAll() - 应该有 PageSize=1000
SizeLimit
在这种情况下无关紧要,因为正在使用服务器端默认值,默认值为 1000 个结果。我从来不需要这样的页面,但我想使用最小大小限制(在您的大小限制和服务器大小限制之间 - 刚刚在我自己的 AD 中测试过)。您PageSize
确实在分页,但是它在后台进行分页并仅返回最终流,据我所知,这就是您获得所有结果的原因。
我相信您最简单的解决方案是在此之上使用 Linq 并执行.Take(2000)
结果。这将以额外的带宽和服务器上的处理为代价获得您想要的结果。
如果您真的想对其进行排序,我想您将不得不将服务器的默认分页大小更新为更高(尽管出于管理原因我怀疑这是否可行)。
编辑:
以下是我粗略处理的方法(来自我的 LinqPad 的快速工作示例代码 - 另请注意,我实际上带来了一切,这与您可能希望通过将 for 循环排除在等式之外):
using(DirectoryEntry de = new DirectoryEntry("LDAP://domain.local/dc=domain,dc=local", "user", "password"))
using(DirectorySearcher ds = new DirectorySearcher(de))
{
ds.Filter="(&(objectCategory=user)(objectClass=user))";
ds.PageSize= 1000;
ds.PropertiesToLoad.Clear();
ds.PropertiesToLoad.Add("objectGuid");
var results = ds.FindAll();
var searchResults = results.Cast<System.DirectoryServices.SearchResult>().ToArray();
int myDesiredPageSize = 2000;
var upns = new StringCollection();
for(var step=0; step < Math.Ceiling((double)results.Count / myDesiredPageSize); step++)
{
Parallel.ForEach(searchResults.Skip(step*myDesiredPageSize).Take(myDesiredPageSize), result => {
using(var entry = result.GetDirectoryEntry())
{
entry.RefreshCache(new[]{ "userPrincipalName" });
if(entry.Properties.Contains("userPrincipalName"))
upns.Add(entry.Properties["userPrincipalName"][0] as string);
}
});
}
upns.Count.Dump();
}
这在我的测试场景中通过我的局域网连接在大约 3 秒内返回大约 1400 个结果。由于我们正在并行查询更高的数字,因此不应线性扩展。此外,您可能希望在某种程度上包含并行化,因为这会无情地打击 AD :)
在我的正常操作中,我使用带有WhenChanged
AD 对象属性的缓存来将我的实际查询减少到仅更改的对象,而不是一遍又一遍地加载相同的东西,这只会在第一次被击中,随后的结果是几分之一秒。采用这种方法,您可以完全取消分页,只需在启动时加载您的属性,然后如果可以选择仅提取更改的条目。