Problems with threading and WebRequests

0

I'm sure there's some other threads about this, but i think i need a threading for dummies or something.

My problem: I want to fetch a value by a WebRequest and display it. My code looks something like this:

Foo = New Fetcher()
AddHandler Foo.HasResult, AddressOf Me.FetchValue

Private Sub FetchValue()
    If Foo.HasErrors Then
        MyTextBlock.Text = "ERROR"
        Exit Sub
    End IF
    MyTextBlock.Text = Foo.Value 'Here it crashes.....
End sub

Public Class Fetcher
    Public Event HasResult(ByVal F As Fetcher)
    Public WasError As Boolean = True
    Public Value As String = ""

    Public Sub New()
        Dim request As WebRequest = WebRequest.Create("theurl")
        request.BeginGetResponse(New AsyncCallback(AddressOf Me.GetValueAnswer), request)
    End Sub

    Private Sub GetValueAnswer(asynchronousResult As IAsyncResult)
        Dim request As HttpWebRequest = asynchronousResult.AsyncState
        If Not request Is Nothing Then
            Try
                Dim response As WebResponse = request.EndGetResponse(asynchronousResult)
                Using stream As Stream = response.GetResponseStream()
                    Using reader As New StreamReader(stream, System.Text.Encoding.UTF8)
                        Dim responseString = reader.ReadToEnd()
                        Me.Value = ResponseString
                        Me.WasError = False
                    End Using
                End Using
            Catch(Exception Ex)
                Me.WasError = True 'Not needed in this example, i know...
            End Try
        End If
        RaiseEvent HasResult(Me)
    End Sub
End Class

This is a little bit simplified, but it's the same error as well. At the line with the comment "Here it crashes....." i get an exception with "The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))" I can how ever see that my result is fetched when i explore the Foo.

So, how is the right way to do this?

(And yes; if I enter a bad URL or something so that "WasError" is true, of course i get the same exception when i try to set my textblock to "ERROR")

EDIT: After some really strong words, blood sweat and tears, i came up with this change to the FetchValue(), and now it finally works....

If Me.MyTextBlock.Dispatcher.HasThreadAccess Then
    If Foo.HasErrors Then
        MyTextBlock.Text = "ERROR"
        Exit Sub
    End IF
    MyTextBlock.Text = Foo.Value
Else
    Me.MyTestBlock.Dispatcher.RunAsync(Core.CoreDispatcherPriority.Normal, _
        AddressOf Me.FetchValue)
End If

I do how ever get a warning on the row in else that says "Because this call is not awaited, execution of the current method continues before the call is completed. Consider applying the Await operator to the result of the call."

Any ideas for how to make this warning go away?

vb.net
multithreading
winrt-xaml
webrequest
asked on Stack Overflow Jul 17, 2014 by gubbfett • edited Jul 17, 2014 by gubbfett

1 Answer

1

It's far, far easier to do this with HttpClient and Async/Await.

My VB is rusty, but here goes:

Public Class Fetcher
    Public Result As Task(of String)

    Public Sub New()
        Dim client As HttpClient = New HttpClient()
        Result = client.GetStringAsync("theurl")
    End Sub
End Class

Usage:

Foo = New Fetcher()
Try
    Dim data As String = Await Foo.Result
    MyTextBlock.Text = data
Catch(Exception Ex)
    MyTextBlock.Text = "ERROR"
End Try

Note that the Task<T> type handles return values, error conditions, and completion notification. So all the posted code in your Fetcher class is pretty much unnecessary if you use HttpClient with Task<T>. If your Fetcher class doesn't do anything else, then you should probably just remove it entirely:

Dim client As HttpClient = New HttpClient()
Try
    MyTextBlock.Text = Await client.GetStringAsync("theurl")
Catch(Exception Ex)
    MyTextBlock.Text = "ERROR"
End Try
answered on Stack Overflow Jul 18, 2014 by Stephen Cleary

User contributions licensed under CC BY-SA 3.0