PrincipalSearcher和DirectorySearcher之间的区别
我看到使用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()); }
我花了很多时间分析这两者之间的差异。 这是我学到的。
-
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;
-
如果您使用
PropertiesToLoad
DirectorySearcher
可以比PrincipalSearcher
快得多。 -
DirectorySearcher
和类似的类可以处理AD中的所有对象,而PrincipalSearcher
则更加有限。 例如,您无法使用PrincipalSearcher
和类似的类修改组织单位。
下面是我使用PrincipalSearcher
, DirectorySearcher
而不使用PropertiesToLoad
进行分析的图表,以及使用PropertiesToLoad
DirectorySearcher
分析的图表。 所有测试……
- 使用
PageSize
为1000
- 查询总共4,278个用户对象
- 指定以下条件
-
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
与“使用DirectorySearcher
”相同,但添加此行
search.PropertiesToLoad.AddRange(new string[] { "canonicalName" });
后
search.PageSize = 1000;
PrincipalSearcher
用于查询组或用户的目录。 DirectorySearcher
用于查询各种对象。
我之前使用DirectorySearcher
来获取组,因此我发现了PrincipalSearcher
所以当我用后者替换前者时,我的程序速度得到了提高(也许只是PrincipalSearcher
为我创建了一个更好的查询。对于我关心的, PrincipalSearcher
更容易使用和更适合获得目标的任务。
另一方面, DirectorySearcher
更通用,因为它可以获得其他类型的对象。 这就是为什么它不能像评论中提到的那样强类型。 PrincipalSearcher
是关于主体的所有内容,因此它将具有与主体相关的强类型对象,这也是为什么你也不需要告诉它为你提供类型用户或组的对象,它将由Principal类隐含使用。