微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 如何在拥有大量用户的Ldap服务器上进行分页搜索?

我需要创建一个使用.NET Core在 Linux上运行的LDAP客户端.我搜索了互联网,唯一支持.Net Standard的库是Novell.Directory.Ldap(开源,iei – https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard).目录服务库在.Net Core for Linux中不支持,仅在Windows上.

我查看了文档并成功创建了一个基本的Ldap客户端应用程序.

现在问题是:我需要同步很多用户(10.000,200.000用户),认情况下,我的ldap服务器的最大大小为1000页(我不想更改它).我使用VirtualListControl来创建页面,它适用于10k用户.

对于200k用户,它崩溃并出现错误53 – 不愿意对LdapSortControl响应执行. Novell库需要一个LdapSortControl才能执行分页操作(对于索引),我认为我的ldap无法对200k进行排序.我使用的代码

int startIndex = 1;
        int contentCount = 0;
        int afterIndex = 10;
        int count = 0;
        do
        {
            LdapVirtualListControl ctrl = new LdapVirtualListControl(startIndex,afterIndex,contentCount);
            LdapSortKey[] keys = new LdapSortKey[1];
            keys[0] = new LdapSortKey("sn");
            LdapSortControl sort = new LdapSortControl(keys,true);

            LdapSearchConstraints constraints = _ldapConnection.SearchConstraints;
            constraints.setControls(new LdapControl[] { ctrl,sort});

            _ldapConnection.Constraints = constraints;
            LdapSearchResults lsc = _ldapConnection.Search(searchBase,searchScope,searchFilter,attributes,typesOnly,cons);
            while (lsc.HasMore())
            {
                try
                {
                    LdapEntry nextEntry = lsc.Next();
                    Console.WriteLine( nextEntry.DN);
                }
                catch (LdapException e)
                {
                    Console.WriteLine($"Error: {e.LdapErrorMessage}");
                    //Exception is thrown,go for next entry
                    continue;
                }

            }

            LdapControl[] controls = lsc.ResponseControls;
            if (controls == null)
            {
                Console.Out.WriteLine("No controls returned");
            }
            else
            {
                foreach (LdapControl control in controls)
                {
                    if (control.ID == "2.16.840.1.113730.3.4.10")
                    {
                        LdapVirtualListResponse response = new LdapVirtualListResponse(control.ID,control.Critical,control.getValue());
                        startIndex += afterIndex + 1;
                        contentCount = response.ContentCount;
                        count += afterIndex;
                    }
                }
            }
            Console.WriteLine(i);

        } while (count <= contentCount);

文档很小,没有足够的信息,我不知道如何以更好的方式使用Novell库进行分页.
这里有人使用Novell Ldap库并且有任何分页经验,也可以帮助我吗?我不顾一切

谢谢

解决方法

要使用Novell.Directory.Ldap进行分页查询,必须使用LdapVirtualListControl作为“请求”控件.

LdapVirtualListControl尊重Ldap排序请求控件的参数:VLV(虚拟列表视图),它们是:

before:after:index:content_count

其中“之前”是您希望在索引之前返回的项目数,“之后”您希望在索引之后返回的项目数和“content_count”是服务器中预期的项目总数.如果你不知道它,你必须使用0作为值.

如果你想通过“ldapsearch”cli返回前5个元素,你必须使用:’0:4:1:0’和’0:4:5:0’用于后续的5个元素.

LdapVirtualListControl拥有一个具有相同参数但具有不同顺序的构造函数

LdapVirtualListControl(int startIndex,int beforeCount,int afterCount,int contentCount)

就个人而言,我使用此函数正确设置参数:

public static LdapSearchConstraints AddPagination(this LdapSearchConstraints constraints,int page,int pageSize)
{
    int startIndex = (page - 1) * pageSize;
    startIndex++;
    int beforeCount = 0;
    int afterCount = pageSize - 1;
    int contentCount = 0; //0 means that i don't kNow the total count

    var lvlc = new LdapVirtualListControl(startIndex,beforeCount,afterCount,contentCount);
    constraints.setControls(lvlc);
    return constraints;
}

之后,需要注意另一个问题:如果您要求在数据集结束后定位的一组数据,您将收到数据集的第一项.

说明:

ldap中存在的数据示例:
| 1 | 2 | 3 | 4 |
如果我们要求这套
________ | 3 | 4 | 5 | < - 5不存在
Ldap返回:
________ | 3 | 4 | 1 | < - 它从头开始 要解决此问题,请在返回之前删除超出的元素:

var lastIndex = (page * pageSize);
if (lastIndex > result.Total)
{
    var itemsToReturn = (int) (result.Total - (lastIndex - pageSize));
    if (itemsToReturn < 1)
    {
        items = new List<LdapQueryItem>();
    }
    else
    {
        items = items.Take(itemsToReturn).ToList();
    }
}

最后,获取总数的函数(在searchResults.HasMore()方法后执行)

protected int? GetTotal(LdapSearchResults searchResult)
{
    if (searchResult == null) {
       throw new ArgumentNullException(nameof(searchResult));
    }
    if (searchResult.ResponseControls != null && searchResult.ResponseControls.Any())
    {
        foreach (LdapControl control in searchResult.ResponseControls)
        {
            if (control.ID == "2.16.840.1.113730.3.4.10") // the id of the response control
            {
                LdapVirtualListResponse response =
                    new LdapVirtualListResponse(control.ID,control.getValue());
                return response.ContentCount;
            }
        }
    }

    return null;
}

您可以在本书中获得更多见解和信息:
Understanding and Deploying LDAP Directory Services

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐