我看到使用PrincipalSearcher
的Active Directory示例以及使用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());
}
答案 0 :(得分:65)
我花了很多时间分析这两者之间的差异。这是我所学到的。
DirectorySearcher
来自System.DirectoryServices
命名空间。
PrincipalSearcher
来自System.DirectoryServices.AccountManagement
命名空间,该命名空间构建于System.DirectoryServices
之上。 PrincipalSearcher
内部使用DirectorySearcher
。
AccountManagement
命名空间(即PrincipalSearcher
)旨在简化用户,组和计算机对象(即主体)的管理。理论上,它的使用应该更容易理解,并产生更少的代码行。虽然在我的实践中到目前为止,它似乎在很大程度上取决于你正在做什么。
DirectorySearcher
更低级别,可以处理的不仅仅是User,Group和Computer对象。
对于一般用法,当您使用基本属性而只使用少量对象时,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
个1000
objectClass=user
objectCategory=person
!msExchResourceMetaData=ResourceType:Room
)!userAccountControl:1.2.840.113556.1.4.803:=2
)
使用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
与&#34相同;使用DirectorySearcher
但添加此行
search.PropertiesToLoad.AddRange(new string[] { "canonicalName" });
之后
search.PageSize = 1000;
答案 1 :(得分:3)
PrincipalSearcher
用于查询组或用户的目录。 DirectorySearcher
用于查询各种对象。
我使用DirectorySearcher
来获取群组之前我发现了PrincipalSearcher
所以当我用后者替换前者时,我的程序速度得到了提升(可能只是创建PrincipalSearcher
对我来说是一个更好的询问。对于我所关心的事情,PrincipalSearcher
更容易使用,更适合于获得目标的任务。
DirectorySearcher
更通用,因为它可以获得其他类型的对象。这就是为什么它不能像评论中提到的那样强类型化。 PrincipalSearcher
是关于主体的所有内容,因此它将具有与主体相关的强类型对象,这就是为什么你也不需要告诉它为了获得类型用户或组的对象,它将被暗示为你使用的主要课程。
答案 2 :(得分:0)
DirectorySearcher快得多。 @DrewChapin中的示例可以更进一步。根据我的测试,速度大约快了10倍。我能够用他的代码在3.8秒内拉出721计算机cn。相当快。通过我的更改,我在0.38秒内完成了更改。根据您在做什么,这可能会很大。我在预测性帐户搜索中使用了此方法(开始输入名称,然后会出现一个组合框。一个非常短的System.Timer在每次按键后启动,并被按键取消。如果计时器过去了,列表将更新。这样做的效率非常高。 )
DirectoryEntry entry = new DirectoryEntry();
DirectorySearcher search = new DirectorySearcher(entry,queryString);
search.PageSize = 1000;
// *** Added following line
search.PropertiesToLoad.AddRange(new string[] { "canonicalName" });
foreach( SearchResult result in search.FindAll() )
{
//DirectoryEntry user = result.GetDirectoryEntry();
// *** Work directly with result instead of user
if( result != null )
{
//user.RefreshCache(new string[]{"canonicalName"});
// *** Following line modified
string canonicalName = result.Properties["canonicalName"][0].ToString();
count++;
}
}