Friday, March 17, 2006

Paging in System.DirectoryServices.Protocols

One of the new features of .NET 2.0 is the System.DirectoryServices.Protocols (SDS.P) namespace that gives us access to the native LDAP api without relying on ADSI.  We can accomplish pretty much anything now in LDAP using managed code and we get around some of the wonkiness of ADSI.

Performing a simple search in SDS.P is pretty straightforward actually.  We just create a connection to the directory using the LdapConnection class, bind to the connection and then make request/response pairs on the connection.  One of the request/response pairs is SearchRequest and SearchResponse.  Without going into too many details, using these two classes in a synchronous manner is pretty easy.  What might be surprising however is that developers will often run into the following error:

System.DirectoryServices.Protocols.DirectoryOperationException : The size limit was exceeded

This departs from System.DirectoryServices (SDS) and ADSI where we do not get errors for simple searches even if we have not enabled paging.  In SDS, a similar query with DirectorySearcher would just return the MaxPageSize for the directory (usually 1000).  We know from SDS that to get more than the MaxPageSize, we need to use paging.  That is as simple as setting DirectorySearcher.PageSize > 0.

So, what about SDS.P.  It turns out that one of the really nice things that ADSI did for us was make paging so seamless.  If we wanted to use it, we simply asked for a specific page size and it just worked.  Now, since we are at a lower level, we need to take care of these details ourselves (native LDAP programmers already know this of course).

How do we do this in SDS.P?  Here is some sample code that implements paging and returns a collection of SearchResultEntry objects.

private List<SearchResultEntry> PerformPagedSearch(

    LdapConnection connection,

    string baseDN,

    string filter,

    string[] attribs)


    List<SearchResultEntry> results = new List<SearchResultEntry>();


        SearchRequest request = new SearchRequest(







    PageResultRequestControl prc = new PageResultRequestControl(500);


    //add the paging control



    while (true)


        SearchResponse response = connection.SendRequest(request) as SearchResponse;


        //find the returned page response control

        foreach (DirectoryControl control in response.Controls)


            if (control is PageResultResponseControl)


                //update the cookie for next set

                prc.Cookie = ((PageResultResponseControl)control).Cookie;





        //add them to our collection

        foreach (SearchResultEntry sre in response.Entries)





        //our exit condition is when our cookie is empty

        if (prc.Cookie.Length == 0)




    return results;