2

所以我基本上是在尝试枚举 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);
4

2 回答 2

1

你混淆了两个概念,这就是给你带来麻烦的原因。这是 SO 论坛上的常见问题解答,因此我可能应该在此发表博客以尝试解决问题。

让我先解释一下概念,然后在概念出现后更正代码。

概念一是获取大量对象。当您获取大量对象时,您需要批量请求它们。这通常称为对结果的“分页”。当您执行此操作时,您将返回一个分页 cookie,并且可以在后续搜索中将分页控件传回,以便每次传递都获得“页面价值”的结果。

第二个概念是从单个属性中获取大量值。一个简单的例子是从组中读取成员属性(例如:对该组进行基本搜索)。这称为“远程检索”。在这种搜索模式下,您正在对该对象进行基本搜索以查找大属性(如成员),并在每次通过搜索时询问值的“范围”。

上面的代码混淆了这些概念。您正在执行成员范围逻辑,就像您正在执行范围检索一样,但实际上您正在执行构建为返回大量对象的搜索,例如分页搜索。这就是为什么您一遍又一遍地获得相同结果的原因。

要解决此问题,您需要首先选择一种方法。:) 我建议对组对象进行范围检索,并要求范围中的大成员属性。这将使您获得组中的所有成员。如果你沿着这条路走,你会注意到你不能要求这些值的属性。您获得的唯一值是成员列表,然后您可以搜索它们。如果您选择像上面那样继续使用分页搜索,那么您最终会切换到分页搜索。

如果您选择坚持分页搜索,那么您需要:

  • 摆脱 Range 逻辑,以及所有提及 1500
  • 将页面大小设置为 1000
  • 查找如何使用您的 API 进行分页搜索(使用页面搜索控件)而不是测距

如果您选择范围,您将从这样的 memberOf 搜索切换到以下形式的搜索:a) 范围:基础 b) 过滤器:(objectclass= ) c) 基础 DN:OU=C,OU=x,DC= h,DC=nt d) 属性:member;Range=0- ...然后您将在获取值范围时将 0 递增(即,对每个后续值范围反复执行此搜索,仅更改0 到后续整数)你会在我的逻辑中注意到的其他细节: - 我没有设置页面大小......你没有进行分页搜索,所以没关系。- 我从来没有在这里硬编码值 1500。没关系。知道甚至计算这一点没有任何价值。关键是你要求 0-* (即全部),你得到了 1500,所以你说 1500- ,然后是 3000-, 等等。你不需要知道范围大小,只需要知道到目前为止你已经得到的。

我希望这能完全回答它......

根据我在下面的评论,这是进行分页搜索的代码片段(这是您需要使用 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);
于 2012-09-05T04:23:24.020 回答
-1

您的问题是由循环创建目录搜索器的新对象引起的。每次都会有一个新的对象,它将获取前 1500 条记录。在循环之外创建 searher 的实例并为所有查询使用相同的实例。

于 2012-09-04T21:05:56.100 回答