Start task without waiting - vb.net

I would like to start a background task without using the Await keyword. Instead I want to monitor the task at various points and restart it when necessary to update information in the background. Here is the method I am trying to call:
Public Async Function UpdateVehicleSummaries(p_vehicleID As Int32) As Task(Of Boolean)
Dim tempVehicle As Koolsoft.MARS.BusinessObjects.Vehicle
For Each tempVehicle In Vehicles
If p_vehicleID = 0 Or p_vehicleID = tempVehicle.VehicleID Then
Await UpdateVehicleStats(tempVehicle)
End If
Next
Return True
End Function
The code I am trying to start the task doesn't seem to work and I'm not sure how to provide the parameter. I get an error that "Task(Of Boolean) cannot be converted to System.Action and or an error on the parameter"
Dim tempTask As Task
tempTask = New Task(UpdateVehicleSummaries(tempVehicleID))
tempTask.Start()
Any help would be appreciated.

Since UpdateVehicleSummaries is already asynchronous, you should be abel to just do:
Dim tempTask As Task(Of Boolean) = UpdateVehicleSummaries(tempVehicleID)
The returned Task(Of T) will be "hot" (running), but shouldn't block, as the Await call will immediately return control flow to the caller at that point.
A more typical use of this method, if you need to perform other work while this runs, would be to do the following:
Dim tempTask = UpdateVehicleSummaries(tempVehicleID)
' Do your other work
Dim success = Await tempTask ' Get the boolean result asynchronously...
' use the result

Related

VB - CefSharp not return values

I can fill a value of a specific field with the code below
nav.EvaluateScriptAsync("document.getElementById('email').value='teste';")
but I can't return the value of this field
Dim placeholder As Task(Of JavascriptResponse) = nav.EvaluateScriptAsync("document.getElementById('email').value")
Task.WaitAll()
MsgBox(placeholder.Result.ToString)
both (placeholder.Result.ToString) and (placeholder.ToString) return "CefSharp.JavascriptResponse"
You can obtain the value from JavascriptResponse.Result property. Check the Success property first, if the script evaluation failed the error will be contained with the Message property.
http://cefsharp.github.io/api/97.1.x/html/Properties_T_CefSharp_JavascriptResponse.htm
I got it that way.
Public Async Function testeAsync() As Task(Of String)
Dim placeholder2 As JavascriptResponse = Await nav.EvaluateScriptAsync("document.getElementById('email').placeholder")
If (placeholder2.Success) Then
MsgBox(placeholder2.Result)
End If
End Function
But when I do a return in the function and call the function in a struct, how do I call waiting for the async function to complete?
This way the sub prints the result before the asynchronous process ends.
Sub testeResultado()
Dim returnedTaskTResult As Task(Of String) = testeAsync()
MsgBox(returnedTaskTResult.ToString)
End Sub

Task.WaitAll() in DataGridView.RowEnter event causes DataError

I am using Advanced DataGridView (https://github.com/davidegironi/advanceddatagridview) to display some data in my application.
Within the RowEnter event I create tasks like this:
Dim One As String = dgv.Item("Col1", e.RowIndex)
Dim Two As String = dgv.Item("Col2", e.RowIndex)
Dim Three As String = dgv.Item("Col3", e.RowIndex)
Dim tOne As Task(Of DataTable) = Task.Run(Function() Return GetData(One) End Function)
Dim tTwo As Task(Of DataTable) = Task.Run(Function() Return GetData(Two) End Function)
Dim tThree As Task(Of DataTable) = Task.Run(Function() Return GetData(Three) End Function)
Task.WaitAll(tOne, tTwo, tThree)
'Do stuff with the results of tasks to update other labels etc on the form
lblDate.Text = tOne.Result.Rows(0).Item("Date").ToString
The reason for this is that if the GetData() function takes, say, 5 seconds to return doing this without tasks would result in a 15 second wait (5+5+5) whereas with tasks it only takes 5 seconds (or whatever the slowest task is) and Task.WaitAll gives control back to UI (unsure on correct terminology) so it feels a bit snappier.
However when I apply a filter I get the following exception repeatedly, where [n] is any number, I've seen indexes of -1 upwards (seems to depend on the number of visible rows?):
System.IndexOutOfRangeException: Index [n] does not have a value.
at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)
at System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetError(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex)
If I remove the Task.WaitAll() or do the functions synchronously I don't get the above error.
I'm completely at a loss as to what the underlying cause of that error is, or what I should do different to avoid it.
I have seen this answer but I'm not sure how to apply to my situation.
Use async event handler and await the tasks using Task.WhenAll
' Mark the event handler with Async so you can use Await in it.
Private Async Sub Grid_RowEnter(sender As Object, e As WhateverEventArgs)
Dim One As String = dgv.Item("Col1", e.RowIndex)
Dim Two As String = dgv.Item("Col2", e.RowIndex)
Dim Three As String = dgv.Item("Col3", e.RowIndex)
Dim tOne As Task(Of DataTable) = Task.Run(Function() Return GetData(One) End Function)
Dim tTwo As Task(Of DataTable) = Task.Run(Function() Return GetData(Two) End Function)
Dim tThree As Task(Of DataTable) = Task.Run(Function() Return GetData(Three) End Function)
' await all the tasks
Await Task.WhenAll(tOne, tTwo, tThree)
' back on UI thread
'Do stuff with the results of tasks to update other labels etc on the form
lblDate.Text = tOne.Result.Rows(0).Item("Date").ToString
End Sub
Reference Async/Await - Best Practices in Asynchronous Programming

VB.Net Async - Check large list of string for a match

I need this function to run Async, but can't seem to figure a way to do it.
LIST1 is Public and contains a List(of String) with a few hundred entries. List Declaration:
Public LIST1 As New List(Of String)
Normally, I'd run the following code to retrieve the boolean of whether or not he list contains the entry:
Dim result = LIST1.Any(Function(s) value.ToLower.Contains(s))
Full non-Async function:
Function CheckValue(byval value As String) As Boolean
Dim result As Boolean = LIST1.Any(Function(s) value.ToLower.Contains(s))
Return result
End Function
That works well as expected.
How would I implement the same as an Async function? I've tried:
Async Function CheckValue(byval value as String) As Task(Of Boolean)
Dim result as Task(Of Boolean) = Await LIST1.Any(Function(s) value.ToLower.Contains(s))
Return result
End Function
I get the following error: 'Await' requires that the type 'Boolean' have a suitable GetAwaiter method.
Any thoughts?
It does not return a task, so there is no reason to await it. If your concern is that it is too slow, you can run any synchronous code in a new thread, and then await the completion of that thread, like this:
Dim result As Boolean = Await Task.Run(Function() LIST1.Any(Function(s) value.ToLower.Contains(s)))
Or, as GSerg mentioned, though it technically doesn't make it awaitable, you can use AsParallel.Any:
Dim result As Boolean = LIST1.AsParallel.Any(Function(s) value.ToLower.Contains(s))
However, be aware that starting new threads has a fair amount of overhead, so starting up a new thread, just to do a small amount of work, may make it actually run slower.
In this particular case, if performance is key, I would recommend looking into various search/indexing algorithms. For instance, take a look at some of the ones mentioned here. I wouldn't be surprised if there are opensource .NET libraries for those kinds of algorithms.

Running .Net Tasks in parallel that return different objects

I am currently looking at processing 2 data downloads from a WCF service that return collections of different objects and was wondering if there was a better method than running the two asynchronous tasks synchronously.
In this case can I implement as Task.WhenAll or Task.WhenAny methodology to run these tasks in parallel?
Public Property Users As IEnumerable(Of UserDto)
Get
Return _users
End Get
Set(value As IEnumerable(Of UserDto))
_users = value
RaisePropertyChanged("Users")
End Set
End Property
Public Property ApplicationRoles() As IEnumerable(Of ApplicationRoleDto)
Get
Return _roles
End Get
Set(ByVal value As IEnumerable(Of ApplicationRoleDto))
_roles = value
RaisePropertyChanged("ApplicationRoles")
End Set
End Property
Private Async Sub GetUserDetails()
Users = Await _serviceHelper.GetUsers()
ApplicationRoles = Await _serviceHelper.GetApplicationRoles
End Sub
Possible solution
I could use the Task Parrallel Library but I am not sure if this is the most efficient method, plus I can't await the return.
Parallel.Invoke(Sub() Users = _serviceHelper.GetUsers(),
Sub() ApplicationRoles = _serviceHelper.GetApplicationRoles())
Task.WhenAll should work just fine. Pardon if the syntax isn't quite correct; my VB is incredibly rusty:
Private Async Function GetUserDetailsAsync() As Task
Dim UsersTask = _serviceHelper.GetUsersAsync()
Dim ApplicationRolesTask = _serviceHelper.GetApplicationRolesAsync
Await Task.WhenAll(UsersTask, ApplicationRolesTask);
Users = Await UsersTask
ApplicationRoles = Await ApplicationRolesTask
End Function
I also took the liberty of changing your Sub to a Function (you should avoid Async Sub), and making your Async methods end with Async, as per the convention.

Trying to get asynchronous functions with arguments and returns to work

I have been trying to get a function to work asynchronously with a GUI window, and having very limited success.
The code below is my function, XXX, with a delegate and Callback - to allow stopping the GUI thread, without getting an error.
It works though - if it is a Sub, not a function, and if it doesn't have any arguments.
I don't know how to change it so I can check its return value... I have found a little help in some examples, http://msdn.microsoft.com/en-us/library/system.iasyncresult.asyncstate.aspx - but they print the return value in the callback, and I can't see how to get it in the caller.
I can't find any way to use arguments in my function.
Private Function XXX_Callback(ByVal ia As IAsyncResult)
Dim d As XXXDelegate = CType(CType(ia, Runtime.Remoting.Messaging.AsyncResult).AsyncDelegate, XXXDelegate)
d.EndInvoke(ia)
Dim result As AsyncResult = CType(ia, AsyncResult)
Dim caller As XXXDelegate = CType(result.AsyncDelegate, XXXDelegate)
Dim returnValue As Boolean = caller.EndInvoke(ia)
XXX_Finish() ' needs the "vvv argument, I don't know how to get it
' The returnValue is here but I don't know how to send it to the caller
End Function
'Private Function XXX_Finish(ByVal vvv as Boolean) As Boolean
' this probably needs to return something, I don't know what/ how to get it
Private Function XXX_Finish() As Boolean
' something
myGui.Finish()
End Function
' Private Delegate Function XXXDelegate(ByVal vvv As Integer) As Boolean
' Public Function XXX(ByVal vvv As Integer) As Boolean ' This is what I would like
Private Delegate Sub XXXDelegate()
Public Sub XXX()
'
myGui.Update()
'
End Sub
Public Sub Caller()
'
myGui = New SomeGui()
myGui.Begin()
Dim t As New XXXDelegate(AddressOf XXX)
t.BeginInvoke(AddressOf XXX_Callback, Nothing)
' more code, another call
End Sub
Private myGui As SomeGui
Please, could someone help me get this into a better shape, or get some examples that will help ? With the ones I have found in the past two days, I have reached a dead end...
Thank you.
After searching through lots of posts on the web, and reading a couple of books, I have found the best resource, with examples for each case that one might encounter:
http://support.microsoft.com/kb/315582
The answers to this particular question are in the above link, "Sample 2: Calling A Method Asynchronously by Using the EndInvoke() Call Pattern" and "Sample 5: Executing a Callback When an Asynchronous Method Completes."
The best thing about it though is the simple and organized fashion in which the options to use Invoke, EndInvoke, Callback are explained.
One thing to note: for my question above, the essential breakthrough was when I read the words "BeginInvoke() returns immediately and does not wait for the asynchronous call to complete."
So... trying to call another method, after it, was the wrong approach.
This is how i made an asyncronous function calls.
I declare the function in the module.
Private Delegate Function fnBolAsyncCallVerificacionNuevaVersion(ByVal pIntModo As Integer, ByVal pIntAccion As Integer) As Boolean
Private Delegate Function fnBolAsyncCallActualizacionTipoCambio(ByVal pIntActualizacionMandatoria As clsBusinessBoxData.tblTipoCambio.enumActualizacionMandatoria) As typBolResultadoFuncion
The functions receive some parameters and the first returns a boolean and the second returns an structure with 2 data, one boolean and one string.
In the load event of the form I call the functions.
sAsyncVerificaVersion = New fnBolAsyncCallVerificacionNuevaVersion(AddressOf fnBolVerificaActualizacion)
sAsyncVerificaVersion.BeginInvoke(enumDisplayGUIMode.Silent, typApplicationUpdate.CheckOnly, New AsyncCallback(AddressOf fnBolTerminaVerificacionVersion), Nothing)
sAsyncActualizaTiposCambio = New fnBolAsyncCallActualizacionTipoCambio(AddressOf fnBolActualizaTiposCambioYahoo)
sAsyncActualizaTiposCambio.BeginInvoke(clsBusinessBoxData.tblTipoCambio.enumActualizacionMandatoria.No, New AsyncCallback(AddressOf fnBolTerminaActualizacionTipoCambio), Nothing)
These calls will execute the function asyncronous and will callback the function defined when finished.
Then i receive the results in the callback functions defined.
Private Function fnBolTerminaVerificacionVersion(ByVal pIarResultado As IAsyncResult) As Boolean
Dim sClsResultado = CType(pIarResultado, Messaging.AsyncResult)
Dim sIarResultado As fnBolAsyncCallVerificacionNuevaVersion = CType(sClsResultado.AsyncDelegate, fnBolAsyncCallVerificacionNuevaVersion)
Dim sBolExisteNuevaVersion As Boolean = False
CheckForIllegalCrossThreadCalls = False
sBolExisteNuevaVersion = sIarResultado.EndInvoke(pIarResultado)
mnuBajarActualizacion.Enabled = sBolExisteNuevaVersion
CheckForIllegalCrossThreadCalls = True
Return True
End Function
Private Function fnBolTerminaActualizacionTipoCambio(ByVal pIarResultado As IAsyncResult) As Boolean
Dim sBolActualizacionExitosa As typBolResultadoFuncion
Dim sClsResultado = CType(pIarResultado, Messaging.AsyncResult)
Dim sIarResultado As fnBolAsyncCallActualizacionTipoCambio = CType(sClsResultado.AsyncDelegate, fnBolAsyncCallActualizacionTipoCambio)
CheckForIllegalCrossThreadCalls = False
sBolActualizacionExitosa = sIarResultado.EndInvoke(pIarResultado)
CheckForIllegalCrossThreadCalls = True
Return True
End Function
I hope they help.