1

I have a code which either gets 1000 or all the results using DirectorySearcher.

But I want to get only 2000 of 6000 results.

Here is the code to get 6000 results whereas I only want 2000

mySearcher.SizeLimit = 2000;
mySearcher.PageSize = 1000;

SearchResultCollection results = mySearcher.FindAll();

int totalUsers = results.Count;

Please help.

Thanks

My research says PageSize = 0 gives 1000 results only and Pagesize = 1000 gives all results.

Need more help to make this work.

user175084
  • 4,550
  • 28
  • 114
  • 169
  • 1
    Any pageSize other than 0 will give you all results. It merely tells the server how big a collection of results to return in a chunk to the underlying framework. – Maverik Jun 01 '12 at 16:15
  • lol.. So in short there is no solution for my problem yet? – user175084 Jun 01 '12 at 16:20
  • updated my answer and I guess short answer is a no. not the way we'd like to go about it. – Maverik Jun 01 '12 at 16:40

2 Answers2

2

There seems to be a slight weird behavior with the PageSize property.
Please set it to 0 , does that work?

By the way:
c# Active Directory Services findAll() returns only 1000 entries

Can I get more than 1000 records from a DirectorySearcher in Asp.Net?

Community
  • 1
  • 1
Magnus Johansson
  • 28,010
  • 19
  • 106
  • 164
  • if i set it to 0 it gives me 1000 results. – user175084 Jun 01 '12 at 15:38
  • +1 I bet Joe Kaplan's answer is spot on - as per usual :-) Good links. – marc_s Jun 01 '12 at 15:38
  • 2
    Well, sort of. If you set the SizeLimit larger than the Server Default, the Server Default will be used as SizeLimit. Talk about Land of Confusion. – Magnus Johansson Jun 01 '12 at 15:41
  • 1
    A yes - I see you've reached the same conclusion while i was writing test code to ensure this was the case. Just learned this myself. – Maverik Jun 01 '12 at 15:44
  • so Maverik can it be done, can i get 2000 results or not? + 1 for writing the test code – user175084 Jun 01 '12 at 15:46
  • I don't think there's a clean / easy way of doing this, but I'm no expert on DirectorySearcher operations. Perhaps somebody more experienced can teach us both. But I've shared my approach in my answers comment section. – Maverik Jun 01 '12 at 15:49
  • 1
    Well I'm writing a bit of sample code and I'll paste it in my answer bit which can help you until somebody comes up with a more elegant solution. – Maverik Jun 01 '12 at 16:02
  • that will be great.. thanks a ton.. cant believe this is so complicated – user175084 Jun 01 '12 at 16:04
2

According to this post: DirectorySearcher.FindAll() - should have PageSize=1000

SizeLimit doesn't matter in this case as the Server side default is being used which defaults to 1000 results. I've never needed to page like this but I imagine the minimum size limit is used (between your size limit and server size limit - just tested it in my own AD). Your PageSize is indeed paging however it does the paging in the background and returns you only the final stream as I understand which is why you are getting all results.

I believe your easiest solution is to just use Linq on top of this and do a .Take(2000) on results. This would get you your desired result at the cost of additional bandwidth and processing on server.

If you really want to sort that, I guess you will have to go update the servers default paging size to be higher (though i doubt this will be feasible for administrative reasons).

EDIT:

Here is how I'd go about this roughly (quick working sample code from my LinqPad - also note that I'm actually bringing over everything unlike how you might wanna do this by taking the for loop out of equation):

using(DirectoryEntry de = new DirectoryEntry("LDAP://domain.local/dc=domain,dc=local", "user", "password"))
using(DirectorySearcher ds = new DirectorySearcher(de))
{
    ds.Filter="(&(objectCategory=user)(objectClass=user))";
    ds.PageSize= 1000;
    ds.PropertiesToLoad.Clear();
    ds.PropertiesToLoad.Add("objectGuid");

    var results = ds.FindAll();
    var searchResults = results.Cast<System.DirectoryServices.SearchResult>().ToArray();
    int myDesiredPageSize = 2000;

    var upns = new StringCollection();

    for(var step=0; step < Math.Ceiling((double)results.Count / myDesiredPageSize); step++)
    {
        Parallel.ForEach(searchResults.Skip(step*myDesiredPageSize).Take(myDesiredPageSize), result => {
        using(var entry = result.GetDirectoryEntry())
        {
            entry.RefreshCache(new[]{ "userPrincipalName" });

            if(entry.Properties.Contains("userPrincipalName"))
                upns.Add(entry.Properties["userPrincipalName"][0] as string);
        }
        });
    }

    upns.Count.Dump();
}

This returns about 1400 results in about 3 seconds over my lan connection in my test scenario. Since we are querying in parallel higher numbers should not scale linearly. Also you may want to contain the parallelisation to some degree as this would hammer AD mercilessly :)

In my normal operations, I employ caching with WhenChanged attribute of AD objects to reduce my actual querying to only changed objects instead of loading the same thing over and over which only takes the hit first time around and subsequent results are fraction of a second. Taking this approach you can do away with paging entirely and just load your properties when you start and then pull only the changed entries if that is an option.

Maverik
  • 5,619
  • 35
  • 48
  • 1
    To my findings, the SizeLimit does indeed matter, as long as it is below the server default. Above server default, than server default it is. – Magnus Johansson Jun 01 '12 at 15:44
  • the reason i am doing this is to reduce the additional bandwidth which it takes to get all the results.. and 6000 is just an example. what if there are 100000 entries and the user wants to only see 2000. getting 2000 will be so much faster. – user175084 Jun 01 '12 at 15:44
  • Well if I had to do this in my environment, I'd either drop down to direct LDAP protocol where I believe you can tell the server what result size you want (as you see in ldp.exe) or I'd take all objectGuid results only and then query them in parallel using my paging number for full properties. – Maverik Jun 01 '12 at 15:47
  • hey thanks.. this is great.. this will be my solution if no one comes up with anything good.. – user175084 Jun 01 '12 at 16:49