所以我基本上是在尝试枚举 AD 的结果,由于某种原因我无法提取新结果,这意味着它会不断提取前 1500 个结果,即使我告诉它我想要一个额外的范围。
有人可以指出我在哪里犯了错误吗?代码永远不会跳出循环,但更重要的是,即使我说我想要用户 1500-3000,它也会吸引 1-1500 的用户。
uint rangeStep = 1500;
uint rangeLow = 0;
uint rangeHigh = rangeLow + (rangeStep - 1);
bool lastQuery = false;
bool quitLoop = false;
do
{
string attributeWithRange;
if (!lastQuery)
{
attributeWithRange = String.Format("member;Range={0}-{1}", rangeLow, rangeHigh);
}
else
{
attributeWithRange = String.Format("member;Range={0}-*", rangeLow);
}
DirectoryEntry dEntryhighlevel = new DirectoryEntry("LDAP://OU=C,OU=x,DC=h,DC=nt");
DirectorySearcher dSeacher = new DirectorySearcher(dEntryhighlevel,"(&(objectClass=user)(memberof=CN=Users,OU=t,OU=s,OU=x,DC=h,DC=nt))",new string[] {attributeWithRange});
dSeacher.PropertiesToLoad.Add("givenname");
dSeacher.PropertiesToLoad.Add("sn");
dSeacher.PropertiesToLoad.Add("samAccountName");
dSeacher.PropertiesToLoad.Add("mail");
dSeacher.PageSize = 1500;
SearchResultCollection resultCollection = resultCollection = dSeacher.FindAll();
dSeacher.Dispose();
foreach (SearchResult userResults in resultCollection)
{
string Last_Name = userResults.Properties["sn"][0].ToString();
string First_Name = userResults.Properties["givenname"][0].ToString();
string userName = userResults.Properties["samAccountName"][0].ToString();
string Email_Address = userResults.Properties["mail"][0].ToString();
OriginalList.Add(Last_Name + "|" + First_Name + "|" + userName + "|" + Email_Address);
}
if(resultCollection.Count == 1500)
{
lastQuery = true;
rangeLow = rangeHigh + 1;
rangeHigh = rangeLow + (rangeStep - 1);
}
else
{
quitLoop = true;
}
}
while (!quitLoop);
你混淆了两个概念,这是给你带来麻烦的原因。这是 SO 论坛上的一个常见问题解答,所以我可能应该写博客来尝试把事情弄清楚。
让我先解释一下概念,然后在概念出来后更正代码。
概念一是获取大量对象。当你取到很多对象时,你需要分批去取。 这通常称为 paging 通过结果。当您执行此操作时,您将取回一个分页 cookie,并可以在后续搜索中传回分页控件,以便每次通过时都能获得“页面价值”的结果。
第二个概念是从单个属性中获取大量值。一个简单的例子是从一个组中读取成员属性(例如:对该组进行基本搜索)。 这叫做远程检索。在这种搜索模式下,您正在针对大型属性(如成员)对该对象进行基本搜索,并在每次通过搜索时询问值的“范围”。
上面的代码混淆了这些概念。您正在执行成员范围逻辑,就像您正在执行范围检索一样,但实际上您正在执行一个搜索,该搜索被构造为返回大量对象,如分页搜索。这就是为什么你一遍又一遍地得到相同的结果。
要解决这个问题,您需要先选择一种方法。 :) 我建议针对组对象进行范围检索,并要求范围中的大成员属性。这将使您获得该组中的所有成员。 如果沿着这条路走下去,您会注意到您不能为这些值请求属性。您获得的唯一值是成员列表,然后您可以搜索他们。 如果您选择像上面那样使用分页搜索,那么您最终会切换到分页搜索。
如果您选择坚持分页搜索,那么您需要:
如果您选择范围,您将从这样的 memberOf 搜索切换到以下形式的搜索:
范围:基地
过滤器:(对象类=*)
基础 DN:OU=C,OU=x,DC=h,DC=nt
属性:成员;范围=0-*...
然后您将在获取值范围时递增 0(即,对每个后续值范围反复执行此搜索,仅将 0 更改为后续整数)
您会在我的逻辑中注意到的其他要点:
我希望这能完全回答...
根据我在下面的评论,这是进行分页搜索 的代码片段(这是您使用 System.DirectoryServices.Protocols 命名空间类需要执行的操作,沿着您在上面开始的逻辑路径(分页搜索, 不是远程检索)):
string searchFilter = "(&(objectClass=user)(memberof=CN=Users,OU=t,OU=s,OU=x,DC=h,DC=nt))";
string baseDN = "OU=C,OU=x,DC=h,DC=nt";
var scope = SearchScope.Subtree;
var attributeList = new string[] { "givenname", "sn", "samAccountName", "mail" };
PageResultRequestControl pageSearchControl = new PageResultRequestControl(1000);
do
{
SearchRequest sr = new SearchRequest(baseDN, searchFilter, scope, attributeList);
sr.Controls.Add(pageSearchControl);
var directoryResponse = ldapConnection.SendRequest(sr);
if (directoryResponse.ResultCode != ResultCode.Success)
{
// Handle error
}
var searchResponse = (SearchResponse)directoryResponse;
pageSearchControl = null; // Reset!
foreach (var control in searchResponse.Controls)
{
if (control is PageResultResponseControl)
{
var prrc = (PageResultResponseControl)control;
if (prrc.Cookie.Length > 0)
{
pageSearchControl = new PageResultRequestControl(prrc.Cookie);
}
}
}
foreach (var entry in searchResponse.Entries)
{
// Handle the search result entry
}
} while (pageSearchControl != null);
您的问题是由循环创建目录搜索器的新对象引起的。每次都会有新对象获取前 1500 条记录。在循环外创建搜索器实例,并对所有查询使用相同的实例。