我需要创建一个使用.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, 0, 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库并且有任何分页经验,也可以帮助我吗?我不顾一切
谢谢
答案 0 :(得分:1)
要使用Novell.Directory.Ldap进行分页查询,必须将LdapVirtualListControl用作“请求”控件。
LdapVirtualListControl遵循Ldap排序请求控件:VLV(虚拟列表视图)的参数,
before:after:index:content_count
其中“ 之前”是您要在索引之前返回的项目数,“ 之后”是要在索引之后返回的项目数索引和“ content_count ”是服务器中预期的项目总数。如果您不知道,则必须使用0作为值。
如果您想通过“ ldapsearch” cli返回前5个元素,则必须对随后的5个元素使用“ 0:4:1:0”和“ 0:4:5:0”。
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.Critical, control.getValue());
return response.ContentCount;
}
}
}
return null;
}
您可以在这本书上获得更多的见解和信息: Understanding and Deploying LDAP Directory Services