c# - C# 目录服务很快,但读取结果真的很慢
问题描述
我正在为我的 Active Directory 中的所有组运行以下代码。
我要做的是首先运行查询以获取我的 Active Directory 中的所有组并返回它们的专有名称。之后我使用下面的代码来获取每个组中所有子组的列表。这包括嵌套的子组。该代码正在运行,尽管它真的很慢。
LDAP 查询总是执行得非常快,但是当我尝试处理结果时,它却非常慢。有什么我可以用来加快这个过程的吗?
目前我需要大约 2 小时来执行大约 20000 个看起来像的组。(我的广告中有超过 200 万)。
以下是我使用的代码:
获取所有组
public override IEnumerable<ADGroupObj> GetCustomGroupAndMember(ADSetting setting)
{
var m_strADFilter = configHandler.GetCustomGroupFilterString().ToString();
string classAndMethodName = $"{this.GetType().Name}.{MethodBase.GetCurrentMethod().Name}";
string[] properties = { "objectGUID", "cn", "distinguishedName", "member", "objectSid" };
//group
m_log.DebugFormat("[{0}]: [GetAllGroupAndMemberFromDomainController] m_strADFilter = {1}", classAndMethodName, m_strADFilter);
if (string.IsNullOrWhiteSpace(m_strADFilter))
{
string strErrorMsg = string.Format("[{0}]: Incorrect AD filter string !!!", classAndMethodName);
m_log.ErrorFormat(strErrorMsg);
throw new Exception(strErrorMsg);
}
bool isSuccess = false;
using (ADServerWrapper instADServer = ADServerWrapper.GetADServerWrapper(setting, this.ConnectType))
{
int iTotalCount = 0;
int iInvalidCount = 0;
int iValidCount = 0;
var results = instADServer.QueryADbyFilterObj(m_strADFilter, properties);
if (results == null)
{ throw new Exception("Error occured while invoking instADServer.QueryADbyFilterObj."); }
(var whiteListDomainOUs, var blackListDomainOUs) = configHandler.GetADSpecifyDomainOU();
foreach (SearchResult result in results)
{
++iTotalCount;
// Check Result valid or not
ADGroupObj adGroup = AnalyzeADGroupObj(result.Properties, whiteListDomainOUs, blackListDomainOUs);
adGroup = GetAllGrpMembers(adGroup,setting);
if (adGroup != null && ValidateADGroup(adGroup))
{
++iValidCount;
configHandler.UpdateCustomGroupDN(adGroup.DN);
yield return adGroup;
m_log.DebugFormat("[{0}]: AD Group ([Valid]/[total] count=[{1}]/[{2}]): {3}", classAndMethodName, iValidCount, iTotalCount, adGroup.Name);
}
else
{
++iInvalidCount;
m_log.DebugFormat("[{0}]: AD Group ([Null or inValid]/[total] count={1}/{2})", classAndMethodName, iInvalidCount, iTotalCount);
}
}
isSuccess = true;
}
if (!isSuccess)
{
string strErrorMsg = string.Format("[{0}]: Did not complete successfully, isSuccess == false.", classAndMethodName);
m_log.ErrorFormat(strErrorMsg);
throw new Exception(strErrorMsg);
}
}
获取所有子组
protected ADGroupObj GetAllGrpMembers(ADGroupObj aDGroup, ADSetting setting) {
string methodName = MethodBase.GetCurrentMethod().Name;
var forUserConnectType = ADServiceConnectType.AD_CONNECT_TYPE_GC | (this.connectType & ADServiceConnectType.AD_CONNECT_TYPE_SSL);
var instADServer = ADServerWrapper.GetADServerWrapper(setting, forUserConnectType);
string m_strADFilter = $"(&(objectCategory=group)(memberOf:1.2.840.113556.1.4.1941:={aDGroup.DN}))";
string[] properties = {
"distinguishedName"
};
try
{
aDGroup.Members = new List<string>();
IEnumerable<SearchResult> results = instADServer.QueryADbyFilterObj(m_strADFilter, properties);
if (results != null)
{
foreach (SearchResult result in results)
{
if (result.Properties["distinguishedName"] != null && result.Properties["distinguishedName"].Count > 0)
{
var user = result.Properties["distinguishedName"][0];
aDGroup.Members.Add(user.ToString());
}
}
}
else
m_log.DebugFormat("[{0}]:No value with member attribute!", methodName);
}
catch (Exception e)
{
}
return aDGroup;
}
在这里,两者中的 foreach 结果列是最耗时的。不是 Query AD By Filter Obj。
供参考: QueruADByFilterObj
public IEnumerable<SearchResult> QueryADbyFilterObj(string strFilter, string[] properties)
{
using (var searcher = new DirectorySearcher(m_ADEntryObject))
{
searcher.Filter = strFilter;
searcher.SizeLimit = int.MaxValue;
searcher.PageSize = int.MaxValue;
searcher.CacheResults = false;
searcher.PropertiesToLoad.AddRange(properties);
//searcher.ReferralChasing = ReferralChasingOption.All;
using (SearchResultCollection searchResults = searcher.FindAll())
{
foreach (SearchResult result in searchResults)
{
yield return result;
}
}
}
}
解决方案
你在做什么需要很长时间。您正在提取大量数据。
我写了一篇关于在使用 AD 编程时获得更好性能的文章,但似乎您已经在执行我在搜索时建议的操作(确保使用PropertiesToLoad
)。但它看起来仍然有一些你没有在这里共享的代码,所以你可以查看它,看看是否还有其他可以调整的地方。
读取结果需要很长时间,因为结果以页面形式出现。您设置PageSize
为int.MaxValue
,但 AD 一次不会返回超过 1000 个结果。所以结果将以 1000 页的形式发送给您。这意味着当您尝试处理结果 1001 时,它将暂停,转到 AD 并获取下一页结果。在 2001、3001 等处也是如此。
了解您为什么要首先提取所有这些数据也可能会有所帮助。当它已经在 AD 中时,将它全部存储在其他地方似乎很奇怪。但我知道你可能刚刚被告知要这样做......这发生在我身上。
作为旁注,您是否阅读过C# 中的字符串插值?它可以让你的string.Format
台词更容易阅读。例如,这一行:
string strErrorMsg = string.Format("[{0}]: Incorrect AD filter string !!!", classAndMethodName);
可以简化为:
var strErrorMsg = $"[{classAndMethodName}]: Incorrect AD filter string !!!";
推荐阅读
- hive - 在 where 子句中使用当前日期的 Hive 选择查询
- azure - 如何使用逻辑应用程序获取服务总线中的消息计数?
- javascript - TSLint '类型上不存在属性' VS firefox 调试器行为
- proget - 如何解决 Inedo Hub Proget 安装错误?
- oracle - ora-22060 参数是无效或未初始化的数字
- javascript - 在JS中打印镜像数字三角形
- javascript - 如何使用 Angular 和 ngAnimate 平滑地显示带有背景和文本的块?
- sql - SSIS OLE DB命令中的多个插入语句
- c# - 数据加载在哪里?
- perl - 贝宝模块的问题