Reputation: 1
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.
I have a large batch of UUIDs representing Active Directory objects.
I need to search for these objects and determine if they exist in AD.
The search is performed using a custom attribute or the ObjectGuid
attribute.
When using a regular foreach
loop, all FindAll()
queries run successfully.
When using Parallel.ForEach
, some threads fail with the error "A local error has occurred" during the FindAll()
call.
Active Directory: Windows Server 2019
.NET Framework version: 4.8
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 };
}
}
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
}
The error occurs regardless of the list size.
It can affect one, two, or more threads, varying between runs.
I've tried using both <domain\user>
and <user>
formats for authentication, with the same results.
The AD credentials used are confirmed to be correct, as evidenced by the successful foreach
loop.
What could be causing the "A local error has occurred" during FindAll()
when using Parallel.ForEach
?
Are there any known issues or limitations with using DirectorySearcher.FindAll()
in parallel operations?
How can I modify my code to reliably perform these AD queries in parallel without encountering this error?
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:
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