This documentation is archived and is not being maintained.

How to: Wrap EAP Patterns in a Task

The following example shows how to expose an arbitrary sequence of Event-based Asynchronous Pattern (EAP) operations as one task by using a TaskCompletionSource(Of TResult). The example also shows how to use a CancellationToken to invoke the built-in cancellation methods on the WebClient objects.

Class WebDataDownLoader

    Dim tcs As New TaskCompletionSource(Of String())
    Dim nameToSearch As String
    Dim token As CancellationToken
    Dim results As New List(Of String)
    Dim m_lock As Object
    Dim count As Integer
    Dim addresses() As String

    Shared Sub Main()

        Dim downloader As New WebDataDownLoader()
        downloader.addresses = {"", "", _
                                     "", "", _
                                     "", ""}
        Dim cts As New CancellationTokenSource()

        ' Create a UI thread from which to cancel the entire operation
                                  Console.WriteLine("Press c to cancel")
                                  If Console.ReadKey().KeyChar = "c"c Then
                                  End If
                              End Sub)

        ' Using a neutral search term that is sure to get some hits on English web sites.
        ' Please substitute your favorite search term.
        downloader.nameToSearch = "the"
        Dim webTask As Task(Of String()) = downloader.GetWordCounts(downloader.addresses, downloader.nameToSearch, cts.Token)

        ' Do some other work here unless the method has already completed.
        If (webTask.IsCompleted = False) Then
            ' Simulate some work
        End If

        Dim results As String() = Nothing
            results = webTask.Result
        Catch ae As AggregateException
            For Each ex As Exception In ae.InnerExceptions
                If (TypeOf (ex) Is OperationCanceledException) Then
                    Dim oce As OperationCanceledException = CType(ex, OperationCanceledException)
                    If oce.CancellationToken = cts.Token Then
                        Console.WriteLine("Operation canceled by user.")
                    End If
                End If

        End Try

        If (Not results Is Nothing) Then
            For Each item As String In results
        End If

        Console.WriteLine("Press any key to exit")
    End Sub

    Public Function GetWordCounts(ByVal urls() As String, ByVal str As String, ByVal token As CancellationToken) As Task(Of String())

        Dim webClients() As WebClient
        ReDim webClients(urls.Length)
        m_lock = New Object()

        ' If the user cancels the CancellationToken, then we can use the
        ' WebClient's ability to cancel its own async operations.
                           For Each wc As WebClient In webClients
                               If Not wc Is Nothing Then
                               End If
                       End Sub)

        For i As Integer = 0 To urls.Length - 1
            webClients(i) = New WebClient()

            ' Specify the callback for the DownloadStringCompleted
            ' event that will be raised by this WebClient instance.
            AddHandler webClients(i).DownloadStringCompleted, AddressOf WebEventHandler

            Dim address As Uri = Nothing
                address = New Uri(urls(i))
                ' Pass the address, and also use it for the userToken 
                ' to identify the page when the delegate is invoked.
                webClients(i).DownloadStringAsync(address, address)
            Catch ex As UriFormatException
                Return tcs.Task
            End Try


        ' Return the underlying Task. The client code
        ' waits on the Result property, and handles exceptions
        ' in the try-catch block there.
        Return tcs.Task
    End Function

    Public Sub WebEventHandler(ByVal sender As Object, ByVal args As DownloadStringCompletedEventArgs)

        If args.Cancelled = True Then
        ElseIf Not args.Error Is Nothing Then
            ' Split the string into an array of words,
            ' then count the number of elements that match
            ' the search term.
            Dim words() As String = args.Result.Split(" "c)
            Dim NAME As String = nameToSearch.ToUpper()
            Dim nameCount = (From word In words.AsParallel()
                            Where word.ToUpper().Contains(NAME)
                            Select word).Count()

            ' Associate the results with the url, and add new string to the array that 
            ' the underlying Task object will return in its Result property.
            results.Add(String.Format("{0} has {1} instances of {2}", args.UserState, nameCount, nameToSearch))
        End If

        SyncLock (m_lock)
            count = count + 1
            If (count = addresses.Length) Then
            End If
        End SyncLock
    End Sub