C#目录服务速度很快,但读取结果的速度却很慢

时间:2020-06-24 06:32:33

标签: c# active-directory ldap

我正在为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结果列最耗时。而不是按过滤对象查询广告。

供参考: 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;
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您正在执行的操作将花费很长时间。您正在提取大量数据。

我写了一篇有关使用AD进行编程时获取better performance的文章,但看来您已经按照搜索建议(确保使用PropertiesToLoad)进行了推荐。但是看来您还没有在此处共享一些代码,因此您可以对其进行检查,看看是否还有其他可以调整的地方。

读取结果要花费很长时间,因为结果会出现在页面中。您将PageSize设置为int.MaxValue,但是AD一次不会返回超过1000个结果。因此,结果将在1000页中发送给您。这意味着当您尝试处理结果1001时,它将暂停,进入AD并获取下一页结果。在2001、3001等处也是如此

这也可能有助于了解为什么首先要提取所有这些数据。将其全部存储在AD中似乎很奇怪。但是我知道您可能刚刚被告知要这样做。。。这是我的事。

作为旁注,您是否了解C#中的string interpolation?它可以使您的string.Format行更加容易阅读。例如,这一行:

string strErrorMsg = string.Format("[{0}]: Incorrect AD filter string !!!", classAndMethodName);

可以简化为:

var strErrorMsg = $"[{classAndMethodName}]: Incorrect AD filter string !!!";