Looking into updating a slew of VB.NET API to C# for a client, and figured I should brush off my VB.NET before getting too serious.

And I figured that means I should make a console app, connect to a sample API URI at JsonPlaceholder, grab a collection of entities, serialize them, loop through, and access something on each individual entity instance. That's half (or more) of what any API does, right?

Oh wow. Slightly larger rabbit hole than I figured.

First, you can't make the top-level Main sub Async in VB.NET. DotNetPerls makes it sound like you can wait out an Async Sub from the Sub Main, but you can't.

From stackoverflow.com:

Subs should not be async. Event handlers are the only exception to that rule. You await Task which can only be returned from a Function. If the intention is to make that interface async then all the members need to be functions that return a Task or its derivative.

Can confirm.

The right answer is to set up an awaiter in a synchronous [sic] Sub Main.

From stackoverflow.com:

You won't be able to do top-level Await in a console program. You can still make it work (preserving the Async on LoadData) with the following changes:

  1. Change the signature of LoadData to Private Async Function LoadData() As Task
  2. Change the call in Main to LoadData.GetAwaiter().GetResult()

It is somewhat amazing how few upvotes these have gotten at SO. Aka "VB.NET was never super popular, relatively speaking [to C#], was it?"

Here's some working code.

Imports Newtonsoft.Json

Module Program

    Public Sub Main()
        Console.WriteLine("Hello World!")

        DoStuff.GetAwaiter().GetResult()

        Console.WriteLine("Done")
    End Sub

    Private Async Function DoStuff() As Task
        Dim httpClient As New Net.Http.HttpClient
        httpClient.BaseAddress = New Uri("https://jsonplaceholder.typicode.com/")

        Try
            Console.WriteLine("Starting")
            ' BaseAddress is strangely draconian:
            ' https://stackoverflow.com/a/23438417/1028230
            'Dim result1 As String = Await webClient.GetStringAsync("https://jsonplaceholder.typicode.com/users/1/todos") ' if you don't use BaseAddress
            Dim result1 As String = Await httpClient.GetStringAsync("users/1/todos")
            Console.WriteLine("Ending")

            Dim allTodos = JsonConvert.DeserializeObject(Of IEnumerable(Of Todo))(result1)

            For Each element In allTodos
                Console.Write(element.Id & "--")
            Next
        Catch ex As Exception
            Console.WriteLine(ex.Message)
        End Try
    End Function
End Module

and the Todo class looks like this:

Public Class Todo
    '{
    '  "userId": 1,
    '  "id": 1,
    '  "title": "delectus aut autem",
    '  "completed": false
    '},
    Public Property UserId As Integer
    Public Property Id As Integer
    Public Property Title As String
    Public Property Completed As Boolean
End Class

As I think I've mentioned before, a prof told me in college, "They're all different dialects of the same language." Or as a buddy on the ultimate team said, "It's all zeroes and ones." Nothing fancy going on here, but it does take a while to get your ears tuned to the new (ancient?) dialect.

Labels: ,