YairZ
YairZ

Reputation: 1

DirectorySearcher.FindAll() failing with "A local error has occurred" when used with Parallel.ForEach

I'm encountering an issue when using Parallel.ForEach to query Active Directory (AD) using DirectoryEntry and DirectorySearcher. Specifically, the FindAll() method is failing intermittently with the error "A local error has occurred". The queries work fine in a regular foreach loop, but fail when parallelized.

Problem Description

Environment

Code

Here's the main method using Parallel.ForEach:

var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = 10 };
Console.WriteLine("Starting parallel processing");
Parallel.ForEach(guids, parallelOptions, guid =>
{
    int currentThreadId = Thread.CurrentThread.ManagedThreadId;
    Console.WriteLine($"thread number: {currentThreadId} started");
    var ldapFilter = $"(&({Consts.ObjectClass}={Consts.OrgClassName})({Consts.customAttr}={guid}))";
    var searchResult =
        adDataProvider.BindByFilter(ldapFilter, context.DomainContext, context.DomainContext.OrgsOu);

    if (!searchResult.Failed && !searchResult.Found)
        searchResult = adDataProvider.BindByObjectGuid(guid.ToString(), context.DomainContext);

    if (searchResult.Failed)
    {
        Console.WriteLine($"FAILED thread number: {currentThreadId}");
    }

    if (searchResult.Found)
    {
        return;
    }
    Console.WriteLine($"Current thread number: {currentThreadId} ended");
});

The BindByFilter method where FindAll() is called:

public AdSearchResult BindByFilter(string filter, DomainContext domainContext, string ou)
{
    int thread = Thread.CurrentThread.ManagedThreadId;
    try
    {
        using (var entry = new DirectoryEntry($"LDAP://{domainContext.DomainDc}/{ou}", domainContext.AdUsername, domainContext.AdPassword))
        {
            using (var searcher = new DirectorySearcher(entry))
            {
                searcher.Filter = !string.IsNullOrEmpty(filter) ? filter : "(objectClass=*)";
                searcher.SearchScope = SearchScope.Subtree;
                searcher.PageSize = 1000;
                var searchResults = searcher.FindAll(); // This is where the error occurs
                return new AdSearchResult
                {
                    Found = searchResults.Count > 0,
                    Entries = searchResults
                };
            }
        }
    }
    catch (Exception e)
    {
        Console.WriteLine(JsonConvert.SerializeObject(e));
        Console.WriteLine("thread ERROR " + thread + " " + e.Message);
        return new AdSearchResult { Failed = true, ErrorMessage = e.Message, Exception = e };
    }
}

Error Details

The exception thrown during FindAll() is:

{
   "ClassName": "System.DirectoryServices.DirectoryServicesCOMException",
   "Message": "A local error has occurred.",
   "Data": null,
   "InnerException": null,
   "HelpURL": null,
   "StackTraceString": "at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
   at System.DirectoryServices.DirectoryEntry.Bind()
   at System.DirectoryServices.DirectoryEntry.get_AdsObject()
   at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
   at ActiveDirectoryParallelTester.AdDataProvider.BindByFilter(String filter, DomainContext domainContext, String ou) in C:\\Users\\*******\\*******\\ActiveDirectoryParallelTester\\AdDataProvider.cs:line 22",
   "RemoteStackTraceString": null,
   "RemoteStackIndex": 0,
   "ExceptionMethod": "8
Bind
System.DirectoryServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
System.DirectoryServices.DirectoryEntry
Void Bind(Boolean)",
   "HResult": -2147016645,
   "Source": "System.DirectoryServices",
   "WatsonBuckets": null
}

Additional Information

Questions

  1. What could be causing the "A local error has occurred" during FindAll() when using Parallel.ForEach?

  2. Are there any known issues or limitations with using DirectorySearcher.FindAll() in parallel operations?

  3. How can I modify my code to reliably perform these AD queries in parallel without encountering this error?

  4. Are there any best practices for handling concurrent AD queries that I should be aware of?

Any insights or suggestions would be greatly appreciated. Thank you!

------

example images for 2 runs:

Run #1

Run #2


Edit

I also tried using a .NET 8.0 project and System.DirectoryServices.Protocols but the same behavior.

                using var connection = new LdapConnection(_ldapDirectoryIdentifier, _networkCredential);
            connection.Bind();

            var searchRequest = new SearchRequest
            {
                SizeLimit = 1000,
                TimeLimit = new TimeSpan(0, 0, 30),
                Filter = ldapFilter,
                DistinguishedName = baseOu,
                Scope = SearchScope.Subtree,
                Attributes = { Consts.DistinguishedName, Consts.ObjectGuid, Consts.OrgInfraGuid }
            };

            var searchResponse = (SearchResponse)connection.SendRequest(searchRequest);

Upvotes: 0

Views: 86

Answers (0)

Related Questions