I want to await a Task<int> returned by Entity Framework Core when saving changes with the following call: myDbContext.SaveChangesAsync true
I found at least 3 different ways of achieving that but I am not really sure which one is the best considering that I don't really care about the int result part in Task<int>, at the end of the day I just wanna to await.
Using Async.AwaitIAsyncResult and then Async.AwaitIgnore to ignore the Task<bool>:
async {
do! myDbContext.SaveChangesAsync true
|> Async.AwaitIAsyncResult
|> Async.AwaitIgnore
}
Upcasting the Task<int> to Task and then just awaiting that Task with Async.AwaitTask:
async {
do! myDbContext.SaveChangesAsync true
:> Task
|> Async.AwaitTask
}
Awaiting Task<int> with Async.AwaitTask and ignoring the result with Async.Ignore
async {
do! myDbContext.SaveChangesAsync true
|> Async.AwaitTask
|> Async.Ignore
}
AwaitIAsyncResult seems more relevant if I wanted to fetch a boolean in case of error while awaiting the task (and / or I wanted to have some control over the execution with a timeout): https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/async.awaitiasyncresult-method-%5Bfsharp%5D?f=255&MSPPError=-2147217396. I am also suspecting that this is the right if I wanted to avoid having an exception thrown to my face in case of something going wrong while awaiting and instead fetch a boolean.
Which leaves then the two other solutions, I would say that the last one translates better my intent of not caring about the int of Task<int> / Async<int>.
However I am not too sure, can someone can validate or invalidate my thoughts?
The interface IAsyncResult is a legacy from the very early days of async on .NET (remember FileStream.BeginRead/FileStream.EndRead), so it's used only when interop with legacy APIs.
The fact that Async.AwaitIAsyncResult returns Async<bool> does not mean that it handles exceptions in any way, in fact it does not.
So with Async.AwaitIAsyncResult out of the way, I'll say that your third example
async {
do! myDbContext.SaveChangesAsync true
|> Async.AwaitTask
|> Async.Ignore
}
is the way to go, since the intent is explicit.
I can't see how your example would compile so I hope I'm not missing something here.
I think this is how I'd tackle it:
open FSharp.Control.Tasks.V2 // From nuget package Taskbuilder.fs
let someExampleAsync (thing: bool) : Threading.Tasks.Task<int> =
task {
printfn "this got called"
return 1
}
let saveChanges() : Async<int> = someExampleAsync true |> Async.AwaitTask
// await once
saveChanges() |> Async.RunSynchronously |> ignore
// await a few times
let repeatIt =
async {
let! awaitOnce = saveChanges()
let! awaitAgain = saveChanges()
let! awaitAndAgain = saveChanges()
return "all done"
}
repeatIt |> Async.RunSynchronously |> ignore
Disclaimer: I'm a beginner.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With