1

I have a vb console application that acts a a relay to a desktop application - posting data to an online service.

Because posts are relatively large and frequent, my intention is to 'fire and forget'. That is to say, I would like the console application to post data and never wait for a response (I control the online service and errors can be handled at the the other end).

httpClient postAsync() seemed like a simple solution, but I am confused by the terminology - despite having read various useful posts found here

Ultimately, it seems that the way to achieve what I want to do is to use a Sub and not a Function as follows (this is called by Sub Main()):

Public Sub POSTRequest(ByVal url As String, ByVal data As String, ByVal format As String)

    Dim content_type As String = ""        

    Select Case format
        Case "xml"
            content_type = "application/xml"
        Case "json"
            content_type = "application/json"
        Case "form"
            content_type = "application/x-www-form-urlencoded"
    End Select        

    Try            
        Dim httpClient As HttpClient = New HttpClient()
        Dim httpContent = New StringContent(data, Encoding.UTF8, content_type)
        httpClient.PostAsync(url, httpContent)
        Dim response = httpClient.PostAsync(url, httpContent).Result
        'I DON'T CARE ABOUT THE VALUE OF RESPONSE, SO NOTHING IS RETURNED...
    Catch ex As Exception
        Debug.Print(ex.Message)
    End Try

End Sub

First, this seems confusing and counter-intuitive. Is not the point of Async / Await to prevent deadlock and to allow multiple tasks to run simultaneously?

Secondly, how would I wrap this Sub (presumably as a Function) so as to allow multiple http posts to occur simultaneously (or in very quick succession) and only return any errors (e.g. a response code <> 200) and only after all the posts have been made?

Community
  • 1
  • 1
Alex Webster
  • 707
  • 1
  • 6
  • 21
  • 1
    .Result will block. Just remove the second line of code where you call postasync and the function will return without waiting. – Crowcoder Jun 06 '15 at 23:34
  • Thanks but removing `Dim response = httpClient.PostAsync(url, httpContent).Result` means that the http request never fires. I want to fire and forget - so I want to fire but I don't want to wait for the result returned by `.Result` ... – Alex Webster Jun 07 '15 at 01:30
  • The request does fire, it is just that the running thread is killed before it can do anything. For demonstration only, do a Thread.Sleep(1000) after `httpClient.PostAsync(url, httpContent)`. I don't know how you are monitoring the request, but you will be able to see it is indeed hit. You can still use `await` with simultaneous calls so you'll probably end up doing that in the end. – Crowcoder Jun 07 '15 at 16:43
  • I will try this but I think Stephen Cleary has provided the answer I was after. Thanks – Alex Webster Jun 08 '15 at 19:42
  • yes, something tells me you can trust him on this. – Crowcoder Jun 08 '15 at 19:48

1 Answers1

1

Ultimately, it seems that the way...

All asynchronous methods should be Function and return Task (or Task (of T)), unless they're implementing event handlers.

Is not the point of Async / Await to...

You're not actually using Async or Await in the code you posted. Result is not intended for use with asynchronous tasks; use Await instead. Since you're writing a Console application, you'll eventually find that you do need to block once - in your Main method - to prevent the application from exiting. You can do this using GetAwaiter().GetResult() on your single top-level task.

allow multiple http posts to occur simultaneously

Asynchronous concurrency is most easily done by saving the Task (e.g., in a List (of Task)) instead of using Await right away, and then later passing the collection of tasks to Task.WhenAll and Awaiting that.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Thanks Stephen - so I really need a three-level solution with the 'executive' function at the bottom that returns the `List (of Task)`, a function that calls the executive function and awaits and handles its returned `List (of Task)` and at the top, `Sub Main()` which calls the middle layer function? I will now go away and try that... – Alex Webster Jun 08 '15 at 19:12
  • In a console app, I recommend having your `Sub Main()` just call `MainAsync().GetAwaiter().GetResult()`, where `MainAsync` is an asynchronous `Function (Of Task)`. Within that `MainAsync` you can do things like build the list of tasks and pass that to `Task.WhenAll`. – Stephen Cleary Jun 08 '15 at 19:26