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.
DirectorySearcher
proviene del espacio de nombresSystem.DirectoryServices
.PrincipalSearcher
proviene del espacio de nombresSystem.DirectoryServices.AccountManagement
, que se basa enSystem.DirectoryServices
.PrincipalSearcher
utiliza 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.DirectorySearcher
tiene 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,
PrincipalSearcher
dará 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
DirectorySearcher
subyacente y configurar elPageSize
DirectorySearcher ds = search.GetUnderlyingSearcher() as DirectorySearcher; if( ds != null ) ds.PageSize = 1000;
DirectorySearcher
puede ser significativamente más rápido quePrincipalSearcher
si hace uso dePropertiesToLoad
.DirectorySearcher
y las clases similares pueden trabajar con todos los objetos en AD, mientras quePrincipalSearcher
es mucho más limitado. Por ejemplo, no puede modificar una unidad organizativa utilizandoPrincipalSearcher
y 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
PageSize
dePageSize
de1000
- 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.