use*_*635 2 .net c# parallel-processing active-directory
我有下面的代码可以从 Active Directory 中检索组。当我只为MY_GROUP_NAME(在下面注释掉)运行代码时,输出符合预期。
当我从 AD 中运行完整的一组组时,最终的数据集是不正确的。一个具体的例子是,我最终在列表中得到了多个具有相同组名但 ParentGroupGuid 不同的 adGroup。这是一个无效的场景。这个问题似乎与Parallel.ForEach()调用下面的递归方法有关。
知道问题可能是什么以及如何解决吗?
private ConcurrentBag<Core.Models.ADGroup> adGroups;
public async Task<List<Core.Models.ADGroup>> GetADGroupsFromADAsync(string domainName)
{
return await Task.Run(async() =>
{
var domainId = await new DomainRepository().GetDomainId(domainName);
using (var context = new PrincipalContext(ContextType.Domain, domainName))
{
var ps = new PrincipalSearcher(new GroupPrincipal(context));
Parallel.ForEach(
ps.FindAll().ToList(),
//ps.FindAll().Where(x => x.Name == "MY_GROUP_NAME").ToList(),
new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount },
async (group, loopState) =>
{
await GetGroupsRecursive((Guid)domainId, null, (GroupPrincipal)group);
});
}
//return group list
return adGroups.ToList();
});
}
private async Task 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)
await GetGroupsRecursive(domainId, adGroup.Guid, (GroupPrincipal)member);
//add to the list
adGroups.Add(adGroup);
}
Run Code Online (Sandbox Code Playgroud)
同时使用PrincipalContext来自多个线程的a 是不安全的。在内部,group.Members您GetGroupsRecursive 将调用 ContextRaw.QueryCtx.GetGroupMembership(this, false);使用主体上下文的调用。
这可能会导致您遇到的错误。您要么需要每个线程的上下文,要么不需要多线程成员查找。
编辑:您的代码还有另一个主要问题(直到我尝试编写示例时才看到),您正在使用 async/await 进行Parallel.ForEach调用。这不受支持,您只能使用 同步方法Parallel.ForEach,摆脱异步或切换到TPL Dataflow。
这是修复 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);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
322 次 |
| 最近记录: |