c# - usuario - system directoryservices dll
Diferencia entre PrincipalSearcher y DirectorySearcher (2)
Veo ejemplos de Active Directory que usan PrincipalSearcher y otros ejemplos que hacen lo mismo pero usan DirectorySearcher . ¿Cuál es la diferencia entre estos dos ejemplos?
Ejemplo usando 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);
}
Ejemplo usando 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());
}
He pasado mucho tiempo analizando las diferencias entre estos dos. Esto es lo que he aprendido.
DirectorySearcherproviene del espacio de nombresSystem.DirectoryServices.PrincipalSearcherproviene del espacio de nombresSystem.DirectoryServices.AccountManagement, que se basa enSystem.DirectoryServices.PrincipalSearcherutiliza internamenteDirectorySearcher.El espacio de nombres de
AccountManagement(es decir,PrincipalSearcher) fue diseñado para simplificar la administración de los objetos de Usuario, Grupo y Computadora (es decir, Principales). En teoría, su uso debería ser más fácil de entender y producir menos líneas de código. Aunque en mi práctica hasta ahora, parece depender en gran medida de lo que estás haciendo.DirectorySearchertiene un nivel más bajo y puede manejar más que solo objetos de Usuario, Grupo y Computadora.Para uso general, cuando trabaja con atributos básicos y solo con algunos objetos,
PrincipalSearcherdará como resultado menos líneas de código y un tiempo de ejecución más rápido.La ventaja parece desaparecer cuanto más avanzadas son las tareas que estás haciendo. Por ejemplo, si está esperando más de unos pocos cientos de resultados, deberá obtener el
DirectorySearchersubyacente y configurar elPageSizeDirectorySearcher ds = search.GetUnderlyingSearcher() as DirectorySearcher; if( ds != null ) ds.PageSize = 1000;DirectorySearcherpuede ser significativamente más rápido quePrincipalSearchersi hace uso dePropertiesToLoad.DirectorySearchery las clases similares pueden trabajar con todos los objetos en AD, mientras quePrincipalSearcheres mucho más limitado. Por ejemplo, no puede modificar una unidad organizativa utilizandoPrincipalSearchery clases similares.
Aquí hay una tabla que hice para analizar usando PrincipalSearcher , DirectorySearcher sin usar PropertiesToLoad , y DirectorySearcher con usar PropertiesToLoad . Todas las pruebas ...
- Utilice un
PageSizedePageSizede1000 - Consulta un total de 4,278 objetos de usuario.
- Especifique los siguientes criterios
-
objectClass=user -
objectCategory=person - No es un recurso de programación (es decir
!msExchResourceMetaData=ResourceType:Room) - Habilitado (es decir
!userAccountControl:1.2.840.113556.1.4.803:=2)
-
Código para cada prueba
Usando 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);
}
Utilizando 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);
}
Usando DirectorySearcher con PropertiesToLoad
Igual que "Usando DirectorySearcher pero agregue esta línea
search.PropertiesToLoad.AddRange(new string[] { "canonicalName" });
Después
search.PageSize = 1000;
PrincipalSearcher se utiliza para consultar el Directorio de Grupos o Usuarios. DirectorySearcher se utiliza para consultar todo tipo de objetos.
Usé DirectorySearcher para obtener grupos antes de eso. Descubrí PrincipalSearcher así que cuando reemplacé el primero con el último, la velocidad de mi programa mejoró (tal vez fue solo PrincipalSearcher que creó una mejor consulta para mí. Por lo que me importa, PrincipalSearcher fue más fácil Para usar y más adecuado para la tarea de conseguir pricipals.
DirectorySearcher por otro lado, es más general, ya que puede obtener otros tipos de objetos. Esta es la razón por la que no se puede escribir con fuerza como se menciona en los comentarios. PrincipalSearcher tiene que ver con los directores, por lo que tendrá objetos fuertemente tipados que pertenecen a los directores, y es por eso que no es necesario que le diga para obtener un objeto de tipo usuario o grupo, estará implícito en las clases principales que utilizar.