《C#高级编程(第四版)_OCRed_部分12.pdf》由会员分享,可在线阅读,更多相关《C#高级编程(第四版)_OCRed_部分12.pdf(61页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、第22章使用ActiveDirectory.645.在通知的间隔期间,发出通知的原因是属性的USN改变了,最后一次进行复制时,USN 的值是47。使用复制机制可以检测到服务器DCl和DC2电话号码属性的USN都是48。使用哪个服务器上的属性值并不重要,但必须使用其中一个服务器上的属性值。要解决这个冲突,就要使用改变的时间戳(timestamp)。因为DC2上的改变比较迟,所以会复制存储在DC2域控制器上的值。提示:在读取对象时,数据不一定存在。数据是否存在取决于复制等待时间。在更新对象时,另一个用户可以在更新后仍获取旧值,同时还可能进行另一个更新操作。22.1.3 Active Directo
2、ry数据的特性Active Directory没有替代关系数据库或注册表,那么什么数据可以存储在ActiveDirectory中?Active Directory可以存储分层数据,容器可以存储其他容器和对象。容器本身也是对象。数据应主要用于读取。因为在一定的时间间隔中会进行复制,所以不能确定可以读取到最新的数据。在应用程序中,必须注意读取的信息有可能不是最新的。数据应是企业普遍感兴趣的数据。这是因为给模式添加一个新数据类型,会把该数据类型复制到企业的所有服务器上,如果只有一小部分用户对该数据类型感兴趣,Domain Enterprise管理员就不会安装新的模式类型。数据应有合理的大小,因为这些
3、数据是要被复制的。如果数据的大小是100K,而且每星期修改一次数据,把它存储在目录中就不会出问题。但如果每小时修改一次数据,这个数据量就太大了。总是要考虑到数据的复制、数据要传送到什么地方、复制的时间间隔等。如果数据量比较大,就要链接到ActiveDirectory中,把数据存储到另一个地方。总之,存储在ActiveDirector中的数据应分层组织,且具育合理的大小,这对企业来说非常重要。22.1.4 模式Active Directory对象是类型安全的。模式定义了对象的类型、必选属性和可选属性,属性的语法和约束。在模式中,必须区分类模式和属性模式的对象,类是属性的集合,有了类,就可以支持单
4、一继承。从图22-3中可以看出,user类派生自organizationalPerson类,而organizationalPerson是person的一个子类,它们的基类都是topoclassSchema定义了一个类,它用systemMayContain属性描述了属性。在图22-3中,只列出了几个systemMayContain值。使用ADSIEdit工具可以看到所有的值。下一4节将介绍这些值。在根类top中,每个对象都有公共的名称(cn)、displayName、objectGUID、whenChanged和whenCreated属性。Person类派生自topoPerson对象也有user
5、Password和telephoneNumber 0 OrganizationalPerson派生白Person。除了Person的属性外,它还杳manager、department、company属性,以及user登录系统所必须的其他属性。.646.第III部分数据top cn displayName distingui shedName objectGUID whenChanged whenCreated mayContain mustContaln 图22-322.2 Active Directory的管理工具学习一些管理工具有助于理解ActiveDirectory、其中包含的数据,以及
6、可编程完成的任务。系统管理员可以用许多工具输入新数据,更新数据和配置ActiveDirectory 0 Active Directory Users and Computers MMC工具可以更新用户数据、输入新用户。Active Directory Sites and Services MMC工具可以配置域中的站点,在这些站点之间复制数据。Active Directory Domains and Trusts MMC工具可以在树的域之间建立信任关系。ADSI Edit是ActiveDirectory的编辑器,可以查看和编辑所有的对象。22.2.1 Active Directory Users
7、 and Computers工具Active Directory Users and Computers管理单元主要由系统管理员用来管理其用户。选择Start1 Programs 1 Administrative Tools 1 Active Directory Users and Computers,就会启动这个程序,得到如22-4所示的屏幕图。臼.11:.:甸OCl1l.,C晒oI第22章使用ActiveDirectory Usel3 Secunty Gro叩O.QlIIfUaer,.,.SecunlY ulO-.DNS Aci晴、,ita,Grq SecuntvG.DNSd酬IsWI-C
8、.四lAm.s回LlMIyGIO叩0.,幽d如IIlIIr lOraC S回盼GlOl4l.AI WClkttat町、,.叫帽睛Ca唱bSecunlyG刷OI.C)AI cb H唱bolen.ntt Seeu句y(j IOCI.dC:Im酬瞄翩S舷吧YGIOI.C)AI dCntairI u,.,Srunly GIO呻OM.响d,*-四,.田-5cunty GIO.,.晴刷刷.睛glOl4)C-in U圃也明配C恨.101d.5ecunty GIO崎G,阳帕饵*.回s.S阻呻6刷早阳、WOlk.,内回回Ilow.队.CC(Ui iof 咽。,、刷L队.t-Iacc队,嚼阳W嗣m盹图22-4.6
9、47.使用这个工具可以添加和修改用户、组、联系人、组织单元、打印机、共享文件夹和计算机。修改己有的工页。在屏幕图22-5中,可以为user对象输入属性:办公室、电话号码、电子邮件、Web页面、公司信息、地址和组等。图22-5Active Directory Users and Computers还可以用于有上百万对象的大公司。我们不必在有1000个对象的列表中查找,而可以使用一个定制过滤器,只显示某些对象,也可以执行LDAP查询,搜索公司中的对象。本章后面将讨论这些问题。22.2.2 ADSI Edit工具ADSI Edit是ActiveDirectory的编辑器。这个工具不能自动安装。在Wi
10、ndowsServer 2000 或WindowsServer 2003 CD上有一个目录SupportingToo1so安装了支持的工具后,执行程序adsiedit.msc,就可以访问该工具。ADSI Edit提供的控制比ActiveDirectory Users and Computers工具更多。使用ADSIEdit,.648.第III部分数据可以配置所有的一切,也可以查看模式和配置。但这个工具的使用并不是很容易,而且很容易输入错误的数据,如图22-6所示。日每剑051E 1ft t-目D晒叫昏也oc:l叫句口.-回b口erl囱.gOU.。酣皿禽由雹 呻HDSCuoIa幡口.斗。,甸、O
11、.间om 图22-6唰、.回L翩剧创IIJGI吼DU.W,唰明跑阴阳orl崎MC创.s阳在.RotW。1.0Ura槐p,副C町、.d、唱打开对象的Properties窗口,可以查看和修改ActiveDirectory中对象的每个属性,例如必选属性、可选属性、属性的类型和值等,如图22-7所示。Distr唱.ished800II皿TAUEgivenNar回Unc国eStrng Dmlion.遭町lCeTypeInteger IadLf lrgo Int筒.1.0 U此吨onL剧唱.1,阳胃1.0 Iog证:OuntInteger 0 modifyTimeSt_ UTC Co扣dTi.14.09.
12、2003汩汩27m.oS-A阴阳I阴暗d.Int.,0 m.oS-K句Wersior制U.1川崎er2 msDS羽00队ltrbJeM.Urcode SI而唱图22-722.3 Active Directory编程要为ActiveDirector开发程序,可以使用System.DirectoryServices或System.DirectoryServices.Protocols命名空间中的类。在System.DirectoryServices命名空间中,有封装了ActiveDirectory Service Interfaces(ADSI)COM对象的类,它们可以访问ActiveDirect
13、ory。ADSI是一个目录服务的编程接口。ADSI定义了一些由ADSI提供程序实现的COM接口。客户可以在相同的编程接口中使用不同的目录服务。System.DirectoryServices命名空间中的.NETFramework类可以使用ADSJ接口。在图22-8中,有一些实现COM接口(如IADs和IUnknown)的ADSI提供程序(LDAP、WinNT和NDS)。程序集S)吼em.DirectoryServices使用ADSI提供程序。第22章使用ActiveDirectory Assembly Sy目em.DlrectoryServl国SUnknown IADs LDAP Active
14、 Provi曲rI I Directory Unknowr、IApS I WinNT Provider Unknown WinNT NDS I I N田ellIADs Prov曲r图22-8.649.System.DirectoryServices.Protocols命名空间中的类使用DirectoryServices Markup Language(DSML)Services for WindowsoOASIS组(http:/www.oasis-open.org/committees/dsml)利用DSML定义了标准化的Web服务接口。要使用System.DirectoryServices命
15、名空间中的类,必须引用System.DirectoryServices程序集。使用这个程序集中的类可以查询对象、查看和更新属性、搜索对象、把对象移动到其他容器对象中。在本节后面的代码段中,将使用一个简单的C#控制台应用程序,来明了如何使用System.DirectoryServices命名空间中的类。本节将介绍:System.DirectoryServices命名空间中的类。连接ActiveDirectory的处理方式:绑定。获取目录工页,创建新对象,并更新己有的项目。搜索ActiveDirectory。22.3.1 System.DirectoryServices命名空间中的类表22-1列出
16、了System.DirectoryServices命名空间中的主要类。类Directory Entry DirectoryEntries 表22-1说阴这个类是System.DirectoryServices命名空间中的主类。这个类的对象表示Active Directory库中的一个对象。使用这个类可以绑定对象,查看和更新属性。对象的属性都放在PropertyCoIlection中。PropertyColIection中的每个元素都有一个PropertyValueCollectionDirectoryEntries是Dire币toryEntry对象的一个集合。DirectoryEntry对象的
17、Children属性返回DirectoryEntries集合中的一个对象列表 650 第皿部分数据(续表)类说明DirectorySearcher 这个类主要用于用指定的属性搜索对象。要定义该搜索,可以使用SortOption类和枚举SearchSpe、SortDirection和ReferaJChasingOption。搜索的结果是个SearchResuJt或SearchResultColJection。也可以得到IJResuJtPropertyCoJlection和ResultProperty VaJueCoJlection对象22.3.2 绑定要获得ActiveDirectory中4个对
18、象的值,必须连接ActiveDirectory服务。这个连接过程称为绑定,绑定路径如下所示。LDAP:/dcO 在绑定过程中,可以指定下述内容:协议(protocol)指定要使用的提供程序。域控制器的服务器名(servername)。服务器过程的端口号。ortnumber)。对象的显名(distingunshedname),以标识要访问的对象。如果需要访问ActiveOirectory的用户不是当前登录的账户,则提供用户名和密码。如果需要加密,应指定authentication类型。F面详细介绍这些内容。1.协议绑走路径的第一部分指定AOSI提供程序。该提供程序是一个COM服务器;prog-i
19、d的标识信息在注册表的HKEY-CLASSES-ROOT下。WindowsXP附带的提供程序如表22-2所示。2.服务器名 在绑定路径中,服务器名在协议的后面。如果用户登录到ActiveOirectory域上,服务器名就是可选的。如果不提供服务器名,就会发生无服务器绑定操作,此时WindowsServer 2003 会在域中查找与用户绑定过程相关的最好的域控制器。如果站点中没有服务器,就使用查找到的第一个域控制器。无服务器的绑定如下所示:LDAP:/OU=Sales,DC=Thinktecture,DC=Local 提供程序LDAP GC 表22-2说明LDAP服务器,例如Exchange目录
20、和Windows2000 Server或WindowsServer 2003 Active Directory服务器GC用于访问Activepirjlctory中的全局目录。它也可以用于快速查询第22章使用ActiveDirectory 651 (续表)提供程序说明IIS 使用IlS的ADSI提供程序,可以在IIS目录中创建和管理新网站WinNT 要访问旧WindowsNT 4域的用户数据库,可以使用WinNT的ADSI提供程序。NT4用户只有几个属性没有改变。也可以使用这个协议绑定Windows2000 域,但这里也限制了可用于NT4的属性NDS NWCOMPAT 3.端口号这个progID
21、用于和NovellDirectory Services通信使用NWCOMPAT可以访问旧的NovelJ目录,例如NovelJNetware 3.x 在服务器名的后面,可以指定服务器过程的端口号,其语法是:XXXoLDAP服务器的默认端口号是端口389:LDAP:lldcO:389o Exchange服务器使用的端口号与LDAP服务器一样。如果在同一个系统上安装了Exchange服务器,例如用作ActiveDirectory的域控制器,就可以配置另一个端口。4.显名在路径中指定的第四部分是显名(distinguishedname,DN)。显名是一个惟一的名称,标识要访问的对象。在ActiveDi
22、rectory中,可以使用基于X.500的LDAP语法,指定对象的名称。例如有一个显名:CN=Christian Nagel,OU=Consultants,DC=Thinktecture,DC=local 这个显名指定域Thinktecture.local中域组件(DomainComponent,DC)Thinktecture的组织单5G(Organizational Unit,OU)Consultants的公共名称(CommonName,CN)Christian Nagel。最右边的部分是域的根对象。该名称必须符合对象树中的分层方式。显名的宇符串表示的LDAP规范在RFC2253(h句:/w
23、ww.ietf.orglrfc/的2253.txt)上。(1)相对显名相对显名(RDN)用于引用容器对象中的对象。使用RDN时,不需要指定OU和DC,有一个公共名称就足够了。CN=ChristianNagel就是组织单元中的一个相对显名。如果已经引用了一个容器对象,要访问其子对象,就可以使用相对显名。(2)默认的命名环境如果在路径中没有指定显名,绑定过程就会使用默认的命名环境(defaultnaming context)。使用rootDSE可以读取默认命名环境。LDAP3.0把rootDSE定义为目录服务器中目录树的根。例如LDAP:llrootDSE 或:LDAP:lIservemame/r
24、ootDSE 通过枚举rootDSE的所有属性,将获得没有指定名称时使用的defaultNamingContext信息。schemaNamingContext和configurationNamingContext指定了用于访问模式和ActiveDirectory库.652.第III部分数据中配置所需要的名称。通过下面的代码可获得rootDSE的所有属性:using(DirectoryEntry de=new DirectoryEntry()de.Path=LDAP:/treslunas/rootDSE;de.Username=explorerchristian;de.Password=pass
25、word;PropertyCollection props=de.Properties;foreach(string prop in props.PropertyNames)PropertyValueCollection values=propsprop;foreach(string val in values)Console.Write(prop+:);Console.W riteLine(val);这个程序显示了默认的命名环境(defaultNamingContextDC=explorer、DC=local),用于访问模式的环境(CN=Schema、CN=Configuration、DC=
26、explorer、DC=local)和配置的命名环境(CN=Configuration、DC=explorer、DC=local),如图22-9所示。图22-9(3)对象标识符每个对象都有一个全局惟一的标识符GUIDoGUID是一个惟一的128位数字,您可能已经在COM开发中了解了它。使用GUID可以绑定一个对象。这样,即使对象移动到另一个容器中,也可以得到该对象。GUID在创建对象时生成,且总是保持不变。使用DirectoryEntry.NativeGuid可以得到GUID的字符串表示。这个字符串表示就可以用于绑定对象。下面的示例显示了一个无服务器绑定的路径名称,它绑定到GUID代表的一个特
27、定对象上:LDAP:/第22章使用ActiveDirectory.653.5.用户名有时,在访问目录时,必须使用一个非当前进程的用户名(也许这个用户没有访问ActiveDirectory所必须的许可),此时必须为绑定过程显式指定用户证书(usercredential)0 Active Directory提供了许多方式来设置用户名。(1)Downlevel登录使用downlevel登录,用户名可以用Windows2000以前的域名来指定:domainusemame(2)显名也可以用user对象的显名来指定用户,例如:CN=Adminstrator.CN=Users.DC=thinktecture
28、.DC=local(3)User Principal Name(UPN)对象的UPN用userPrincipalName属性来定义。系统管理员可以在ActiveDirectory Users and Computers工具中User属性的Account选项卡上,用登录信息来指定UPN,注意,这不是用户的电子邮件地址。这些信息也惟一地标识了用户,可以用于登录:Nagel thinktecture.local 6.身份验证为了给身份验证进行安全的加密,也可以指定身份验证(authentication)类型。身份验证可以用DirectoryEntry类的AuthenticationType属性设置。
29、可以指定其值为AuthenticationTypes枚举中的一个值。因为枚举是用属性Flags标识的,所以可以指定多个值。其可能的值有ReadonlyServer和SecureoReadonlyServer对发送的数据进行加密,它指定只需要读取访问:Secure表示安全的身份验证。7.用Directo叩Ent叩类绑定System.DirectoryServices.DirectoryEntry类可以用于指定所有的绑定信息。可以使用默认的构造函数,用Path、Usemame、Password和AuthenticationType属性定义绑定信息,或者把这些信息传递给构造函数:DirectoryE
30、ntry de=new DirectoryEntryO;de.Path=LDAP:/platinumIDC=thinktecre,DC=local;de.Usemame=nagel thinktecture.local;de.Password=password;/use the current user credentials DirectoryEntry de2=new DirectoryEntry(LDAP:/IDC=thinktecture,DC=local);.654.第III部分数据即使成功地构造了DirectoryEntry对象,也并不意味着绑定成功了。在第一次读取属性时进行绑定,
31、可以避免不必要的网络流通量。对象是否存在,或者指定的用户证书是否正确,都可以在第次访问该对象时确定。22.3.3 获取目录项前面介绍了如何指定ActiveDirectory中对象的绑起属性,-f面要读取对象的属性。在下面的示例中要读取用户对象的属性。Directory Entry类的一些属性可以提供对象的信息,即Name、Guid和SchemaClassName属性。第4次访问DirectoryEntry对象的属性时,会执行绑定操作,并填充底层ADSI对象的缓存。后面将详细讨论这些。其他属性可以从缓存中读取,I司一对象的数据不需要通过与服务器的通信未获得。在本例中,用组织单元WroxPress
32、中的公共名称ChristianNagel访问个用户对象:using(DirectoryEntry de=new DirectoryEntry()提示:de.Path=LDAP:/treslunas/CN=Christian Nagel,+OU=Thinktecture,DC=explorer,DC=local;Console.WriteLine(Name:+de.Name);Console.WriteLine(GUID:+de.Guid);Console.WriteLine(Type:+de.SchemaClassName);Console.WriteLineO;/.要在计算机上运行这段代码,
33、必须修改要访问的对象路径,使之包含服务器名。Active Directory对象包含许多信息,这些信息取决于对象的类型。属性Properties将返回-个PropertyCollection。每个属性本身就是一个集合,因为一个属性可以有多个值,例如,user 对象可以有多个电话号码。在本例中,用一个内部foreach循环查看这些值。从propertiesname J 返回的集合是4个object数组。属性值可以是字符申、数字或其他类型。使用ToStringO方法就可以显示这些值:Console.WriteLine(Properties:);PropertyCol1ection properti
34、es=de.Properties;foreach(string name in properties.PropertyNames)foreach(object 0 in propertiesname)Console.WriteLine(name+:+o.ToString();第22章使用ActiveDirectory.655.在得到的结果中,包含了user对象ChristianNagel的所有属性,如图22-10所示。OtherTelephone是一个多值属性,它包含许多电话号码。一些属性值只显示System.一ComObject对象的类型,例如,lastLogoff、las比ogon和nTS
35、ecurityDescriptor。要得到这些属性的值,必须直接使用System.DirectoIServices命名空间的类中的ADSICOM接口。图22-10注意:第33章介绍了如何使用COM对象和接口。直接通过名称访问属性使用DirectoryEntry.Properties可以访问所有属性。如果己知属性名,就可以直接访问其值:foreach(string homePage in de.PropertieswWWHomePage)Console.WriteLine(Home page:+homePage);22.3.4 对象 1=1 对象在ActiveDirectory中是分层存储的。容
36、器对象包含子对象。使用DirectoryEntry类的Children属性可以枚举容器中的子对象。另一方面,使用Parent属性可以得到对象的容器。用户对象没有子对象,所以下面的示例使用一个组织单元,如图22-11所示。非容器对象用Children属性返回一个空集合。下面在域thinktecture.1ocal的组织单元WroxPress中获得其所有的用户对象。Children属性返回一个DirectoryEn tri es集合,其中包含DirectoryEntry对象。选代所有的DirectoryEntry对象,显示子对象的名称。using(DirectoryEntry de=new Dir
37、ectoryEn仕y()de.Path=LDAP:/platinumlOU=thinktecture,+DC=explorer,DC=local Console.WriteLine(Children of+de.Name);foreach(DirectoryEntry obj in de.Children)Console.WriteLine(obj.Name);.656.第III部分数据图22-11本例显示了组织单元中的所有对象:users、contacts、printers、shares和其他对象。如果只需要查看某些对象类型,可以使用DirectoryEntries类的SchemaFilte
38、r属性。SchemaFilter属性返回一个SchemaNameCollection。有了这个SchemaNameCollection,就可以使用AddO方法定义要查看的对象类型。在本例中,因为只需要查看user对象,所以把user添加到这个集合中:using(DirectoryEntry de=new DirectoryEntry()de.Path=LDAP:/platinum/OU=Thibktectrue,+DC=explorer,DC=local Console.WriteLine(Children of+de.Name);de.Children.SchemaFilter.Add(us
39、er);foreach(DirectoryEntry obj in de.Children)Console.WriteLine(obj.Name);结果,只显示组织单元中的user对象,如图22-12所示。图22-1222.3.5 缓存为了减少网络流通量,ADSI使用缓存来存储对象属性。如前所述,在创建DirectoryEntry对象时是不访问服务器的。只要从目录库中读取第一个属性,所有的属性都会写到缓存中,这样,在读取下一个属性时,就不需要往返于服务器了。写入对象的改变,只会改变己缓存的对象。设置属性不会产生网络流通量。必须使用第22章使用ActiveDirectory.657 Direct
40、ory Entry.CommitChangesO刷新缓存,把所高己改变的数据传送回服务器。要再次从目录库中获取新写入的数据,可以使用DirectorEntry.RefreshCacheO读取属性。当然,如果没有调用CommitChangesO和RefreshCacheO就修改了一些属性,所有的改变都会丢失,因为我们将再次使用RefreshCacheO读取目录服务中的值。把属性DirectoryEntry.U sePropertyCache设置为false,就可以关闭这个属性缓存。但除非在进行调试,否则最好不要关闭它,因为这会与服务器间产生许多不必要的往返通信。22.3.6 创建新对象创建新Ac
41、tiveDirectory对象时,例如users、computers、printers和contacts等,可以使用DirectoryEntries类以编程的方式来完成创建工作。要给目录添加新对象,首先必须绑走一个容器对象,例如组织单元,可以在其中插入新对象。不包含其他对象的对象是不能使用的。下面使用个容器对象,其显名为CN=Users,DC=thinktectrue,DC=local:DirectoryEntry de=new DirectoryEntry();de.Path=LDAP:lltres1unas/CN=Users,DC=athenaproject,DC=lal;使用Direct
42、oryEntry的Children属性,可以得到一个DirectoryEntries对象:DirectoryEntries users=de.Children;Directory Entries类提供的方法可以添加、删除和查找集合中的对象。下面创建一个新的user对象。使用AddO方法时,需要一个对象名和一个类型名。使用ADSIEdit很容易获得类型名:DirectoryEntry user=users.Add(CN-John Doe,user);对象现在有了默认属性值。要指定特定的属性值,可以使用Properties属性的AddO方法添加属性。当然,所有的属性都必须存在于user对象的模式中
43、。如果指定的属性不存在,就得到个COMException指定的目录服务属性或值不存在:user.Properties company.Add(咆omeCompany);user.Properties department.Add(咆ales);user.Propertiesemp1oyeeID).Add(4711);user.Properties samAccoun创ame1.Add(JDo的;user.PropertiesuserPrincipaIName.Add(JDoe exp1orer.1oca1);user.PropertiesgivenN缸ne.Add(John);user.Pro
44、pertiessn1.Add(D饵);user.PropertiesuserPassword1.Add(someSecret);此时,为了把数据写入ActiveDirectory,必须刷新缓存:user.CommitChangesO;.658.第III部分数据22.3.7 更新目录项Active Directory服务中对象的更新和读取一样简单。可以在读取对象后修改它们的值。要删除一个属性的所有值,可以调用PropertyV al ueCo llection.C 1阔的方法。使用AddO,可以把新值添加到属性中。RemoveO和RemoveAtO可以从属性集合中删除指定的值。要修改一个值,可以
45、把这个值设置为指定的值。下面的代码将通过PropertyValueCol1ection的一个索引符把移动电话号码设置为-个新值。使用该索引符,只能改变己存在的值。因此,应使用DirectoryEntry.Properties.ContainsO来确定属性是否可用。using(DirectoryEntry de=new DirectoryEntry()de.Path=LDAP:/treslunas/CN=Christian Nagel,+OU=Thinktectrue,DC=explorer,DC=local;if(de.Properties.Contains(mobile)de.Propert
46、iesmobleO=+43(664)3434343434飞else de.Propertiesmobile.Add(+43(664)3434343434);de.CommitChangesO;在本例的else部分,如果移动电话号码不存在新属性,就用方法PropertyValue-Collection.AddO添加它。如果对已有的属性使用AddO方法,得到的结果将取决于属性的类型:单值属性或多值属性。对已有的单值属性使用AddO方法,会得到一个COMException:A constraint violation occurred。对己有的多值属性使用AddO方法,则会成功地把另一个值添加到属性
47、中。user对象的属性nobile定义为单值属性,所以不能添加其他移动电话的号码。但是用户可以有多个移动电话的号码。对于多个移动电话的号码,可以使用属性otherMobile,它是一个多值属性,允许设置多个移动电话号码,所以可以调用AddO多次。注意,对多值属性要检查其惟一性。如果把第二个电话号码添加到同一个user对象上,也会得到一个COMException:指定的目录服务属性或值已经存在。提示:在创建或是新目录对象后,应调用DirectoryEntry.CommitChangesO。否则只能更新缓存中的信息,改变的信息不会发送到目录服务上。22.3.8 访问内部的ADSI对象调用预定义的A
48、DSI接口方法常常比搜索对象的属性名容易得多。一些ADSI对象还支持不能在DirectoryEntry类中直接使用的方法。例如IADsServiceOperations接口有启动和停止 第22章使用ActiveDirectory.659.Windows服务的方法。Windows服务将在第36章讨论。如前所述,System.DirectoryServices命名空间的类使用底层的ADSICOM对象。DirectoryEntry类支持直接使用InvokeO方法调用底层对象的方法。InvokeO的第一个参数是应在ADSI对象中调用的方法名,第二个参数的params关键字允许把数量可变的其他参数传送给
49、ADSI方法:public 0均ectInvoke(string methodName,params 0均ect口吨。;在ADSI文档中介绍了可以用InvokeO方法调用的方法。域中的每个对象都支持IADs接口的方法。前面创建的user对象也支持IADsUser接口的方法。在下面的代码示例中,使用方法IADsUser.SetPasswordO改变前面创建的user对象的密码:using(DirectoryEntry de=new DirectoryEntry()de.Path=LDAP:/treslunas/CN=John Doe,+CN=Users,DC=explorer,DC=local;
50、de.lnvoke(SetPassword,anotherSecret);de.CommitChangesO;如果不使用InvokeO,还可以直接使用底层的ADSI对象。要使用这些对象,必须使用ProjectI Add Reference添加对ActiveDS类型库的引用,如图22-13所示。这会创建一个包装器类,在该类中可以访问ActiveDS命名空间中的这些对象。内部对象可以使用DirectoryEntry类的NativeObject属性来访问。在下面的示例中,对象de是一个user对象,所以可以把它强制转换为ActiveDs.IADsUser.SetPasswordO是在IADsUser