War diese Seite hilfreich?
Ihr Feedback ist uns wichtig. Teilen Sie uns Ihre Meinung mit.
Weiteres Feedback?
1500 verbleibende Zeichen
Exportieren (0) Drucken
Alle erweitern
Erweitern Minimieren

Verwenden von System.DirectoryServices für die Suche in Active Directory

Veröffentlicht: 17. Jan 2003 | Aktualisiert: 23. Jun 2004
Von Duncan Mackenzie

In diesem Artikel werde ich detailliert erläutern, wie Sie den System.DirectoryServices-Namespace verwenden können, um eine Verbindung zu Active Directory herzustellen, nach Objekten zu suchen und die Suchergebnisse anzuzeigen. Natürlich kann der System.DirectoryServices-Namespace nicht nur für Active Directory verwendet werden - er kann für viele unterschiedliche Dienste genutzt werden, einschließlich des weit verbreiteten LDAP-Protokolls - aber in meinen Beispielen werden ich mich auf Active Directory konzentrieren.

Bitte beachten Sie, dass die Kommentare der Programmierer in den Beispieldateien englischsprachig sind. Zum leichteren Verständnis wurden sie in diesem Artikel übersetzt.

Auf dieser Seite

Einführung Einführung
Wechseln von ADSI zu "System.DirectoryServices" Wechseln von ADSI zu "System.DirectoryServices"
Herstellen einer Verbindung Herstellen einer Verbindung
Binden an einen Verzeichnispfad Binden an einen Verzeichnispfad
Verzeichnisauthentifizierung Verzeichnisauthentifizierung
Durchführen einer Suche Durchführen einer Suche
Zusätzliche Optionen Zusätzliche Optionen
Erstellen einer Schnellsuchdemo Erstellen einer Schnellsuchdemo
Verschieben der Suche in einen Hintergrundthread Verschieben der Suche in einen Hintergrundthread
Datenbindung mit "DirectoryServices"-Objekten Datenbindung mit "DirectoryServices"-Objekten
Zusammenfassung Zusammenfassung

Einführung

Active Directory ist eine spezielle Datenbank, die unternehmensweit repliziert wird und problemlos erweitert werden kann. Somit eignet sie sich ideal zum Speichern von Benutzerinformationen, der Netzwerkkonfiguration und anderen Daten, die in einem Unternehmen für den globalen Zugriff bereitgestellt werden müssen. Active Directory ist eines der leistungsstärksten Betriebssystemfeatures. Daher ist es empfehlenswert, Active Directory beim Erstellen von Anwendungen einzusetzen, wenn es in Ihrem Unternehmen verfügbar ist.

Allerdings werde ich nicht ausführlich auf Active Directory eingehen. Weitere Informationen zu Active Directory finden Sie in den folgenden Referenzdokumenten:

Wechseln von ADSI zu "System.DirectoryServices"

Diejenigen unter Ihnen, die noch keine Erfahrungen in der Programmierung mit Active Directory gesammelt haben, wundern sich vielleicht über all die ADSI-Verweise auf der MSDN-Website und in anderen Ressourcen. ADSI (Active Directory Service Interfaces) ist eine COM-Bibliothek, die eine Interaktion mit Active Directory über Nicht-.NET-Sprachen ermöglicht. Es ist die gängigste Methode für den Zugriff auf Verzeichnisinformationen unter Verwendung von Microsoft Visual Basic 6.0, Visual Basic für Applikationen (VBA) und Skriptingsprachen. Daher befassen sich viele Beispiele und Newsgrouppostings zum Thema Active Directory mit ADSI.

Die gute Nachricht ist, dass viele in ADSI verwendete Konzepte problemlos für die Verwendung in System.DirectoryServices konvertiert werden können - das gleiche gilt für beliebige ADSI-Pfade oder Eigenschaftennamen, die in einem ADSI-Beispiel enthalten sind. Es ist auch möglich, Code innerhalb der COM- und .NET-Bibliotheken auszutauschen. Mehrere Methoden und Eigenschaften im System.DirectoryServices-Namespace akzeptieren ADSI-Objekte als Parameter. Auch wenn Sie noch nie ADSI verwendet haben, wird es Ihnen nicht schwerfallen, System.DirectoryServices zu erlernen und zu verwenden.

Herstellen einer Verbindung

Es gibt zwei Hauptklassen im System.DirectoryServices-Namespace: DirectoryEntry und DirectorySearcher. (Es sind mehrere weitere Klassen vorhanden, aber diese beiden Klassen sollten Sie zuerst verwenden.) Die Suche wird mit der DirectorySearcher-Klasse durchgeführt. Diese kann entweder ohne Festlegen von Optionen oder durch das Bereitstellen eines DirectoryEntry-Stammobjekts verwendet werden.

Beim Erstellen eines DirectoryEntry-Objekts, das als Stamm verwendet werden soll, müssen Sie einen Pfad angeben, der den Dienst beschreibt, zu dem Sie eine Verbindung herstellen. Sie geben auch Ihre Anmeldeinformationen an. Durch das Erstellen dieses einzelnen Objekts wird eine Verbindung zu Ihrem Verzeichnis hergestellt. Sie können diese Verbindung für Ihre Abfragen verwenden, indem Sie dieses DirectoryEntry-Objekt als Stamm für Ihre Suche verwenden. Wenn Sie kein Stammobjekt angeben, stellt das DirectorySearcher-Objekt automatisch eine Bindung zur aktuellen Domäne her und verwendet Ihre Microsoft® Windows®-Anmeldeinformationen zur Authentifizierung.

Binden an einen Verzeichnispfad

Zum Herstellen einer Verbindung zu Active Directory können Sie entweder einen Pfad mithilfe der Global Catalog (GC://)-Syntax angeben, oder Sie können einen Standard-LDAP-Pfad (LDAP://) verwenden. Die Syntax und der Pfad, die verwendet werden sollen, hängen von Ihrer Netzwerkumgebung ab. Ich habe mich z.B. für mein internes Netzwerk für die Global Catalog-Syntax entschieden, da sie es mir ermöglicht, eine Suche im gesamten Unternehmensnetzwerk (in der Active Directory-Gesamtstruktur) durchzuführen. Statt eines Pfades einschließlich Servernamen habe ich nur "GC://dc=home,dc=duncanmackenzie,dc=net" (in der Annahme, dass meine Domäne home.duncanmackenzie.net lautet) angegeben. Dadurch wird die ADSI veranlasst, eine Verbindung zu einem globalen Katalogserver für die angegebene Domäne herzustellen. Wenn Sie möchten, können Sie auch eine Verbindung ohne Pfadangabe herstellen. Wenn Sie ein DirectorySearcher-Objekt verwenden, ohne dass ein Stammobjekt angegeben ist, verwendet das Objekt automatisch die aktuelle Domäne für die Suche. Weitere Informationen zum Festlegen des korrekten Pfads für Ihr Netzwerk finden Sie in den folgenden Referenzartikeln:

Verzeichnisauthentifizierung

Nachdem Sie über einen LDAP- oder GC-Pfad verfügen, wenden Sie sich als Nächstes den Anmeldeinformationen zu. Der Konstruktor für die DirectoryEntry-Klasse ermöglicht es Ihnen, eine Benutzer-ID und ein Kennwort festzulegen. Sie können auch die Benutzer-ID- und Kennworteigenschaften festlegen, nachdem Sie Ihre Instanz des Objekts erstellt haben. Speichern Sie das Kennwort bzw. die Benutzer-ID nicht in Ihrem Code. Rufen Sie stattdessen diese Informationen vom Benutzer ab, oder besser noch, verwenden Sie die integrierte Windows-Authentifizierung.

Dim rootEntry _ 
 As New DirectoryEntry("GC://dc=home,dc=duncanmackenzie,dc=net", _ 
  userID.Text, _ 
  password.Text)

Anmerkung:
Damit dieser Code funktioniert, müssen Sie in Ihrem Projekt auf System.DirectoryServices verweisen und die Zeile Imports System.DirectoryServices (Visual Basic .NET) oder using System.DirectoryServices; (C#) oben in die Quelldatei einfügen.

Wenn Sie keine Benutzer-ID und kein Kennwort angeben, versucht System.DirectoryServices eine Verbindung mithilfe der integrierten Windows-Authentifizierung durchzuführen. Im Allgemeinen bevorzuge ich die Option der integrierten Authentifizierung, zumindest in Microsoft® Windows Forms-Anwendungen, da jeder Benutzer in Active Directory nur über die vorhandene Gruppe von Berechtigungen verfügt. Wenn fest codierte Benutzer-IDs und Kennwörter verwendet werden, besteht die Möglichkeit, dass meine Anwendung einem Benutzer umfassendere Zugriffsrechte für Active Directory erteilt, als ihm eigentlich zugewiesen sind, so dass ein Sicherheitsrisiko entsteht.

Durchführen einer Suche

Nachdem Sie Ihr erstes DirectoryEntry-(Stamm-) Objekt erstellt haben, können Sie die DirectorySearcher-Klasse zum Durchführen von Abfragen verwenden. Das Durchführen einer einfachen Suche umfasst nur wenige Schritte:
Erstellen einer Instanz von DirectorySearcher und optionale Verwendung eines DirectoryEntry-Objekts.

  • Setzen des Suchfilters auf eine Zeichenfolge, die Ihre Suchkriterien beschreibt.

  • Auffüllen der PropertiesToLoad-Auflistung mit der Liste von Active Directory-Eigenschaften, die Sie für jedes Suchergebnis abrufen möchten.

  • Ausführen der FindAll-Methode und Abrufen der Ergebnisse.

Bei Bedarf können Sie die meisten dieser Schritte überspringen, um eine Suche mit den Standardeinstellungen durchzuführen. Ist kein DirectoryEntry-Stammobjekt vorhanden, stellt DirectorySearcher eine Bindung zur aktuellen Domäne her. Wenn kein Suchfilter bereitgestellt wird, werden standardmäßig alle Objekte abgerufen, und wenn Sie keine PropertiesToLoad-Werte angeben, werden alle Eigenschaften (für die Sie eine Leseberechtigung besitzen) abgerufen. Diese Standardeinstellungen können die Verwendung von DirectoryServices-Klassen sehr vereinfachen. Ich würde jedoch empfehlen, die Suche mit mindestens einem Filter einzuschränken und die Anzahl der geladenen Eigenschaften zu beschränken, sofern Sie nicht alle Eigenschaften und Objekte für Ihre Anwendung benötigen.

Dim searcher As New DirectorySearcher(rootEntry) 
searcher.PropertiesToLoad.Add("cn") 
searcher.PropertiesToLoad.Add("mail") 
'searcher.PropertiesToLoad.AddRange(New String() {"cn", "mail"}) 
'funktioniert auch und reduziert den Codeumfang 
searcher.Filter = "(&(anr=duncan)(objectCategory=person))" 
Dim results As SearchResultCollection 
results = searcher.FindAll()

Zusätzliche Optionen

Es gibt viele zusätzliche Suchoptionen, die zwar nicht erforderlich sind, aber das Verhalten der Abfrage in hohem Maße beeinflussen können. Im Folgenden sind einige dieser zusätzlichen Optionen sowie eine kurze Beschreibung ihrer Verwendung aufgeführt:

  • CacheResults legt fest, dass die Suchergebnisse lokal auf dem Client gespeichert werden. Wenn Sie diese Einstellung verwenden, können Sie in den Suchergebissen beliebig vor- und zurückwechseln, andernfalls können Sie in den Ergebnissen nur in Vorwärtsrichtung navigieren.

  • ClientTimeout, ServerTimeLimit, ServerPageTimeLimit sind Timeoutwerte, die verhindern, dass eine Suche zu lange ausgeführt wird. Der erste Wert, ClientTimeout, steuert, wie lange der Client wartet. Die anderen beiden Zeitlimits werden vom Server auferlegt. Ich empfehle, mindestens ClientTimeout festzulegen, um zu verhindern, dass Ihre Anwendung für einen unbefristeten Zeitraum wartet. Es muss jedoch beachtet werden, dass beim Erreichen eines serverbasierten Zeitlimits die bis zu diesem Zeitpunkt abgerufenen Einträge zurückgegeben werden. Dagegen werden keine Einträge zurückgegeben, wenn zuerst das Clientzeitlimit erreicht wird. Bedenken Sie, dass für den Server selbst ein Zeitlimit gilt, das vom Administrator konfiguriert werden kann, so dass auf dem Server noch vor dem von Ihnen angegebenen Zeitlimit eine Zeitüberschreitung eintreten kann (und unvollständige Ergebnisse zurückgegeben werden können).

  • PageSize legt die Anzahl der Einträge fest, die gleichzeitig zurückgegeben werden sollen. Wenn Sie die PageSize-Eigenschaft nicht festlegen oder auf 0 setzen, werden alle Ergebnisse gleichzeitig zurückgegeben. Nichtsdestotrotz kann die seitenweise Ausgabe von Ergebnissen (Paging) Ihre Anwendung reaktionsschneller erscheinen lassen. Denken Sie daran, dass der Server entscheidet, wie viele Objekte maximal in einer Suche zurückgegeben werden, um sicherzustellen, dass ein Benutzer das System nicht überlastet. Somit ist Paging immer empfehlenswert, insbesondere wenn umfangreiche Ergebnissätze ausgegeben werden. In einer Demoanwendung am Ende dieses Artikels werde ich Ihnen zeigen, wie Sie Paging zusammen mit Multithreading verwenden können, um eine Suche ohne Wartezeiten für den Benutzer zu generieren.

Arbeiten mit den Ergebnissen

Nachdem Sie eine Suche durchgeführt haben, wird eine Instanz der SearchResultCollection-Klasse zurückgegeben, mit der Sie die Ergebnisse in Form einer Enumeration durchlaufen können. Es ist dabei unerheblich, ob Sie Paging verwendet haben oder nicht. Der Zugriff auf die Suchergebnisse geschieht auf die gleiche Weise. Wenn die nächste Ergebnisseite noch nicht verfügbar ist, wird Ihre Auflistung gesperrt, bis die Ergebnisse vorliegen.

Dim result As SearchResult 
For Each result In results 
 MessageBox.Show(result.Properties("cn")(0)) 
Next

Erstellen einer Schnellsuchdemo

Um alle Schritte zusammenzufassen, habe ich eine einfache Anwendung erstellt, die eine Suche in Active Directory durchführt. Dieses Beispiel ist im Download für diesen Artikel enthalten, (klicken Sie auf den Link oben in diesem Artikel). Oder Sie können einfach nur weiter diesem Artikel folgen, wenn Sie die Suche selbst erstellen möchten.

Um die Suche korrekt zu konfigurieren, einschließlich Sicherheitsoptionen, musste ich auf dem Windows Form, mit dem ich begonnen hatte, einige Steuerelemente einrichten. Ich erstellte vier TextBox-Steuerelemente (für den Stammpfad, die Suchzeichenfolge, die Benutzer-ID und das Kennwort), ein CheckBox-Steuerelement, um zwischen der integrierten Windows-Authentifizierung und dem Verwenden einer Benutzer-ID und eines Kennworts wechseln zu können, eine Schaltfläche zum Ausführen der Suche und ein ListBox-Steuerelement für die Ergebnisse. Ich habe einige Momente damit verbracht, meine Steuerelemente anzuordnen und Anchor-Eigenschaften festzulegen, um eine Benutzeroberfläche mit einer einigermaßen ansprechenden Darstellung zu erstellen, die auch Größenänderungen unterstützt, aber das ist natürlich optional.

dotnetadsearch_fig1

Abbildung 1. Mit dem ausgefüllten Formular können Sie eine einfache Suche durchführen

Jetzt verwende ich im Klickereignis meiner Schaltfläche die in den vier TextBox-Steuerelementen und dem CheckBox-Steuerelement eingegebenen Werte, um meine Suche durchzuführen.

Dim rootEntry _ 
 As New DirectoryEntry(rootPath.Text) 
If Not integratedAuth.Checked Then 
 rootEntry.Username = userID.Text 
 rootEntry.Password = password.Text 
End If 
Dim searcher As New DirectorySearcher(rootEntry) 
searcher.PropertiesToLoad.Add("cn") 
searcher.PropertiesToLoad.Add("telephoneNumber") 
'searcher.PropertiesToLoad.AddRange(New String() {"cn", "mail"}) 
'funktioniert auch und reduziert den Codeumfang 
searcher.PageSize = 5 
searcher.ServerTimeLimit = New TimeSpan(0, 0, 30) 
searcher.ClientTimeout = New TimeSpan(0, 10, 0) 
searcher.Filter = searchString.Text 
Dim queryResults As SearchResultCollection 
queryResults = searcher.FindAll()

Nach dem Erhalt der Ergebnisse füge ich jedes einzelne dem ListBox-Steuerelement hinzu.

Dim result As SearchResult 
For Each result In queryResults 
 results.Items.Add(result.Properties("cn")(0)) 
Next

Anmerkung:
Eine der schwierigeren Aufgaben bei der Verwendung des System.DirectoryServices-Namespace ist zu wissen, welche Eigenschaften verwendet werden sollen und wie diese abgerufen werden. Eine gute Quelle für Active Directory-Eigenschaftennamen, zumindest wenn es um Benutzer und Konten geht, ist die SDK-Referenz (in Englisch), die Eigenschaftennamen den Informationen aus dem Snap-In Benutzer und Gruppen in Windows zuordnet. Bedenken Sie, dass viele Eigenschaften mehrwertig sein können, so dass der Wert einer Eigenschaft als Array offen gelegt wird, das eine beliebige Anzahl von Werten enthalten kann. Im Beispiel rufe ich den Wert der cn-Eigenschaft ab, indem ich auf das erste Element des Eigenschaftenwertarrays zugreife. Dies funktioniert nur, weil ich weiß, dass die cn-Eigenschaft nur einen einzelnen Wert enthält. Wenn Sie mit vielen unterschiedlichen Eigenschaften arbeiten, müssen Sie wahrscheinlich für jede einzelne Eigenschaft prüfen, ob sie ein- oder mehrwertig ist. Die Active Directory-Schemareferenz in MSDN eignet sich sehr gut für diesen Zweck. Sie enthält Informationen zu jeder Eigenschaft (auch als Attribut bezeichnet), einschließlich Datentyp und Angaben darüber, ob die Eigenschaft ein- oder mehrwertig ist.

Wenn die Suche abgeschlossen ist, können Sie eine Suche in Active Directory durchführen, wie im obigen Beispiel veranschaulicht. Zunächst möchte ich aber noch auf zwei Probleme eingehen. Das erste Problem ist, dass diese Suche auf demselben Thread wie meine Benutzeroberfläche (das Formular) ausgeführt wird, das heißt dass meine Benutzeroberfläche nicht mehr reagiert, wenn mein Code auf eine Antwort von den DirectoryServices-Objekten wartet. Das zweite Problem ist, dass ich meine abgerufenen Ergebnisse manuell dem ListBox-Steuerelement hinzufüge. Viele Programmierer verwenden aber stattdessen die Datenbindung, um eine Gruppe von Daten mit einer Benutzeroberfläche zu verbinden. Im weiteren Verlauf dieses Artikels werde ich Ihnen zeigen, wie Sie mithilfe eines Hintergrundthreads eine reaktionsschnelle Benutzeroberfläche schaffen und zur Laufzeit ein DataTable-Objekt erstellen können, um eine Datenbindungsfunktionalität bereitzustellen.

Verschieben der Suche in einen Hintergrundthread

Jedes Mal, wenn ich einen Task (einen beliebigen Task, nicht nur DirectoryServices-Arbeit) auf einem Hintergrundthread ausführen möchte, folge ich unweigerlich demselben Muster. Zunächst werde ich das Muster beschreiben. Anschließend zeige ich Ihnen, wie ich es auf einen bestimmten Task der Verzeichnissuche angewendet habe.

Ich erstelle eine Klasse, um meinen Hintergrundtask zu kapseln. Diese Klasse umfasst Folgendes:

  • Eigenschaften, die zum Konfigurieren des Tasks verwendet werden.

  • Eine Methode, die keine eigenen Parameter akzeptiert (aus diesem Grund verwende ich Eigenschaften) und auf einem neuen Thread ausgeführt wird.

  • Ein Ereignis oder Ereignisse, die ausgelöst werden, um über den Fortschritt (und das Ende) des Hintergrundtask zu informieren.

Anmerkung:
Wenn ich dieses Muster von einem Windows Form aus verwende, muss ich verhindern, dass das Formular aufgrund der Ereignisse, die von dem Hintergrundtask ausgelöst werden, selbst aktualisiert wird und die Invoke-Methode des Formulars verwenden, um korrekt zwischen den beiden Threads zu marshallen.

Um dieses Musters auf das zuvor erstellte einfache Suchbeispiel (erstellt das DS Background-Projekt in der Downloaddatei) anzuwenden, muss eine neue Klasse hinzufügt werden: BackgroundSearch. BackgroundSearch besitzt mehrere Eigenschaften, so dass die Suche ordnungsgemäß konfiguriert werden kann und über eine StartSearch-Methode verfügt. Wenn ein Ergebnis gefunden wird, wird ein ResultFound-Ereignis (meine Benennungskonventionen sind wirklich nicht sehr kreativ) ausgelöst. Wenn die gesamte Suche abgeschlossen ist, tritt ein SearchCompleted-Ereignis auf.

Imports System 
Imports System.DirectoryServices 
Public Class BackgroundSearch 
 Dim m_FilterString As String 
 Dim m_PageSize As Integer 
 Dim m_RootPath As String 
 Dim m_PropertiesToLoad() As String 
 Dim m_IntegratedAuthentication As Boolean 
 Dim m_UserID As String 
 Dim m_Password As String 
 Public Property IntegratedAuthentication() As Boolean 
  Get 
   Return m_IntegratedAuthentication 
  End Get 
  Set(ByVal Value As Boolean) 
   m_IntegratedAuthentication = Value 
  End Set 
 End Property 
 Public Property UserID() As String 
  Get 
   Return m_UserID 
  End Get 
  Set(ByVal Value As String) 
   m_UserID = Value 
  End Set 
 End Property 
 Public Property Password() As String 
  Get 
   Return m_Password 
  End Get 
  Set(ByVal Value As String) 
   m_Password = Value 
  End Set 
 End Property 
 Public Property PropertiesToLoad() As String() 
  Get 
   Return m_PropertiesToLoad 
  End Get 
  Set(ByVal Value As String()) 
   m_PropertiesToLoad = Value 
  End Set 
 End Property 
 Public Property FilterString() As String 
  Get 
   Return m_FilterString 
  End Get 
  Set(ByVal Value As String) 
   m_FilterString = Value 
  End Set 
 End Property 
 Public Property PageSize() As Integer 
  Get 
   Return m_PageSize 
  End Get 
  Set(ByVal Value As Integer) 
   m_PageSize = Value 
  End Set 
 End Property 
 Public Property RootPath() As String 
  Get 
   Return m_RootPath 
  End Get 
  Set(ByVal Value As String) 
   m_RootPath = Value 
  End Set 
 End Property 
 Public Event ResultFound(ByVal result As SearchResult) 
 Public Event SearchCompleted(ByVal entriesFound As Integer) 
 Public Sub StartSearch() 
  Dim rootEntry _ 
   As New DirectoryEntry(RootPath) 
  If Not IntegratedAuthentication Then 
   rootEntry.Username = UserID 
   rootEntry.Password = Password 
  End If 
  Dim searcher As New DirectorySearcher(rootEntry) 
  searcher.PropertiesToLoad.AddRange(PropertiesToLoad) 
  searcher.PageSize = PageSize 
  searcher.ServerTimeLimit = New TimeSpan(0, 10, 0) 
  searcher.Filter = FilterString 
  Dim queryResults As SearchResultCollection 
  queryResults = searcher.FindAll() 
  Dim result As SearchResult 
  Dim resultCount As Integer = 0 
  For Each result In queryResults 
   RaiseEvent ResultFound(result) 
   resultCount += 1 
  Next 
  RaiseEvent SearchCompleted(resultCount) 
 End Sub 
End Class

Wie ich bereits erwähnt habe, wird beliebiger Code, der in einen Ereignishandler für diese Ereignisse platziert wurde, auf dem Hintergrundthread und nicht auf demselben Thread wie das Formular ausgeführt. Wenn Sie Ihr Formular (oder ein Steuerelement auf dem Formular) ändern möchten, müssen Sie den Aufruf an den Thread des Formulars zurückmarshallen. Mein Beispiel löst dieses Problem, indem eine zusätzliche Prozedur für das tatsächliche Einfügen von Ergebnissen in das ListBox-Steuerelement bereitgestellt und die Invoke-Methode des Formulars verwendet wird, um diese Prozedur von der Ereignisbehandlungsroutine aus aufzurufen.

Private Sub startSearch_Click( _ 
 ByVal sender As Object, _ 
 ByVal e As EventArgs) Handles startSearch.Click 
 With bkg 
  .RootPath = rootPath.Text 
  .FilterString = searchString.Text 
  If Not integratedAuth.Checked Then 
   .UserID = userID.Text 
   .Password = password.Text 
  End If 
  .PageSize = 5 
  .PropertiesToLoad = _ 
   New String() {"cn", "mail", "telephoneNumber"} 
  Dim search As New _ 
   Threading.Thread(AddressOf .StartSearch) 
  search.Start() 
 End With 
End Sub 
Private Sub bkg_ResultFound( _ 
   ByVal result As SearchResult) _ 
  Handles bkg.ResultFound 
 If result.Properties.Contains("mail") Then 
  Dim emailAddress As String 
  emailAddress = CStr(result.Properties("mail")(0)) 
  Dim display As New displayResult _ 
 (AddressOf AddTextToListBox) 
  Me.Invoke(display, New Object() {emailAddress}) 
 End If 
End Sub 
Private Delegate Sub displayResult(ByVal textEntry As String) 
Private Sub AddTextToListBox(ByVal textEntry As String) 
 results.Items.Add(textEntry) 
End Sub 
Private Sub bkg_SearchCompleted( _ 
  ByVal entriesFound As Integer) _ 
 Handles bkg.SearchCompleted 
 MessageBox.Show( _ 
   String.Format("{0} Entries Found", entriesFound)) 
End Sub

Wenn Sie Ihre Suche auf einem Hintergrundthread ausführen möchten, möchten Sie ggf. die Seitengröße ändern, da hierdurch der Umfang jeder Benutzeroberflächenaktualisierung beeinflusst wird.

Datenbindung mit "DirectoryServices"-Objekten

Verzeichniseinträge haben dynamische Eigenschaften, das heißt, sie haben keine vordefinierte Gruppe von Eigenschaften, sondern eher eine Eigenschaftenauflistung, die zur Laufzeit bestimmt wird. Dies ist ein gutes Modell für das DirectoryServices-Objekt, da die Gruppe von verfügbaren Eigenschaften für ein bestimmtes Objekt nicht feststeht. Nichtsdestotrotz entsteht ein Problem, wenn Sie versuchen, Daten mit diesen Objekten zu binden. Ohne eine feste Gruppe von Eigenschaften können Sie ein Steuerelement wie DataGrid nicht direkt an eine Auflistung von SearchResult-Objekten binden. Das bedeutet aber nicht, dass keine Bindung möglich ist. Sie können weiterhin Daten binden, es erfordert nur etwas Arbeit.

Im Wesentlichen müssen Sie Ihre DirectoryServices-Suchergebnisse in ein anderes Objekt mit statischen Eigenschaften wrappen und dann eine Bindung zu diesem neuen Objekt herstellen. Für meine Zwecke gibt es zwei mögliche Vorgehensweisen: Ich könnte eine benutzerdefinierte Klasse schreiben, die die gewünschten spezifischen Eigenschaften offen legt, und dann die Klasse jedes Mal ändern, wenn ich der DirectoryServices-Suche eine Eigenschaft hinzufüge oder daraus entferne, oder ich könnte ein DataTable-Objekt dynamisch erstellen und es als mein bindungsfähiges Objekt verwenden. Der DataTable-Ansatz ist viel einfacher und funktioniert gut, so dass er für diese Situation eindeutig vorzuziehen ist. Die dritte Version meines ursprünglichen Beispiels (das DS DataBinding-Projekt) erstellt ein DataTable-Objekt und bindet die Ergebnisse an das DataGrid-Steuerelement. Es ist im Codebeispiel für diesen Artikel enthalten, das zum Download bereitsteht. Wenn Sie ein DataTable-Objekt ohne Datenbank (oder XML-Datei) erstellen möchten, erstellen Sie eine neue DataTable-Instanz und fügen Sie der Instanz DataColumns für jede Ihrer Eigenschaften hinzu.

Dim myTable As New DataTable("Results") 
Dim colName As String 
For Each colName In searcher.PropertiesToLoad 
 myTable.Columns.Add(colName, GetType(System.String)) 
Next

Sobald Sie Ergebnisse empfangen, müssen Sie einfach nur das DataTable-Objekt füllen und können loslegen.

Dim result As SearchResult 
For Each result In queryResults 
Dim dr As DataRow = myTable.NewRow() 
 For Each colName In searcher.PropertiesToLoad 
  If result.Properties.Contains(colName) Then 
   dr(colName) = CStr(result.Properties(colName)(0)) 
  Else 
   dr(colName) = "" 
  End If 
 Next 
 myTable.Rows.Add(dr) 
Next 
results.SetDataBinding(myTable.DefaultView, "")

Zusammenfassung

Mithilfe des System.DirectoryServices-Namespace können Sie auf einfache Weise eine Verbindung zu Active Directory herstellen und Active Directory-Funktionen in Ihren Anwendungen nutzen. Dies eröffnet Ihnen eine Vielzahl an Möglichkeiten. Die Beispiele in diesem Artikel haben nur eine Verwendung dieser Technologie veranschaulicht und zwar das Durchsuchen des Benutzerverzeichnisses. Der System.DirectoryServices-Namespace bietet jedoch darüber hinaus noch viele weitere nützliche Verwendungsmöglichkeiten, einschließlich Netzwerkadministration, Serverkonfiguration usw.


Anzeigen:
© 2015 Microsoft