Active Directory搜索的有效分页

在.NET中对Active Directory搜索进行分页的有效方法是什么? 在AD中搜索的方法有很多,但到目前为止我找不到如何有效地进行搜索。 我希望能够指示SkipTake参数,并能够在结果中检索与我的搜索条件匹配的记录总数。

我尝试过使用PrincipalSearcher类进行搜索:

 using (var ctx = new PrincipalContext(ContextType.Domain, "FABRIKAM", "DC=fabrikam,DC=com")) using (var criteria = new UserPrincipal(ctx)) { criteria.SamAccountName = "*foo*"; using (var searcher = new PrincipalSearcher(criteria)) { ((DirectorySearcher)searcher.GetUnderlyingSearcher()).SizeLimit = 3; var results = searcher.FindAll(); foreach (var found in results) { Console.WriteLine(found.Name); } } } 

在这里,我能够将搜索结果限制为3但是我无法获得与我的搜索条件相对应的记录总数( SamAccountName包含foo )我既没有能够向搜索者指示跳过前50条记录例。

我也尝试使用System.DirectoryServices.DirectoryEntrySystem.DirectoryServices.Protocols.SearchRequest但我唯一能做的就是指定页面大小。

那么获取客户端上的所有结果并在那里进行跳过和计数的唯一方法是什么? 我真的希望有更有效的方法直接在域控制器上实现这一点。

您可以尝试虚拟列表视图搜索。 下面按cn对用户进行排序,然后从第100个用户开始获取51个用户。

  DirectoryEntry rootEntry = new DirectoryEntry("LDAP://domain.com/dc=domain,dc=com", "user", "pwd"); DirectorySearcher searcher = new DirectorySearcher(rootEntry); searcher.SearchScope = SearchScope.Subtree; searcher.Filter = "(&(objectCategory=person)(objectClass=user))"; searcher.Sort = new SortOption("cn", SortDirection.Ascending); searcher.VirtualListView = new DirectoryVirtualListView(0, 50, 100); foreach (SearchResult result in searcher.FindAll()) { Console.WriteLine(result.Path); } 

对于您的用例,您只需要DirectoryVirtualListView的BeforeCount,AfterCount和Offset属性(DirectoryVirtualListView ctor中的3)。 DirectoryVirtualListView的文档非常有限。 您可能需要对其行为进行一些实验。

如果SizeLimit设置为零并且PageSize设置为500,则搜索将返回500个项目的页面中的所有12,000个结果,最后一页仅包含200个项目。 分页对应用程序透明地发生,除了将PageSize属性设置为正确的值之外,应用程序不必执行任何特殊处理。

SizeLimit限制您可以一次检索的结果数量 – 因此您的PageSize需要小于或等于1000(Active Directory将最大搜索结果数限制为1000.在这种情况下,将SizeLimit属性设置为更大的值超过1000没有效果。) 当您调用FindAll()等时,分页在后台自动完成。

有关详细信息,请参阅MSDN

https://msdn.microsoft.com/en-us/library/ms180880.aspx

https://msdn.microsoft.com/en-us/library/system.directoryservices.directorysearcher.pagesize.aspx

https://msdn.microsoft.com/en-us/library/system.directoryservices.directorysearcher.sizelimit.aspx

Waaaay迟到了,但这就是我正在做的事情:

我在PropertiesToLoad上使用FindOne()而不是FindAll()member;range=-

member;range有一个问题member;range :当它是最后一页时,即使你传递member;range=1000-1999 (例如),它返回member;range=1000-* ,所以你必须检查*最后知道是否有更多数据。

 public void List PagedSearch() { var list = new List(); bool lastPage = false; int start = 0, end = 0, step = 1000; var rootEntry = new DirectoryEntry("LDAP://domain.com/dc=domain,dc=com", "user", "pwd"); var filter = "(&(objectCategory=person)(objectClass=user)(samAccountName=*foo*))"; using (var memberSearcher = new DirectorySearcher(rootEntry, filter, null, SearchScope.Base)) { while (!lastPage) { start = end; end = start + step - 1; memberSearcher.PropertiesToLoad.Clear(); memberSearcher.PropertiesToLoad.Add(string.Format("member;range={0}-{1}", start, end)); var memberResult = memberSearcher.FindOne(); var membersProperty = memberResult.Properties.PropertyNames.Cast().FirstOrDefault(p => p.StartsWith("member;range=")); if (membersProperty != null) { lastPage = membersProperty.EndsWith("-*"); list.AddRange(memberResult.Properties[membersProperty].Cast()); end = list.Count; } else { lastPage = true; } } } return list; } 
  private static DirectoryEntry forestlocal = new DirectoryEntry(LocalGCUri, LocalGCUsername, LocalGCPassword); private DirectorySearcher localSearcher = new DirectorySearcher(forestlocal); public List GetAllUsers() { List users = new List(); localSearcher.SizeLimit = 10000; localSearcher.PageSize = 250; string localFilter = string.Format(@"(&(objectClass=user)(objectCategory=person)(!(objectClass=contact))(msRTCSIP-PrimaryUserAddress=*))"); localSearcher.Filter = localFilter; SearchResultCollection localForestResult; try { localForestResult = localSearcher.FindAll(); if (resourceForestResult != null) { foreach (SearchResult result in localForestResult) { if (result.Properties.Contains("mail")) users.Add((string)result.Properties["mail"][0]); } } } catch (Exception ex) { } return users; }