?
Solved

vb.net and query ldap inside of a background worker

Posted on 2014-11-10
4
Medium Priority
?
294 Views
Last Modified: 2014-11-11
I am attempting to query an LDAP group and return fields to a listview based on that group that i supply in my query.  It takes about 15 seconds to run so i would like to run this query in a background worker.  I get an error that i cant run a listview via cross-threading.  Can someone take a look at my code and help?

 Private bw As BackgroundWorker = New BackgroundWorker

    Public Sub New()
        InitializeComponent()
        bw.WorkerReportsProgress = True
        bw.WorkerSupportsCancellation = True
        AddHandler bw.DoWork, AddressOf BackgroundWorker1_DoWork
        AddHandler bw.ProgressChanged, AddressOf BackgroundWorker1_ProgressChanged
        AddHandler bw.RunWorkerCompleted, AddressOf BackgroundWorker1_RunWorkerCompleted
    End Sub

Open in new window


Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ListView1.Items.Clear()
        If Not bw.IsBusy = True Then
            bw.RunWorkerAsync()
        End If
        Label2.Visible = False
end sub

Open in new window


Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        Dim userIds As String() = txtcc.Text.Split(New String() {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
        For Each i As String In userIds
            Dim de As New DirectoryEntry("LDAP://test.net/DC=test,DC=net")
            Dim LdapFilter As String = "(departmentNumber=" & i & ")"
            Dim searcher As New DirectorySearcher(de, LdapFilter)
            Dim result As SearchResult
            Dim res As SearchResultCollection = searcher.FindAll()
            For Each result In res
                Dim item As ListViewItem = ListView1.Items.Add(i)
                item.SubItems.Add(result.Properties("givenName")(0).ToString())
                item.SubItems.Add(result.Properties("cn")(0).ToString())
                item.SubItems.Add(result.Properties("userPrincipalName")(0).ToString())
                worker.ReportProgress(0, New ListViewState() With {.Item = item, .Group = ListViewGroupDefinition.None})
            Next
        Next
    End Sub

    Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        If Not e.UserState Is Nothing AndAlso TypeOf e.UserState Is ListViewState Then
            Dim state As ListViewState = TryCast(e.UserState, ListViewState)
            If Not state Is Nothing Then
                Select Case state.Group
                    Case ListViewGroupDefinition.None
                        Exit Select
                    Case ListViewGroupDefinition.Applications
                       Exit Select
                End Select
                ListView1.Items.Add(state.Item)
            End If
        End If
    End Sub

    Public Class ListViewState
        Public Property Item() As ListViewItem
        Public Property Group As ListViewGroupDefinition
    End Class

    Public Enum ListViewGroupDefinition As Integer
        None = 0
            End Enum

Open in new window

0
Comment
Question by:derek7467
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
4 Comments
 
LVL 86

Accepted Solution

by:
Mike Tomlinson earned 668 total points
ID: 40433486
Pass out each "result" to ProgressChanged() so that the ListView item can be created on the Form's thread.

Something like:
    Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim userIds As String() = txtcc.Text.Split(New String() {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
        For Each i As String In userIds
            Dim de As New DirectoryEntry("LDAP://test.net/DC=test,DC=net")
            Dim LdapFilter As String = "(departmentNumber=" & i & ")"
            Dim searcher As New DirectorySearcher(de, LdapFilter)
            For Each result As SearchResult In searcher.FindAll()
                BackgroundWorker1.ReportProgress(i, result)
            Next
        Next
    End Sub

    Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        Dim item As ListViewItem = ListView1.Items.Add(e.ProgressPercentage)
        Dim result As SearchResult = DirectCast(e.UserState, SearchResult)
        item.SubItems.Add(result.Properties("givenName")(0).ToString())
        item.SubItems.Add(result.Properties("cn")(0).ToString())
        item.SubItems.Add(result.Properties("userPrincipalName")(0).ToString())
        ListView1.Items.Add(item)
    End Sub

Open in new window

0
 
LVL 34

Assisted Solution

by:it_saige
it_saige earned 1332 total points
ID: 40433555
Just like what Mike said...  If you look at each example I provide, I always change this line:
Dim item As ListViewItem = ListView1.Items.Add(i)
'To this...
Dim item As ListViewItem = New ListViewItem(i)

Open in new window


The purpose of the ListViewState class is so that you can send a new list view item to your list view using the ProgressChanged Event.

Just change your DoWork method to reflect:
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        Dim userIds As String() = txtcc.Text.Split(New String() {Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries)
        For Each i As String In userIds
            Dim de As New DirectoryEntry("LDAP://test.net/DC=test,DC=net")
            Dim LdapFilter As String = "(departmentNumber=" & i & ")"
            Dim searcher As New DirectorySearcher(de, LdapFilter)
            Dim result As SearchResult
            Dim res As SearchResultCollection = searcher.FindAll()
            For Each result In res
                Dim item As ListViewItem = New ListViewItem(i)
                item.SubItems.Add(result.Properties("givenName")(0).ToString())
                item.SubItems.Add(result.Properties("cn")(0).ToString())
                item.SubItems.Add(result.Properties("userPrincipalName")(0).ToString())
                worker.ReportProgress(0, New ListViewState() With {.Item = item, .Group = ListViewGroupDefinition.None})
            Next
        Next
    End Sub

Open in new window


-saige-
0
 

Author Comment

by:derek7467
ID: 40433676
Cool that worked:

Any idea, why my label2 doesnt stay until the background worker is done?:

Below is my query button that i put some status text on the page doing the query:

       
 Label2.Visible = True
        Label2.Text = "Please wait, loading..."
        delay(2000)
        ListView1.Items.Clear()
                If Not bw.IsBusy = True Then
            bw.RunWorkerAsync()
        End If
        Label2.Visible = False

Open in new window

0
 
LVL 34

Assisted Solution

by:it_saige
it_saige earned 1332 total points
ID: 40433729
Because the background worker runs asynchronously, meaning basically that it is fired and forgotten...  In order to combat this, just show your label as you have done, and then in the RunBackgroundWorkerCompleted method, hide the label again.  Something like:
Imports System.ComponentModel
Imports System.Linq
Imports System.Management

Public Class Form1
	Private bw As BackgroundWorker = New BackgroundWorker

	Public Sub New()
		InitializeComponent()
		bw.WorkerReportsProgress = True
		bw.WorkerSupportsCancellation = True
		AddHandler bw.DoWork, AddressOf OnDoWork
		AddHandler bw.ProgressChanged, AddressOf OnProgressChanged
		AddHandler bw.RunWorkerCompleted, AddressOf OnWorkerCompleted
	End Sub

	Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
		Label2.Visible = True
		Label2.Text = "Please wait, loading..."
		delay(2000)
        	If Not bw.IsBusy = True Then
			ListView1.Items.Clear()
			ListView1.Groups.Add(New ListViewGroup("Processes", "Process List"))
			bw.RunWorkerAsync()
		End If
	End Sub

	Private Sub OnDoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)
		' Doing our work here.
		' Calling our progress sends an call to the ProgressChanged event.
		' When we finish, we call the RunWorkerCompleted event.
	End Sub

	Private Sub OnProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)
		' Adding our list items here
	End Sub

	Private Sub OnWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
		If e.Cancelled = True Then
			Me.tbProgress.Text = "Canceled!"
		ElseIf e.Error IsNot Nothing Then
			Me.tbProgress.Text = "Error: " & e.Error.Message
		Else
			Me.tbProgress.Text = "Done!"
		End If
		' Add a wait timer or delay and hide the Label.
		delay(2000)
		Label2.Visible = False
	End Sub
End Class

Open in new window


-saige-
0

Featured Post

Does Powershell have you tied up in knots?

Managing Active Directory does not always have to be complicated.  If you are spending more time trying instead of doing, then it's time to look at something else. For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Uncontrolled local administrators groups within any organization pose a huge security risk. Because these groups are locally managed it becomes difficult to audit and maintain them.
Microsoft Office 365 is a subscriptions based service which includes services like Exchange Online and Skype for business Online. These services integrate with Microsoft's online version of Active Directory called Azure Active Directory.
This tutorial will walk an individual through the process of transferring the five major, necessary Active Directory Roles, commonly referred to as the FSMO roles to another domain controller. Log onto the new domain controller with a user account t…
Are you ready to implement Active Directory best practices without reading 300+ pages? You're in luck. In this webinar hosted by Skyport Systems, you gain insight into Microsoft's latest comprehensive guide, with tips on the best and easiest way…
Suggested Courses

770 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question