Разница между PrincipalSearcher и DirectorySearcher

Я вижу примеры Active Directory, которые используют PrincipalSearcher и другие примеры, которые делают то же самое, но использовать DirectorySearcher. В чем разница между этими двумя примерами?

пример использования PrincipalSearcher

PrincipalContext context = new PrincipalContext(ContextType.Domain);
PrincipalSearcher search = new PrincipalSearcher(new UserPrincipal(context));
foreach( UserPrincipal user in search.FindAll() )
{
    if( null != user )
        Console.WriteLine(user.DistinguishedName);
}

пример использования DirectorySearcher

DirectorySearcher search = new DirectorySearcher("(&(objectClass=user)(objectCategory=person))");
search.PageSize = 1000;
foreach( SearchResult result in search.FindAll() )
{
    DirectoryEntry user = result.GetDirectoryEntry();
    if( null != user )
        Console.WriteLine(user.Properties["distinguishedName"].Value.ToString());
}

2 ответов


я потратил много времени на анализ различий между этими двумя. Вот что я узнал.

  • DirectorySearcher происходит от System.DirectoryServices пространство имен.

  • PrincipalSearcher происходит от System.DirectoryServices.AccountManagement пространство имен, которое построено поверх System.DirectoryServices. PrincipalSearcher внутренне использует DirectorySearcher.

  • на AccountManagement пространство имен (т. е. PrincipalSearcher) был разработан для упрощения управления пользовательскими, групповыми и компьютерными объектами (т. е. Принципалы.) Теоретически, это использование должно быть проще понять и производить меньше строк кода. Хотя в моей практике это сильно зависит от того, что вы делаете.

  • DirectorySearcher более низкоуровнево и может общаться с больше чем как раз объектами потребителя, группы и компьютера.

  • для общего использования, когда вы работаете с основными атрибутами и лишь немногие объекты, PrincipalSearcher приведет к меньшему количеству строк кода и более быстрому времени выполнения.

  • преимущество, кажется, исчезает тем более продвинутые задачи, которые вы делаете становятся. Например, если вы ожидаете более нескольких сотен результатов, вам нужно будет получить базовый DirectorySearcher и выберите PageSize

    DirectorySearcher ds = search.GetUnderlyingSearcher() as DirectorySearcher;
    if( ds != null )
        ds.PageSize = 1000;
    
  • DirectorySearcher может быть значительно быстрее, чем PrincipalSearcher если вы используете PropertiesToLoad.

  • DirectorySearcher и подобные классы могут работать со всеми объектами в AD, тогда как PrincipalSearcher намного более ограниченный. Например, нельзя изменить организационное подразделение с помощью PrincipalSearcher и как классы.

вот график для анализа с помощью PrincipalSearcher, DirectorySearcher без использования PropertiesToLoad и DirectorySearcher С помощью PropertiesToLoad. Все тесты...

  • использовать PageSize of 1000
  • запрос в общей сложности 4,278 пользовательских объектов
  • указать следующие критерий
    • objectClass=user
    • objectCategory=person
    • не ресурс планирования (т. е. !msExchResourceMetaData=ResourceType:Room)
    • включить (т. е. !userAccountControl:1.2.840.113556.1.4.803:=2)

DirectorySearcher vs. PrincipalSearcher Performance Chart


Код Для Каждого Теста


используя PrincipalSearcher

[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("Person")]
public class UserPrincipalEx: UserPrincipal
{

    private AdvancedFiltersEx _advancedFilters;

    public UserPrincipalEx( PrincipalContext context ): base(context)
    {
        this.ExtensionSet("objectCategory","User");
    }

    public new AdvancedFiltersEx AdvancedSearchFilter
    {
        get {
            if( null == _advancedFilters )
                _advancedFilters = new AdvancedFiltersEx(this);
                return _advancedFilters;
        }
    }

}

public class AdvancedFiltersEx: AdvancedFilters 
{

    public AdvancedFiltersEx( Principal principal ): 
        base(principal) { }

    public void Person()
    {
        this.AdvancedFilterSet("objectCategory", "person", typeof(string), MatchType.Equals);
        this.AdvancedFilterSet("msExchResourceMetaData", "ResourceType:Room", typeof(string), MatchType.NotEquals);
    }
}

//...

for( int i = 0; i < 10; i++ )
{
    uint count = 0;
    Stopwatch timer = Stopwatch.StartNew();
    PrincipalContext context = new PrincipalContext(ContextType.Domain);
    UserPrincipalEx filter = new UserPrincipalEx(context);
    filter.Enabled = true;
    filter.AdvancedSearchFilter.Person();
    PrincipalSearcher search = new PrincipalSearcher(filter);
    DirectorySearcher ds = search.GetUnderlyingSearcher() as DirectorySearcher;
    if( ds != null )
        ds.PageSize = 1000;
    foreach( UserPrincipalEx result in search.FindAll() )
    {
        string canonicalName = result.CanonicalName;
        count++;
    }

    timer.Stop();
    Console.WriteLine("{0}, {1} ms", count, timer.ElapsedMilliseconds);
}


используя DirectorySearcher

for( int i = 0; i < 10; i++ )
{
    uint count = 0;
    string queryString = "(&(objectClass=user)(objectCategory=person)(!msExchResourceMetaData=ResourceType:Room)(!userAccountControl:1.2.840.113556.1.4.803:=2))";

    Stopwatch timer = Stopwatch.StartNew();

    DirectoryEntry entry = new DirectoryEntry();
    DirectorySearcher search = new DirectorySearcher(entry,queryString);
    search.PageSize = 1000;
    foreach( SearchResult result in search.FindAll() )
    {
        DirectoryEntry user = result.GetDirectoryEntry();
        if( user != null )
        {
            user.RefreshCache(new string[]{"canonicalName"});
            string canonicalName = user.Properties["canonicalName"].Value.ToString();
            count++;
        }
    }
    timer.Stop();
    Console.WriteLine("{0}, {1} ms", count, timer.ElapsedMilliseconds);
}


используя DirectorySearcher С PropertiesToLoad

то же самое, что и "Using DirectorySearcher но добавьте эту строку

search.PropertiesToLoad.AddRange(new string[] { "canonicalName" });

после

search.PageSize = 1000;

PrincipalSearcher используется для запроса каталога для групп или пользователей. DirectorySearcher используется для запроса всех видов объектов.

Я DirectorySearcher чтобы получить группы до того, как я обнаружил PrincipalSearcher поэтому, когда я заменил первый на последний, скорость моей программы улучшилась (может быть, это было просто PrincipalSearcher Это создало лучший запрос для меня. За то, что я забочусь, PrincipalSearcher было просто проще в использовании и больше подходит для задачи получения участников.

DirectorySearcher С другой стороны, это больше общие, как это может получить другие виды объектов. Вот почему он не может быть строго набран, как указано в комментариях. PrincipalSearcher все о субъектах, поэтому у него будут строго типизированные объекты, относящиеся к субъектам, и поэтому вам также не нужно говорить об этом, чтобы получить объект пользователя или группы, это будет подразумеваться основными классами, которые вы используете.