Abe
Abe

Reputation: 35

Value of type 'System.Threading.Tasks.Task(Of String)' cannot be converted to 'String'. in VB.Net

I am attempting Asyn calls but having a problem unboxing my results. Here is the error info that I got : Value of type 'System.Threading.Tasks.Task(Of String)' cannot be converted to 'String'. Can someone help to achieve this. This is my code that I used:

Private Sub Download_Click(sender As Object, e As EventArgs) Handles Button1.Click
    'GET DOWNLOAD URL
    Dim download_url As String = Download_HttpClient(space_id, file_id)

    'ACCESS URL THROUGH GOOGLE CHROME
    Dim proc As New ProcessStartInfo()
    proc.FileName = "C:\Windows\System32\cmd.exe"
    proc.Arguments = "/c start chrome " + download_url
    Process.Start(proc)
End Sub

Public Async Function Download_HttpClient(ByVal spaceId As String, fileId As String) As Task(Of String)
    Dim cookieContainer As New CookieContainer
    Dim httpClientHandler As New HttpClientHandler
    httpClientHandler.AllowAutoRedirect = True
    httpClientHandler.UseCookies = True
    httpClientHandler.CookieContainer = cookieContainer
    Dim httpClient As New HttpClient(httpClientHandler)

    'GET LOGIN CREDENTIALS
    Dim login_url As String = host + "/common/Authentication.json"
    Dim login_parameter As String = "?id=" + user_id + "&pw=" + password
    Dim login_response As HttpResponseMessage = Await httpClient.GetAsync(login_url + login_parameter)
    Dim login_contents As String = Await login_response.Content.ReadAsStringAsync()
    'MessageBox.Show(login_contents)

    'GET DOWNLOAD ID
    Dim download_url As String = host + "/contentsmanagement/SingleContentsDownloadApi.json"
    Dim download_param As String = "?fileId=" + file_id + "&spaceId=" + space_id + "&type=alive"
    Dim download_response As HttpResponseMessage = Await httpClient.GetAsync(download_url + download_param)
    Dim download_contents As String = Await download_response.Content.ReadAsStringAsync()
    Dim downloadId As String = Nothing
    Dim map As Dictionary(Of String, String)
    map = JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(download_contents)
    map.TryGetValue("id", downloadId)
    'MessageBox.Show(downloadId)
    'set DOWNLOAD URL
    Dim url As String = host + "/contentsmanagement/ContentsDownloadApi.json?id=" + downloadId
    Return url

End Function

Upvotes: 1

Views: 699

Answers (1)

jmcilhinney
jmcilhinney

Reputation: 54417

When a function is declared Async and returns a Task(Of T), you need to Await it when you call it in order to get the T object produced by the Task, i.e. this:

Dim download_url As String = Download_HttpClient(space_id, file_id)

needs to be changed to this:

Dim download_url As String = Await Download_HttpClient(space_id, file_id)

You can only use Await in a method that is, itself, declared Async though. That means that this:

Private Sub Download_Click(sender As Object, e As EventArgs) Handles Button1.Click

needs to be changed to this:

Private Async Sub Download_Click(sender As Object, e As EventArgs) Handles Button1.Click

Note that you should only ever use Async Sub for event handlers and otherwise use Async Function.

I would generally recommend some reading on Async/Await but it is a somewhat advanced topic. As a general rule, if you need to call an existing Async function, e.g. HttpClient.GetAsync, then you need to make your own methods Async too.

If you have a Sub like this:

Private Sub SomeMethod()

and you call it like this:

SomeMethod()

then that would become this:

Private Async Function SomeMethodAsync() As Task

and this:

Await SomeMethodAsync()

The exception is an event handler, which I already demonstrated above. They must be a Sub and you don't call them directly.

Similarly, if you have a Function like this:

Private Function SomeMethod() As T

and you call it like this:

Dim result As T = SomeMethod()

then that would become this:

Private Async Function SomeMethodAsync() As Task(Of T)

and this:

Dim result As T = Await SomeMethodAsync()

If you have a method that is not Async and you want to call an Async method in it, you have to make your method Async and use Await, then make any methods that call it Async and use Await in them, and on up the chain until you get to your event handler(s). This is why it is generally recommended that, if you're going to use Async at all, you use it pretty much everywhere.

If making everything Async is too onerous then you can call an asynchronous method synchronously and get the result of the Task returned, e.g. this:

Dim download_url As String = Download_HttpClient(space_id, file_id)

becomes this:

Dim download_url_task As Task(Of String) = Download_HttpClient(space_id, file_id)
Dim download_url As String = download_url_task.Result

or just this:

Dim download_url As String = Download_HttpClient(space_id, file_id).Result

Upvotes: 1

Related Questions