Home > Enterprise >  How do I use CallByName or Invoke with Async/Await
How do I use CallByName or Invoke with Async/Await

Time:03-08

CallByName and Invoke are not async functions so I can't call them asynchronously using the obvious syntax like:

rv = await CallByName(objScripts, txtScript.Text, CallType.Method)

Apparently I am the only one to ever need this so no answers on the internet.

My use case is I have hundreds of database transformation scripts written in vb.net. I have a database of which script processes which database. My code then reads the database and processes each script as the updated databases arrive, or I can select the script from a dropdown in my UI and run it that way.

I now need to run some of theses scripts async so I can use PuppeteerSharp to scrape some data rather use a database.

So how do I make that work?

CodePudding user response:

Just cast the result to Task and await it

rv = Await DirectCast(CallByName(objScripts, txtScript.Text, CallType.Method), Task)

CodePudding user response:

Ok got it figure out.

Private Async Function RunAScript_Worker(ScriptName As String, objScript As Object) As Task(Of Integer)

    Try
        Dim result As Task(Of Integer) = CType(objScript.GetType().GetMethod(ScriptName).Invoke(objScript, Nothing), Task(Of Integer))
        Await result
        Return result.Result
    Catch ex As Exception
        Throw ex
    End Try

End Function

And you call it like this:

rv = Await RunAScript_Worker(ScriptName, ClsContainingMethod)

This uses reflection and .Invoke and by adding Task(Of Integer) type turns it into an awaitable method.

You also need to add Async the the called method, but you can leave the ones the don't need it alone and it will work fine.

Edit:

Well, almost there. The problem arises when I try to return a value from the other functions that are not set to async. The await expects a Task(of Integer) but the non-async function return just Integer and I get a run time error.

So I figured out how to use reflection do determine if the method was async. I discovered the name paramerer in GetMethod() is case sensitive so for that and other reasons I added check before executing the method. I also like @Charlieface's solution better than mine so:

If Not objScripts.GetType().GetMethod(ScriptName) Is Nothing Then
    If objScripts.GetType().GetMethod(ScriptName).ReturnTypeCustomAttributes.ToString.Contains("Task") Then
        Return Await DirectCast(CallByName(objScripts, ScriptName, CallType.Method), Task(Of Integer))
    Else
        Return CallByName(objScripts, ScriptName, CallType.Method)
    End If
Else
    ' Exception handling
End If
  • Related