поиск принципалов ldap очень медленный

Я хочу получить информацию только от 1 пользователя из 20 000 пользователей. Время отклика метода, который я использовал ниже, составляет 40 секунд. Каково решение этой проблемы?

public AuthenticatedUserProperties Info(string Username)
        {
            try
            {
                var context = new PrincipalContext(ContextType.Domain, Settings.LDAPDomain, Settings.LDAPContainer, Settings.LDAPUsername, Settings.LDAPPassword);

                UserPrincipal user = new UserPrincipal(context);
                user.SamAccountName = Username;
                var searcher = new PrincipalSearcher(user);
                var searchResults = searcher.FindOne();
                DirectoryEntry de = searchResults.GetUnderlyingObject() as DirectoryEntry;
                ActiveDirectoryUserProperties prop = ConvertLdapUserPropertyToArray(de);

                return new AuthenticatedUserProperties
                {
                    Status = true,
                    Properties = prop
                };

            }
            catch (Exception e)
            {

                return new AuthenticatedUserProperties
                {
                    Status = false,
                    Properties = null
                };
            }
        }

person Gökhan YILDIZ    schedule 24.07.2018    source источник
comment
Вероятно, прямой доступ к базовому DirectoryEntry. Что делает ConvertLdapUserPropertyToArray? Также вы можете использовать UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, Username); вместо PrincipalSearcher.   -  person The-First-Tiger    schedule 24.07.2018
comment
ConvertLdapUserPropertyToArray делает соответствующие данные значимыми и возвращает их в виде массива. Но моя проблема начинает запрашивать свойства пользователя. Я думаю, что сначала пытается привлечь 20000 пользователей, а затем находит запрошенного пользователя. Этот процесс отвечает через 40-50 секунд после.   -  person Gökhan YILDIZ    schedule 24.07.2018
comment
Код не обрабатывает 20000 пользователей. Он просит сервер найти 1 пользователя с определенными критериями поиска. Определите, на что уходит большая часть 40 секунд: на поиск или на ConvertLdapUserPropertyToArray. Если вы обрабатываете много реквизитов в ConvertLdapUserPropertyToArray, используя базовый DirectoryEntry, это может быть медленным, потому что доступ к большинству значений свойств запускает новый запрос к серверу ldap. Вы можете переопределить UserPrincipal и добавить требуемые свойства или использовать «DirectoryServices» вместо «AccountingManagement» и использовать DirectorySearcher с предварительно настроенными свойствами для загрузки.   -  person The-First-Tiger    schedule 24.07.2018
comment
Я не могу получить результат отладки на сервере, потому что не могу получить к нему доступ с моего собственного компьютера. Они не разрешают этот процесс из соображений безопасности. У меня нет проблем с активным каталогом, установленным на виртуальной машине. Но у меня проблемы с производственным сервером. Вы можете увидеть функцию ConvertLdapUserPropertyToArray из URL-адреса. codeshare.io/21NDR0 Как вы думаете, приведет ли это использование к замедлению?   -  person Gökhan YILDIZ    schedule 24.07.2018
comment
Трудно сказать, просто глядя на код. Также кажется, что есть вызов базы данных. Оптимизация производительности без измерения не имеет большого смысла. Вы можете попробовать DirectorySearcher, поскольку он предварительно загружает свойства, которые могут повысить производительность, но я не знаю, действительно ли это узкое место, но поиск пользователя не должен быть. Здесь кто-то говорит Запрос нескольких тысяч пользователей,[...](около 30 секунд для ~34 тыс. пользователей) stackoverflow.com/questions/45357892 Пример реализации: codeshare.io/am3L0X Потребовалось 170 мс на поиск пользователя ~3 тыс. пользователей 2.5 на преобразование реквизита   -  person The-First-Tiger    schedule 24.07.2018
comment
Я изменил код, как по ссылке. codeshare.io/am3L0X Код Виртуальная машина тоже работает нормально. В понедельник возьму результат анализов. Я надеюсь, что в этой ситуации он будет работать быстрее. Я снова прокомментирую по результатам теста. Спасибо за вашу помощь и идеи.   -  person Gökhan YILDIZ    schedule 25.07.2018


Ответы (1)


Вместо этого я использую библиотеку System.DirectoryServices.Protocols. Он всегда быстро пылает. Я никогда не смогу заставить System.DirectoryServices.AccountManagement иметь надежную производительность, и часто мучительно медленно (10+ секунд) получить только одного пользователя. TBH — я думаю, что наша настройка сети, вероятно, виновата в том, что привязка не работает, но библиотека протоколов дает хорошие результаты без особых усилий, независимо от нашей сетевой дисфункции.

Вы должны сделать немного больше работы, но ничего особенно сложного. Я не специалист по этой библиотеке, но этот пример кода у меня работает надежно.

using System.DirectoryServices.Protocols;
public class UserInfo
{
    public string SAMAccountName;
    public string DomainHostName;
    public string ADSDirectory;
    public Dictionary<string, string> UserAttributes;
    // Some attributes not really strings and require extra handling - but simplied for example
    // This is really just for illustrative purposes
    public UserInfo(string a_SAMAccountName, string a_DomainHostName = "ldap.mydomain:3268", string a_ADSDirectory = "ours.net")
    {
        UserAttributes = new Dictionary<string, string>();
        SAMAccountName = a_SAMAccountName;
        DomainHostName = a_DomainHostName;
        ADSDirectory = a_ADSDirectory;
    }
}
public static class GetUserAttributes
{
    public static List<string> WantedAttributes;

    static GetUserAttributes()
    {
        WantedAttributes = new List<string>();
        WantedAttributes.Add("mail");
        //... Add Properties Wanted
    }

    public static void GetUserAttributes(UserInfo a_user)
    {
        using (HostingEnvironment.Impersonate())
        {
            LdapDirectoryIdentifier z_entry = new LdapDirectoryIdentifier(a_user.DomainHostName, true, false);
            using (LdapConnection z_remote = new LdapConnection(z_entry))
            {
                z_remote.SessionOptions.VerifyServerCertificate = delegate (LdapConnection l, X509Certificate c) { return true; };
                z_remote.SessionOptions.ReferralChasing = ReferralChasingOptions.None;
                z_remote.SessionOptions.ProtocolVersion = 3;
                z_remote.Bind();

                SearchRequest z_search = new SearchRequest();
                z_search.Scope = System.DirectoryServices.Protocols.SearchScope.Subtree;
                z_search.Filter = "(SAMAccountName=" + a_user.SAMAccountName + ")";
                z_search.DistinguishedName = a_user.ADSdirectory;

                foreach (List<string> z_item in WantedAttributes)
                {
                    z_search.Attributes.Add(z_item);
                }

                SearchResponse z_response = (SearchResponse)z_remote.SendRequest(z_search);

                if (z_response != null)
                {
                    foreach (SearchResultEntry z_result in z_response.Entries)
                    {
                        foreach (string z_property in z_result.Attributes.AttributeNames)
                        {
                            if (WantedAttributes.ContainsKey(z_property))
                            {
                                DirectoryAttribute z_details = a_result.Attributes[z_property];
                                if (z_details.Count == 1)
                                {
                                    // Special handling required for Attributes that aren't strings objectSid, objectGUID, etc
                                    string z_value = z_details[0].ToString().Trim();
                                    if (!string.IsNullOrWhiteSpace(z_value))
                                    {
                                        a_user.UserAttributes.Add(z_property, z_value);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
person Robin Johnson    schedule 24.09.2018