This is similar to How to do a paged search on an Ldap server with lots of users? but the suggested solution does not work for us.
We use Novell.Directory.Ldap.NETStandard library and we need to fetch more than 10000 entries from an Active Directory. We use the LdapVirtualListControl to handle paging, but that control requires another control: LdapSortControl. Active Directory has an default limit for sorting (10000) and will send an error 53 (unwilling to perform) if the result exceeds that limit. If the "Detect max result error" is omitted, we will instead get a LdapException: 'Unavailable Critical Extension'.
// Connection
var ldapConn = new LdapConnection()
{
SecureSocketLayer = true,
};
ldapConn.UserDefinedServerCertValidationDelegate += (sender, certificate, chain, sslPolicyErrors) => true;
ldapConn.Connect(host, 636);
ldapConn.Bind(username, password);
var searchConstraints = (LdapSearchConstraints)ldapConn.SearchConstraints.Clone();
int contentCount = 0, count = 0, startIndex = 1, pageSize = 1000;
bool exit;
do
{
// Add Virtual List Control
searchConstraints.setControls(new List<LdapControl>
{
{ new LdapVirtualListControl(startIndex, 0, pageSize - 1, contentCount) },
{ new LdapSortControl(new LdapSortKey[1] { new LdapSortKey("name") },true) }
}.ToArray());
// Perform search
var searchResult = ldapConn.Search(container, scope, query, null, false, searchConstraints);
// Get entries in page
var inPageCount = 0;
while (searchResult.hasMore())
{
// Detect max result error
LdapSortResponse ldapControl = searchResult.ResponseControls?.OfType<LdapSortResponse>().FirstOrDefault();
if (ldapControl != null && ldapControl.ResultCode == 53) throw new LdapResultLimitExceeded(string.Format("ActiveDirectory: Ldap result limit exceeded in {0}.", container));
searchResult.next();
inPageCount++;
}
// Check for more pages
var control = FindResponseControl(searchResult, ActiveDirectoryService.LDAP_SERVER_VIRTUAL_LIST_VIEW_OID);
if (control != null)
{
var response = new LdapVirtualListResponse(control.ID, control.Critical, control.getValue());
startIndex += pageSize;
contentCount = response.ContentCount;
if (count + pageSize > contentCount) count = contentCount; else count += inPageCount;
}
exit = control == null;
} while (count < contentCount && contentCount > 0 && !exit);
How should we handle search for more then 10000 entries?