user175084
user175084

Reputation: 4640

Get 2000 of 6000 records from DirectorySearcher

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.

Upvotes: 2

Views: 9593

Answers (2)

Maverik
Maverik

Reputation: 5681

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.

Upvotes: 2

Magnus Johansson
Magnus Johansson

Reputation: 28325

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?

Upvotes: 2

Related Questions