0

This is a continuing quest to get api calls to work in in VB.NET application using RestSharp. When I started this effort I created a Windows forms project so I could manually enter values and test the approach. The first task in running the application is to retrieve a oauth user token from eBay given the refresh token for that user. In the form I enter the refresh token and run the procedure cmdGetCode which is executed by a button press. The procedure returns the user token information in JSON format. This works and returns the usertoken JSON. See code below.

Imports System.Net
Imports RestSharp
Imports System.Text.Json
Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Public Class Form1
    Public uT As userToken
    Dim sBaseURL As String = My.Settings.baseURL
    Dim ClientSec As String = My.Settings.ClientSec
    Dim ClientID As String = My.Settings.ClientID
    Dim sTokURL As String = My.Settings.tokenURL
    Dim sFulfillmentURL As String = My.Settings.fulfillmentURL
    Dim dsFulfilment As DataSet
    Dim client As RestClient = New RestClient(sBaseURL)
    Async Sub cmdGetCode_Click(sender As Object, e As EventArgs) Handles cmdGetCode.Click
        Dim Base64Auth As String = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(ClientID & ":" & ClientSec))
        Dim request As RestRequest = New RestRequest(sTokURL, Method.Post)
        With request
            .AddHeader("Content-Type", "application/x-www-form-urlencoded")
            .AddHeader("Authorization", "Basic " & Base64Auth)
            .AddParameter("grant_type", "refresh_token")
            .AddParameter("refresh_token", txtRefreshToken.Text)
            .AddParameter("Scope", "https://api.ebay.com/oauth/api_scope/sell.inventory")
        End With
        Try
            Dim response = Await client.PostAsync(request)
            If response.StatusCode = HttpStatusCode.OK Then
                Dim sR As String = response.Content
                'uT = JsonSerializer.Deserialize(Of userToken)(sR)
                uT = New userToken
                JsonConvert.PopulateObject(sR, uT)
                txtAuthToken.Text = uT.access_token.ToString
                txtDuration.Text = uT.expires_in.ToString
            Else
                txtRefreshToken.Text = "Failed to GetType tokens"
            End If
        Catch ex As Exception
            txtRefreshToken.Text = "Failed to GetType tokens"
        End Try
    End Sub

Given that this worked I then created a class in my application, clsUserToken, to provide the same function. This class in instantiated on application start and then executed to retrieve the user token for each of our users by updating the refresh token and executing the procedure getUserToken in the class. Code follows:


Imports System.Net
Imports RestSharp
Imports System.Text.Json
Imports Newtonsoft.Json

Public Class clsUserToken

    Property uT As userToken
    Dim sBaseURL As String
    Dim ClientSec As String
    Dim ClientID As String
    Dim sTokURL As String
    Dim client As RestClient
    Property refreshToken

    Sub New()
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12
        sBaseURL = My.Settings.baseURL
        client = New RestClient(sBaseURL)
        ClientSec = My.Settings.ClientSec
        ClientID = My.Settings.ClientID
        sTokURL = My.Settings.tokenURL

    End Sub

    Async Sub getUserToken()

        Dim Base64Auth As String = System.Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(ClientID & ":" & ClientSec))
        Dim request As RestRequest = New RestRequest(sTokURL, Method.Post)
        With request
            .AddHeader("Content-Type", "application/x-www-form-urlencoded")
            .AddHeader("Authorization", "Basic " & Base64Auth)
            .AddParameter("grant_type", "refresh_token")
            .AddParameter("refresh_token", refreshToken)
            .AddParameter("Scope", "https://api.ebay.com/oauth/api_scope/sell.inventory")
        End With
        Try
            Dim response = Await client.PostAsync(request)
            'Dim responce = Await client.ExecuteAsync(request)
            If response.StatusCode = HttpStatusCode.OK Then
                Dim sR As String = response.Content
                JsonConvert.PopulateObject(sR, uT)
                uT.fail = False
            Else
                uT.fail = True
            End If
        Catch ex As Exception
            ErrorLogger.WriteToErrorLog(ex.Message, ex.StackTrace, "clsUsertToken_getUserToken")
        End Try
    End Sub
End Class

This does not work. The application drops out of the procedure when the line Dim response = Await client.PostAsync(request) is executed. No error message, nothing in the catch.

There is really no difference in the code between the two modules so I am at a loss as to what is happening. Any thoughts or suggestions would be appreciated.

Here is how the class is called.

Imports Newtonsoft.Json
Imports Newtonsoft.Json.Linq
Module Run
    'Public clsUT As clsUserToken = New clsUserToken
    Dim tok As String
    Public UT As userToken
    Public policies As clsPolicies
    Dim d As Dac
    'Public T As test

    Public Sub main()
        Call getCode()
        UT = New userToken 'Instansiate userToken class. Holds user token properties
        policies = New clsPolicies
        d = New Dac
        Call getPolicies()
    End Sub

    Sub getPolicies()

        Dim dt As DataTable
        Dim dr As DataRow
        Dim refreshToken As String
        'Dim token As userToken = New userToken 
        Dim clsUT As New clsUserToken
        Dim sName As String
        Dim iCredentialID As Integer
        d.Connstring = My.Settings.conn
        dt = d.ExecuteDataTable("sp_GetSellers")
        If dt.Rows.Count > 0 Then
            For Each dr In dt.Rows
                refreshToken = dr.Item(2).ToString
                iCredentialID = dr.Item(0)
                sName = dr.Item(1).ToString
                clsUT.uT = UT 'Pass token to Get user token class
                clsUT.refreshToken = refreshToken

                clsUT.getUserToken()
                If UT.fail = False Then
                    tok = UT.access_token
                    policies.sUserToken = tok
                    policies.fulfillmentPolicies()
                    policies.returnPolicies()
                    policies.paymentPolicies()
                    updateFullfillment(policies.sFulfillmentContent, iCredentialID)
                    updatePayment(policies.sPaymentContent, iCredentialID)
                    updateReturn(policies.sReturnContent, iCredentialID)
                End If

            Next
        End If
    End Sub
5
  • How are you calling getUserToken? Can you show the code where you use a clsUserToken instance? Commented May 25, 2022 at 4:15
  • Here is how it is called. Commented May 25, 2022 at 15:17
  • 1
    I'd make getPolicies Async and Await the clsUT.getUserToken() call. Commented May 25, 2022 at 15:31
  • The Call keyword is a noop and serves no purpose at all in modern VB (since at least 2002... 20 years now!). The only reason it's still there is a convenience when porting forward older code, and it should not be used for new development. Also, modern VB should always use parentheses when calling methods. Commented May 25, 2022 at 15:43
  • clsUT already uses Async Await in the call to get the token. Seems redundant to do again. As to the use of Call, just my old ways. I know I don't need it and will clean up later. The basic question I still have is why the process works when in a forms code module, but won't work in the class. Essentially the same code. Commented May 25, 2022 at 16:59

1 Answer 1

0

Async is "viral", in that if you call an Async method your calling code must also be Async, and it must Await the result of the method you are calling. Thus one Async use tends to force a lot of other dependant code to also be Async, which in turn can cause other code to be Async, and it can infest an entire code base.

It works in the Form's button click event because Visual Studio is smart enough to see the event handler method is Async and call it appropriately when the event is raised.

Sign up to request clarification or add additional context in comments.

3 Comments

I can see that but I'm not sure what to change in the class. The only async is around the web request. Guess I'm not as smart as the form.
You don't change anything in the class. You change any code that calls the class's Async method, meaning the getPolicies() method must now be async, and Await clsUT.getUserToken(). Also, void (Sub) Async methods are kind of bad, so you should probably make getPolicies() return a result, rather than set global variables, which is better practice anyway, and then the code that calls getPolicies() must also become Async.
Finally got it working. Got rid of the class clsUserToken and went to a standard module with async function GetCode() As Task. Then in the execution used GetCode().Wait. Found a good reference site and examples link.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.