Не безопасно использовать PrincipalContext
из нескольких потоков одновременно.Внутренне вызов group.Members
, который вы имеете в GetGroupsRecursive
, вызовет ContextRaw.QueryCtx.GetGroupMembership(this, false);
, который использует основной контекст.
Это, вероятно, вызывает ваши ошибки.Вам нужен контекст для каждого потока или не многопоточный поиск членов.
РЕДАКТИРОВАТЬ: Еще одна серьезная проблема, с которой столкнулся ваш код (не видел ее, пока я не попытался написатьпример), вы используете async / await с вызовом Parallel.ForEach
. Это не поддерживается, вы можете выполнять синхронные методы только с Parallel.ForEach
, избавиться от асинхронного или переключиться на Поток данных TPL .
Вот пример исправления async / await и превращения его в контекст для потока
public async Task<List<Core.Models.ADGroup>> GetADGroupsFromADAsync(string domainName)
{
return await Task.Run(async() =>
{
var domainId = await new DomainRepository().GetDomainId(domainName);
using (var searchContext = new PrincipalContext(ContextType.Domain, domainName))
{
var ps = new PrincipalSearcher(new GroupPrincipal(searchContext));
Parallel.ForEach(
ps.FindAll().Select(x=>x.DistinguishedName),
new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount },
() => new PrincipalContext(ContextType.Domain, domainName),
(distinguishedName, loopState, threadLocalContext) =>
{
var threadLocalGroup = GroupPrincipal.FindByIdentity(threadLocalContext, IdentityType.DistinguishedName, distinguishedName);
GetGroupsRecursive((Guid)domainId, null, threadLocalGroup);
return threadLocalContext;
},
threadLocalContext => threadLocalContext.Dispose());
}
//return group list
return adGroups.ToList();
});
}
private void GetGroupsRecursive(Guid domainId, Guid? parentGroupGuid, GroupPrincipal group)
{
//cast result to adgroup
var adGroup = Mapper.Map<Core.Models.ADGroup>(group);
//set domainid
adGroup.DomainId = domainId;
//set parent group id
adGroup.ParentGroupGuid = parentGroupGuid;
//process child groups
foreach (var member in group.Members)
if (member is GroupPrincipal)
GetGroupsRecursive(domainId, adGroup.Guid, (GroupPrincipal)member);
//add to the list
adGroups.Add(adGroup);
}