LdapConnection SearchRequest throws exception for "The size limit was exceeded"

16,923

Solution 1

As it turns out, this works:

            try
            {
                response = (SearchResponse)con.SendRequest(request);

                return response.Entries.Cast<SearchResultEntry>()
                    .Select(entry => entry.Attributes)
                    .Select(x => GetADUserSearchItemFromADProperties(x, logMessage))
                    .Where(user => user.HasName)
                    .Cast<IUserSearchItem>();
            }
            catch (DirectoryOperationException ex)
            {
                response = (SearchResponse) ex.Response;
                return response.Entries.Cast<SearchResultEntry>()
                    .Select(entry => entry.Attributes)
                    .Select(x => GetADUserSearchItemFromADProperties(x, logMessage))
                    .Where(user => user.HasName)
                    .Cast<IUserSearchItem>();
            }

The MSDN documentation states that you get a DirectoryResponse class as the DirectoryOperationException.Response property. You can however cast this property to a SearchResponse type and then use the SearchResponse.Entries property to get the entries that you have received prior to hitting the specified SizeLimit.

I have tried this and I get the expected results, I'm just a bit upset that I have to work with an exception in order to perform the operation.

Solution 2

You should use cookies in a function similar to this. The function returns a collection of SearchResponse objects, which the caller should loop though.

private List<SearchResponse> SearchDirectory(string distinguishedName, string searchFilter, System.DirectoryServices.Protocols.SearchScope searchScope, params string[] attributeList)
{
    List<SearchResponse> result = new List<SearchResponse>();
    SearchResponse response = null;
    int maxResultsToRequest = 100;
    try
    {
        PageResultRequestControl pageRequestControl = new PageResultRequestControl(maxResultsToRequest);

        // used to retrieve the cookie to send for the subsequent request
        PageResultResponseControl pageResponseControl;
        SearchRequest searchRequest = new SearchRequest(distinguishedName, searchFilter, searchScope, attributeList);
        searchRequest.Controls.Add(pageRequestControl);

        while (true)
        {
            response = (SearchResponse)connection.SendRequest(searchRequest);
            result.Add(response);
            pageResponseControl = (PageResultResponseControl)response.Controls[0];
            if (pageResponseControl.Cookie.Length == 0)
                break;
            pageRequestControl.Cookie = pageResponseControl.Cookie;
        }
    }
    catch (Exception e)
    {
        // do something with the error

    }
    return result;
}
Share:
16,923
Karell Ste-Marie
Author by

Karell Ste-Marie

Been programming for about... wow, has it been that long?

Updated on June 26, 2022

Comments

  • Karell Ste-Marie
    Karell Ste-Marie about 2 years

    Because of the fact that we are required to connect to an LDAP server using LDAPS we must use LdapConnection instead of DirectoryEntry.

    Here is the source code:

            SearchResponse response;
            using (LdapConnection con = new LdapConnection(new LdapDirectoryIdentifier(Host, Port)))
            {
                if (IsSSL)
                {
                    con.SessionOptions.SecureSocketLayer = true;
                    con.SessionOptions.VerifyServerCertificate =
                        (connection, certificate)
                        => true;
                }
                con.Credential = new NetworkCredential(_username, _password);
                con.AuthType = AuthType.Basic;
                con.Bind();
    
                if (logMessage != null)
                    logMessage("Connected to LDAP");
    
                string sFilter = String.Format(
                    "(&(objectcategory=person)(objectclass=user){0}(!(userAccountControl:1.2.840.113556.1.4.803:=2)))",
                    filter
                    );
    
                SearchRequest request = new SearchRequest("OU=Corp,DC=mydc,DC=com", sFilter, SearchScope.Subtree);
                request.Attributes.Add(Resources.objectguid);
                request.Attributes.Add(Resources.givenname);
                request.Attributes.Add(Resources.sn);
                request.Attributes.Add(Resources.initials);
                request.Attributes.Add(Resources.samaccountname);
                request.Attributes.Add(Resources.userprincipalname);
                request.Attributes.Add(Resources.mail);
                request.Attributes.Add(Resources.objectsid);
                request.Attributes.Add(Resources.department);
                request.Attributes.Add(Resources.company);
                request.SizeLimit = 10;
    
                response = (SearchResponse) con.SendRequest(request);
            }
    

    Upon execution of the source code (we have verified credentials, host, port, etc - using an external 3rd party software) we get the following exception:

    The size limit was exceeded

    Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

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

    Source Error:

    response = (SearchResponse) con.SendRequest(request);
    
    [DirectoryOperationException: The size limit was exceeded]
       System.DirectoryServices.Protocols.LdapConnection.ConstructResponse(Int32
    

    messageId, LdapOperation operation, ResultAll resultType, TimeSpan requestTimeOut, Boolean exceptionOnTimeOut) +2385 System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request, TimeSpan requestTimeout) +499 System.DirectoryServices.Protocols.LdapConnection.SendRequest(DirectoryRequest request) +50 UserSearchProvider.ADUserSearchProvider.QueryStore(UserSearchCriteriaCollection criterias, Action1 logMessage) in c:\Users\stemarie\Documents\Visual Studio 2012\Projects\Idealink.Modules\UserSearchProvider\UserSearchProvider\ADUserSearchProvider.cs:298 UserSearchProvider.UserSearchProvider.QueryAndSort(UserSearchCriteriaCollection criterias, Action1 logMessage) in c:\Users\stemarie\Documents\Visual Studio 2012\Projects\Idealink.Modules\UserSearchProvider\UserSearchProvider\UserSearchProvider.cs:77 UserSearchProvider.UserSearchProvider.Search(UserSearchCriteriaCollection criterias, Action1 logMessage) in c:\Users\stemarie\Documents\Visual Studio 2012\Projects\Idealink.Modules\UserSearchProvider\UserSearchProvider\UserSearchProvider.cs:33 UserSearchProvider.UserSearchService.Search(UserSearchCriteriaCollection criterias, Action1 logMessage) in c:\Users\stemarie\Documents\Visual Studio 2012\Projects\Idealink.Modules\UserSearchProvider\UserSearchProvider\UserSearchService.cs:44 UserSearchProviderTest._Default.Page_Load(Object sender, EventArgs e) in c:\Users\stemarie\Documents\Visual Studio 2012\Projects\Idealink.Modules\UserSearchProvider\UserSearchProviderTest\Default.aspx.cs:28

    The part that confuses me is that we did specify the maximum size limit, we don't want more than 100 entries - we want to limit it. But yet the library consistently throws the error even if we specify a SizeLimit of 1.

    Does anyone have any insights/suggestions regarding this issue? We are very close to getting this working and just need to resolve this last problem.