Click here to Skip to main content
15,885,278 members
Articles / Programming Languages / Visual Basic

Asynchronous Processing of Functions and Webservice Calls

Rate me:
Please Sign up or sign in to vote.
4.56/5 (20 votes)
14 Jul 2004CPOL6 min read 159.5K   2.1K   79  
How to do process functions and webservice calls asynchronously
This article shows how to implement the Whidbey (.NET 2.0) BackgroundWorker component in VB.NET 1.1, and extend it to support multiple arguments.
Namespace VS2005

    <ToolboxBitmap(GetType(BackgroundWorker))> _
    Public Class BackgroundWorker : Inherits System.ComponentModel.Component
        Private _CancelPending As Boolean = False
        Private _ReportsProgress As Boolean = False
        Private _SupportsCancellation As Boolean = False

        Public Event DoWork As DoWorkEventHandler

        Public Event ProgressChanged As ProgressChangedEventHandler

        Public Event RunWorkerCompleted As RunWorkerCompletedEventHandler

        Private Sub ProcessDelegate(ByVal delegateToProcess As System.Delegate, ByVal ParamArray args As Object())
            If delegateToProcess Is Nothing Then
                Exit Sub
            End If

            Dim delegates As System.Delegate() = delegateToProcess.GetInvocationList
            For Each handler As System.Delegate In delegates
                InvokeDelegate(handler, args)
            Next
        End Sub

        Private Sub InvokeDelegate(ByVal delegateToInvoke As System.Delegate, ByVal args As Object())

            Dim synchronizer As System.ComponentModel.ISynchronizeInvoke = Nothing
            If GetType(System.ComponentModel.ISynchronizeInvoke).IsInstanceOfType(delegateToInvoke.Target) Then
                synchronizer = DirectCast(delegateToInvoke.Target, System.ComponentModel.ISynchronizeInvoke)
            End If

            If Not (synchronizer Is Nothing) Then   '   A windows Form object
                If synchronizer.InvokeRequired = False Then
                    delegateToInvoke.DynamicInvoke(args)
                    Return
                End If
                Try
                    synchronizer.Invoke(delegateToInvoke, args)
                Catch ex As Exception
                End Try
            Else                                    '   Not a windows form object
                delegateToInvoke.DynamicInvoke(args)
            End If

        End Sub

        Private Sub AsyncOperationCompleted(ByVal asyncResult As IAsyncResult)

            Dim doWorkEventDelegate As DoWorkEventHandler = CType(CType(asyncResult, System.Runtime.Remoting.Messaging.AsyncResult).AsyncDelegate, DoWorkEventHandler)
            Dim doWorkArgs As DoWorkEventArgs = CType(asyncResult.AsyncState, DoWorkEventArgs)
            Dim result As Object = Nothing
            Dim doWorkEventError As Exception = Nothing


            Try
                doWorkEventDelegate.EndInvoke(asyncResult)
                result = doWorkArgs.Result
            Catch ex As Exception
                doWorkEventError = ex
            End Try

            Dim completedArgs As RunWorkerCompletedEventArgs
            completedArgs = New RunWorkerCompletedEventArgs(result, doWorkEventError, doWorkArgs.Cancel)
            OnRunWorkerCompleted(completedArgs)
        End Sub

        Protected Overridable Sub OnRunWorkerCompleted(ByVal completedArgs As RunWorkerCompletedEventArgs)
            ProcessDelegate(RunWorkerCompletedEvent, Me, completedArgs)
        End Sub

        Public Overloads Sub RunWorkerAsync()
            RunWorkerAsync(Nothing)
        End Sub

        Public Overloads Sub RunWorkerAsync(ByVal argument As Object)
            Me._CancelPending = False
            If Not (DoWorkEvent Is Nothing) Then
                Dim args As DoWorkEventArgs
                If argument Is Nothing Then
                    argument = New Object
                End If
                args = New DoWorkEventArgs(argument)
                Dim callback As AsyncCallback
                callback = AddressOf Me.AsyncOperationCompleted
                DoWorkEvent.BeginInvoke(Me, args, callback, args)
            End If
        End Sub

        Public Overloads Sub ReportProgress(ByVal percent As Integer)
            Me.ReportProgress(percent, Nothing)
        End Sub

        Public Overloads Sub ReportProgress(ByVal percent As Integer, ByVal userState As Object)
            If WorkerReportsProgress Then
                Dim progressArgs As ProgressChangedEventArgs = New ProgressChangedEventArgs(percent, userState)
                OnProgressChanged(progressArgs)
            End If
        End Sub

        Protected Overridable Sub OnProgressChanged(ByVal progressArgs As ProgressChangedEventArgs)
            ProcessDelegate(ProgressChangedEvent, Me, progressArgs)
        End Sub

        Public Sub CancelAsync()
            If Me._SupportsCancellation = True Then
                SyncLock Me
                    Me._CancelPending = True
                End SyncLock
            Else
                Throw New System.InvalidOperationException("This BackgroundWorker states that it doesn't support cancellation. Modify WorkerSupportsCancellation to state that it does support cancellation.")
            End If
        End Sub

        Public ReadOnly Property CancellationPending() As Boolean
            Get
                SyncLock Me
                    Return Me._CancelPending
                End SyncLock
            End Get
        End Property

        Public Property WorkerSupportsCancellation() As Boolean
            Get
                SyncLock Me
                    Return Me._SupportsCancellation
                End SyncLock
            End Get
            Set(ByVal Value As Boolean)
                SyncLock Me
                    Me._SupportsCancellation = Value
                End SyncLock
            End Set
        End Property

        Public Property WorkerReportsProgress() As Boolean
            Get
                SyncLock Me
                    Return Me._ReportsProgress
                End SyncLock
            End Get
            Set(ByVal Value As Boolean)
                SyncLock Me
                    Me._ReportsProgress = Value
                End SyncLock
            End Set
        End Property

    End Class

    Public Class DoWorkEventArgs : Inherits System.ComponentModel.CancelEventArgs

        Private _Result As Object

        Public Property Result() As Object
            Get
                Return Me._Result
            End Get
            Set(ByVal Value As Object)
                Me._Result = Value
            End Set
        End Property

        Public ReadOnly Argument As Object

        Public Sub New(ByVal argument As Object)
            Me.Argument = argument
        End Sub

    End Class

    Public Class ProgressChangedEventArgs : Inherits EventArgs

        Public ReadOnly ProgressPercentage As Integer
        Public ReadOnly userState As Object

        Public Sub New(ByVal percentage As Integer, ByVal userState As Object)
            Me.ProgressPercentage = percentage
            Me.userState = userState
        End Sub

    End Class

    Public Class AsyncCompletedEventArgs : Inherits EventArgs

        Public ReadOnly [Error] As Exception = Nothing
        Public ReadOnly Cancelled As Boolean
        Public ReadOnly UserState As Object
            
        Public Sub New(ByVal runException As Exception, ByVal cancel As Boolean, ByVal userState As Object)
            Me.Error = runException
            Me.Cancelled = cancel
            Me.UserState = userState
        End Sub

        Protected Sub RaiseExceptionIfNecessary()
            If Me.Cancelled = True Then
                Throw New System.InvalidOperationException("Operation has been cancelled.")
            End If
            If Not Me.Error Is Nothing Then
                Throw New InvalidCastException
            End If
        End Sub

    End Class

    Public Class RunWorkerCompletedEventArgs : Inherits AsyncCompletedEventArgs

        Public ReadOnly Property Result() As Object
            Get
                Me.RaiseExceptionIfNecessary()
                Return Me.UserState
            End Get
        End Property

        Public Sub New(ByVal result As Object, ByVal runException As Exception, ByVal cancel As Boolean)
            MyBase.New(runException, cancel, result)
        End Sub

    End Class

    Public Delegate Sub DoWorkEventHandler(ByVal sender As Object, ByVal e As DoWorkEventArgs)

    Public Delegate Sub ProgressChangedEventHandler(ByVal sender As Object, ByVal e As ProgressChangedEventArgs)

    Public Delegate Sub RunWorkerCompletedEventHandler(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)

End Namespace

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United Kingdom United Kingdom
Unfortunately my real name was already in use as a code project login. For those of you who are wondering I am really Napoleon Solo. Sorry, I mean, Mark Jackson. Well, I do look a bit like him I think.

Comments and Discussions