Получение пользовательского атрибута AD одним пакетом

Можно ли использовать библиотеку System.DirectoryServices.AccountManagement и класс PrincipalSearcher для получения пользовательского атрибута для всех участников, возвращаемых вызовом FindAll()?

В настоящее время я использую этот пример: http://msdn.microsoft.com/en-us/library/bb552835%28v=vs.90%29.aspx.

Однако при доступе к моему пользовательскому свойству/атрибуту он, похоже, совершает дополнительную поездку в хранилище AD. Я бы хотел, чтобы это свойство жадно загружалось при первом вызове FindAll().


person Chris    schedule 22.08.2011    source источник


Ответы (2)


Да, можно быстро загрузить настраиваемый атрибут для всех принципалов при первоначальном вызове FindAll(). Вам нужно только указать свои настраиваемые атрибуты, как описано в образце Microsoft, используя атрибут [DirectoryProperty("YOUR_PROP_NAME")].

Получив доступ к свойству PropertiesToLoad базового DirectorySearcher с помощью метода GetUnderlyingSearcher() класса UserPrincipal, вы увидите, что ваш настраиваемый атрибут включен в коллекцию свойств для загрузки. Вы можете проверить коллекцию PropertiesToLoad в отладчике.

На моей машине коллекция содержит в общей сложности 68 свойств.

И тут начинаются проблемы и штраф за производительность. Чем больше свойств включено в эту коллекцию, тем больше потребуется обращений к Active Directory для их извлечения.

Я сделал несколько тестов производительности:

Использование образца Microsoft для извлечения 200 объектов InetOrgPerson заняло около 500 мс.

Использование класса DirectorySearcher напрямую и запрос только интересующих свойств заняло всего 70 мс (см. пример ниже).

using (DirectoryEntry e = new DirectoryEntry("LDAP://server10/CN=users,DC=treyresearch,DC=net", 
                                         "treyresearch\\administrator", "P@$$W0rd", AuthenticationTypes.FastBind | AuthenticationTypes.Secure))
  {
    using (DirectorySearcher ds = new DirectorySearcher(e, "(&(objectCategory=inetorgperson)(logonCount=0))"))
    {
      ds.SearchScope = SearchScope.OneLevel;
      ds.PropertiesToLoad.Clear();
      ds.PropertiesToLoad.Add("logonCount");
      ds.PropertiesToLoad.Add("sAMAccountName");


      Stopwatch sw = new Stopwatch();
      sw.Start();
      int countPerson = 0;
      using (SearchResultCollection searchResultCol = ds.FindAll())
      {
        foreach (SearchResult sr in searchResultCol)
        {
          ResultPropertyValueCollection propCol = sr.Properties["logonCount"];

          if (propCol.Count > 0)
          {
            countPerson++;
            object cou = propCol[0];
          }
        }
        sw.Stop();
        Console.Out.WriteLine(sw.ElapsedMilliseconds);
        Console.Out.WriteLine(countPerson);
      }
    }
  }

Точно так же я использовал objectCategory в фильтре поиска вместо objectClass, потому что objectCategory является так называемым индексированным свойством. Доступ к индексированным свойствам выполняется быстрее, чем доступ к неиндексированным свойствам.

Кроме того, я указал AuthenticationTypes.FastBind для повышения производительности.

Чтобы еще больше повысить производительность, см. эту статью на MSDN, в которой описывается создание эффективные поисковые запросы.

Подводя итог, можно сказать, что использование класса DirectorySearcher и указание только тех свойств, которые вас интересуют, значительно повышает производительность вашего поиска (уменьшая количество обращений к Active Directory).

Надеюсь это поможет.

person Hans    schedule 07.09.2011
comment
Спасибо за информацию. Однако я специально попросил решение с использованием PrincipalSearcher и пространства имен AccountManagement. - person Chris; 10.09.2011
comment
@Chris Dwyer Насколько мне известно, класс PrincipalSearcher основан на классе DirectorySearcher. Класс DirectorySearcher основан на COM-объекте (см. COM-интерфейс IDirectorySearcher). Этот COM-объект предлагает метод ExecuteSearch (в .Net называемый FindAll()). В документации указано, что некоторые поставщики, такие как поставщик LDAP, откладывают выполнение. Таким образом, FindAll() возвращает только дескриптор поиска, но не фактический результат поиска. - person Hans; 10.09.2011
comment
Мои тесты по-прежнему показывают ленивую загрузку атрибута при доступе к нему в соответствии с примером MSDN. Я использую настраиваемый атрибут, определяю свойство и выполняю вызов ExtensionGet — и выполняется сетевой вызов. Прохождение примера MSDN кажется просто способом доступа к пользовательским атрибутам с помощью ООП/строгого типа. В любом случае, ваше решение по-прежнему не дает возможности просто использовать только класс PrincipalSearch, что, я думаю, необходимо для этого вопроса и вознаграждения. Тем не менее, спасибо за ваш ответ. - person Chris; 10.09.2011

Да, ты можешь; Приведите GetUnderlyingObject() для каждого объекта Principal к DirectoryEntry, после чего вы сможете получить доступ к пользовательскому атрибуту, такому как oDE.Properties[YOUR_CUSTOM_ATTRIBUTE].Value.

person PerlDev    schedule 07.09.2011
comment
Я пробовал это, и это делает еще одну поездку в AD. Эти свойства загружаются неохотно - person Chris; 10.09.2011