2014-02-07 26 views
16

什么是一种有效的方式来分页与.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但我唯一能做的就是指定页面大小。

那么,只有这样才能在客户端获取所有结果并执行跳过和计数?我真的希望有更直接在域控制器上实现这一点的更有效方法。

+0

如果sepcified大小限制的Active Directory将返回第一个条目到你的大小限制符合你的标准,所以我看到的唯一方法是通过配置尺寸返回的一切,然后开始过滤自己限制和页数 –

+0

您可以指定zie限制为高数字,它将分配到您确定的页数 –

+1

也许[this](http://zetetic.net/blog/2012/4/23/virtual -list-view-vlv-and-active-directory-what-it-good-for.html)会有所帮助。 –

回答

-1
private static DirectoryEntry forestlocal = new DirectoryEntry(LocalGCUri, LocalGCUsername, LocalGCPassword); 
    private DirectorySearcher localSearcher = new DirectorySearcher(forestlocal); 

    public List<string> GetAllUsers() 
    { 
     List<string> users = new List<string>(); 

     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; 
    } 
+2

我不太明白这个PageSize和SizeLimit是如何工作的。假设我指定'SizeLimit = 1000'和'PageSize = 5',并且有200个用户符合我的搜索条件。现在我想获得用户195-200。此示例是否会向AD发送40个请求以将所有200个用户返回给客户端?然后,我必须为客户端上的200个用户分页,以便将用户从195个提取到200个?如果这是真的,这是唯一的方法吗?我的意思是,如果我要把他们扔掉,因为在我的用户界面中我想显示195-200,所以对于我来说,让用户1-195给客户似乎是一个完全浪费。 –

+0

@DarinDimitrov是的,没有能力跳过第一个条目的分页是毫无价值的 – ken2k

+0

是的,完全没有价值,因此我的问题是否可以与AD做有效的分页。 –

6

您可以尝试虚拟列表视图搜索。以下按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); 
    } 

为了您的使用情况,你只需要BeforeCount,AfterCount和DirectoryVirtualListView的偏移特性(3 DirectoryVirtualListView构造函数)。 DirectoryVirtualListView的文档非常有限。您可能需要对其行为做一些实验。

4

如果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

0

Waaaay晚派对,但这是我在做什么:

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

有上member;range一个问题:当它的最后一页,即使你通过member;range=1000-1999(例如),它返回member;range=1000-*,所以你必须在最后来检查*知道,如果有更多的数据。

public void List<string> PagedSearch() 
{ 
    var list = new List<string>(); 
    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<string>().FirstOrDefault(p => p.StartsWith("member;range=")); 

      if (membersProperty != null) 
      { 
       lastPage = membersProperty.EndsWith("-*"); 
       list.AddRange(memberResult.Properties[membersProperty].Cast<string>()); 
       end = list.Count; 
      } 
      else 
      { 
       lastPage = true; 
      } 
     } 
    } 
    return list; 
}