I'm using webforms and VB.net. I am calling Stripe to perform an ACH transaction. I have a standalone program that works, however when I put the code in my production application, the flow is not what I'm expecting.
I'm reading a gridview which contains customer IDs of records which need to be billed via Stripe. I have a button (btnPost) which starts the process. That button calls an Async Sub which loops through the gridview. For each row I call a "Post_ACHAsync" subroutine, which is also Async. Within the "Post_ACHAsync" subroutine is the call to Stripe, with an "Await", which returns a Task.
The problem is that, when the call to Stripe is done, it goes back to the For/Each loop instead of proceeding with code. Why is it doing that?
Here's the code:
Protected Sub btnPost_Click(sender As Object, e As EventArgs) Handles btnPost.Click
PostTransactions()
PopulatePendingTrxs()
End Sub
Protected Async Sub PostTransactions()
For Each row As GridViewRow In gvTrxs.Rows
Select Case row.Cells(2).Text.ToUpper()
Case "B"
'--- Bank Account (ACH)
Post_ACHAsync([parameters])
Case "C"
'--- Credit Card
Post_CC(row)
Case Else
End Select
Next
End Sub
Private Async Sub Post_ACHAsync([parameters])
dim oM as new BillingMaster()
'--- call Stripe
Try
Dim stripeService As New StripeService()
Dim chargeId As String = Await stripeService.ProcessAchTransferAsync([parameters])
' Success!
oM.Status = "W" 'Withdrawal
oM.SuccessOrFailure = "S"
oM.StripeWithdrawalID = chargeId
oM.StripeWithdrawalMsg = "Success"
colErrors = oM.SaveRecord(oM)
Catch ex As Exception
OKtoContinue = False
colErrors.Add(ex.Message)
End Try
If Not OKtoContinue Then
oM.PostGUID = strPostGUID
oM.Status = "F"
oM.SuccessOrFailure = "F"
oM.StripeWithdrawalID = ""
oM.WithdrawalDate = DateTime.Now
oM.StripeWithdrawalMsg = SplitErrors(colErrors)
colErrors = oM.SaveRecord(oM)
End If
oM = Nothing
End Sub
Public Async Function ProcessAchTransferAsync([parameters]) As Task(Of String)
Try
'--- do Stripe stuff here
Return charge.Id
Catch ex As StripeException
' Log the error
System.Diagnostics.Debug.WriteLine($"Stripe Error: {If(ex.StripeError?.Message, ex.Message)}")
Throw New Exception($"Payment processing error: {If(ex.StripeError?.Message, ex.Message)}")
Catch ex As Exception
' Log the error
System.Diagnostics.Debug.WriteLine($"General Error: {ex.Message}")
Throw New Exception("An unexpected error occurred while processing your payment. Please try again.")
End Try
End Function
After the Await stripeService.ProcessAchTransferAsync line, the flow goes back to the For/Each loop; it doesn't continue with the "Success" (or Catch) code.
Do I need both subroutines to be Async? Should there be another "Await" somewhere?

btnPost_Clickneeds to be markedasync, then await the methods there; it's OK for event handlers to beasync void(it's handled internally). The other methods not so much. Change them fromasync voidtoasync Task. Await the async callsAsync, it'sAsyncall the way down. Every step in the chain needs to go through anAwait.