C# async / await method to F#? - f#

I am trying to learn F# and am in the process of converting some C# code to F#.
I have the following C# method:
public async Task<Foo> GetFooAsync(byte[] content)
{
using (var stream = new MemoryStream(content))
{
return await bar.GetFooAsync(stream);
}
}
Where bar is some private field and GetFooAsync returns a Task<Foo>.
How does this translate to F#?
Here is what I currently have:
member public this.GetFooAsync (content : byte[]) =
use stream = new MemoryStream(content)
this.bar.GetFooAsync(stream)
Which returns a Task.

In F#, asynchrony is represented by the async computation builder, which is not an exact analog of Task, but can generally be used in place of one:
member public this.GetFooAsync (content : byte[]) =
async {
use stream = new MemoryStream(content)
return! this.bar.GetFooAsync(stream) |> Async.AwaitTask
}
|> Async.StartAsTask

If you are converting async/await-intensive C# code to F#, it might get cumbersome because of the difference between F#'s async and Task and the fact that you always have to call Async.AwaitTask
To avoid that you can use FSharpx library, which has a task computation expression.
let tplAsyncMethod p = Task.Run (fun _ -> string p)
// awaiting TPL method inside async computation expression
let asyncResult = async {
let! value1 = tplAsyncMethod 1 |> Async.AwaitTask
let! value2 = tplAsyncMethod 2 |> Async.AwaitTask
return value1 + value2
}
// The same logic using task computation expression
open FSharpx.Task
let taskResult = task {
let! value1 = tplAsyncMethod 1
let! value2 = tplAsyncMethod 2
return value1 + value2
}
The result of asyncResult is Async<string> and the result of taskResult is Task<string>.

Related

How to use while loop in F# Async expression?

How would I go about writing the following in F#?
var reader = await someDatabaseCommand.ExecuteReaderAsync();
while (await reader.ReadAsync())
{
var foo = reader.GetDouble(1);
// ...
}
I'm very new to F# so this is the best I can come up with
task {
let! reader = someDatabaseCommand.ExecuteReaderAsync ()
let! tmp1 = reader.ReadAsync ()
let mutable hasNext = tmp1
while hasNext do
// ...
let! tmp2 = reader.ReadAsync ()
hasNext <- tmp2
}
I know it's a C# library so it's not going to be perfect, but I'd like to avoid needing to store the result of ReadAsync in a variable, let alone have two temporaries. I don't know of a way to get the "result" of a Task without binding it to a name. Perhaps a recursive solution would work?
This library works very nicely with C#, because you can use await in the condition of the loop. I think that using recursive computation expression in F# is a bit nicer than the imperative solution (I do not think you can simplify that), but it is about the same length:
task {
let! reader = someDatabaseCommand.ExecuteReaderAsync ()
let rec loop () = task {
let! hasNext = reader.ReadAsync ()
if hasNext then
// ..
return! loop () }
return! loop ()
}
A more elaborate solution would be to use F# asynchronous sequences (from the FSharp.Control.AsyncSeq library). I think this only works for async (and so you'd have to use that instead of task), but it makes the code nicer. You can define a function that runs a command and returns an asynchronous sequence of results (for simplicity, I just return the reader, which is a bit dirty, but works):
#r "nuget: FSharp.Control.AsyncSeq"
#r "nuget: System.Data.SqlClient"
open FSharp.Control
let runCommand (cmd:System.Data.SqlClient.SqlCommand) = asyncSeq {
let! reader = cmd.ExecuteReaderAsync () |> Async.AwaitTask
let rec loop () = asyncSeq {
let! hasNext = reader.ReadAsync () |> Async.AwaitTask
if hasNext then
yield reader
yield! loop () }
yield! loop () }
Given this, you can very nicely iterate over the results using plain for loop inside async (using an overload added by the AsyncSeq library):
async {
for reader in runCommand someDatabaseCommand do
let foo = reader.GetDouble(1)
() }

Using Task and Async together for Asynchronous operations on seperate threads in F#

I'm being a little adventurous with my code for the amount of experience I have with F# and I am a little worried about cross threading issues.
Background:
I have a number of orders where I need to validate the address. Some of the orders can be validated against google maps geocoding API which allows 50/ second. the rest are Australian PO Boxes which we don't have many of - but I need to validate them against a different API that only allows 1 call per second.
I have switched over most of my code from async{} functions to task{} functions and I am assuming to get something on several threads at the same time it needs to be in an async{} function or block and be piped to Async.Parallel
Question: Is this the right way to do this or will it fall over? I am wondering if I am fundamentally thinking about this the wrong way.
Notes:
I am passing a database context into the async function and updating the database within that function
I will call this from a C# ( WPF ) Application and report the progress
Am I going to have cross threading issues?
let validateOrder
(
order: artooProvider.dataContext.``dbo.OrdersEntity``,
httpClient: HttpClient,
ctx: artooProvider.dataContext,
isAuPoBox: bool
) =
async {
// Validate Address
let! addressExceptions = ValidateAddress.validateAddress (order, httpClient, ctx, isAuPoBox) |> Async.AwaitTask
// SaveExceptions
do! ctx.SubmitUpdatesAsync()
// return Exception count
return ""
}
let validateGMapOrders(httpClient: HttpClient, ctx: artooProvider.dataContext, orders: artooProvider.dataContext.``dbo.OrdersEntity`` list) =
async {
let ordersChunked = orders |> List.chunkBySize 50
for fiftyOrders in ordersChunked do
let! tasks =
fiftyOrders
|> List.map (fun (order) -> validateOrder (order, httpClient, ctx, false) )
|> Async.Parallel
do! Async.Sleep(2000)
}
let validateOrders (ctx: artooProvider.dataContext, progress: IProgress<DownloadProgressModel>) =
task {
let unvalidatedOrders =
query {
for orders in ctx.Dbo.Orders do
where (orders.IsValidated.IsNone)
select (orders)
}
|> Seq.toList
let auPoBoxOrders =
unvalidatedOrders
|> List.filter (fun order -> isAUPoBox(order) = true )
let gMapOrders =
unvalidatedOrders
|> List.filter (fun order -> isAUPoBox(order) = false )
let googleHttpClient = new HttpClient()
let auspostHttpclient = Auspost.AuspostApi.getApiClient ()
// Google maps validations
do! validateGMapOrders(googleHttpClient,ctx,gMapOrders)
// PO Box Validations
for position in 0 .. auPoBoxOrders.Length - 1 do
let! result = validateOrder (gMapOrders[position], auspostHttpclient, ctx, true)
do! Task.Delay(1000)
return true
}
When I have had to deal with rate-limited API problems I hide that API behind a MailboxProcessor that maintains an internal time to comply with the rate limit but appears as a normal async API from the outside.
Since you have two API's with different rate limits I'd parameterise the time delay and processing action then create one object for each API.
open System
type Request = string
type Response = string
type RateLimitedProcessor() =
// Initialise 1s in past so ready to start immediately.
let mutable lastCall = DateTime.Now - TimeSpan(0, 0, 1)
let mbox = new MailboxProcessor<Request * AsyncReplyChannel<Response>>((fun mbox ->
let rec f () =
async {
let! (req, reply) = mbox.Receive()
let msSinceCall = (DateTime.Now - lastCall).Milliseconds
// wait 1s between requests
if msSinceCall < 1000 then
do! Async.Sleep (1000 - msSinceCall)
lastCall <- DateTime.Now
reply.Reply "Response"
// Call self recursively to process the next incoming message
return! f()
}
f()
))
do mbox.Start()
member __.Process(req:Request): Async<Response> =
async {
return! mbox.PostAndAsyncReply(fun reply -> req, reply)
}
interface IDisposable with
member this.Dispose() = (mbox :> IDisposable).Dispose()

How to do await an Async method, similar to C#

How to do an simple await in F# ?
In C# I have code like this:
await collection.InsertOneAsync(DO);
var r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO)
So I created a let await = ... to my F# code become more similar with my C# code.
My current F# code is this:
let awaits (t: Threading.Tasks.Task) = t |> Async.AwaitTask |> Async.RunSynchronously
let await (t: Threading.Tasks.Task<'T>) = t |> Async.AwaitTask |> Async.RunSynchronously
let Busca (numero) =
let c = collection.Find(fun d -> d.Numero=numero).ToList()
c
let Insere(DO: DiarioOficial) =
//collection.InsertOneAsync(DO) |> Async.AwaitTask |> Async.RunSynchronously
collection.InsertOneAsync(DO) |> awaits
let Salva (DO: DiarioOficial) =
//let r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO) |> Async.AwaitTask |> Async.RunSynchronously
let r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO) |> await
r
I want to have only one definition for await (awaits), but the best I could do is this, because on Insere, type is Task, but on Salva, type is Task<'T>
If i use only the await, I get this compile error:
FS0001 The type 'Threading.Tasks.Task' is not compatible with the type 'Threading.Tasks.Task<'a>'
If I use only the awaits, it compiles, but I lose the return type from the async Task
I want to merge the await and awaits in a single
let await = ...
How can I do this?
In F# we tend to use another syntax. It is described e.g. here: https://fsharpforfunandprofit.com/posts/concurrency-async-and-parallel/.
or here: https://learn.microsoft.com/en-us/dotnet/fsharp/tutorials/asynchronous-and-concurrent-programming/async
The idea of working with C# Tasks is to "convert" them to async with Async.Await<'T>
You can do it probably another way, but it is the most straightforward.
There are two parts of writing async code in both F# and C#.
You need to mark the method or code block as asynchronous. In C#, this is done using the async keyword. The F# equivalent is to use the async { ... } block (which is an expression, but otherwise, it is similar).
Inside async method or async { .. } block, you can make non-blocking calls. In C#, this is done using await and in F# it is done using let!. Note that this is not just a function call - the compiler handles this in a special way.
F# also uses Async<T> type rather than Task<T>, but those are easy to convert - e.g. using Async.AwaitTask. So, you probably want something like this:
let myAsyncFunction () = async {
let! _ = collection.InsertOneAsync(DO) |> Async.AwaitTask
let r = collection.ReplaceOneAsync((fun d -> d.Id = DO.Id), DO)
// More code goes here
}
I used let! to show the idea, but if you have an asynchronous operation that returns unit, you can also use do!
do! collection.InsertOneAsync(DO) |> Async.AwaitTask

Using TaskCompletionSource in F# for use in a .NET library

Considering the following
type MyClass () =
member x.ReadStreamAsync(stream:Stream) =
async {
let tcs = new TaskCompletionSource<int>()
let buffer = Array.create 2048 0uy
let! bytesReadCount = stream.ReadAsync(buffer, 0, buffer.Length) |> Async.AwaitTask
if bytesReadCount > 0 then
for i in 0..bytesReadCount do
if buffer.[i] = 10uy then
tcs.SetResult(i)
// Omitted more code to handle the case if 10uy is not found..
return tcs.Task
}
The code reads from a stream until in meets a certain character (represented by a byte value) at which point the task returned by the method completes.
The function signature of DoSomethingAsync is unit -> Async<Task<int>>, but I would like it to be unit -> Task<int> such that it can be used more generally in .NET.
Can this be done in F# using an asynchronous expression, or do I can to rely more on the Task constructs of .NET?
Given that you don't actually use the async workflow for anything in your example, the easiest solution would be to forgo it entirely:
member x.DoSomethingAsync() =
let tcs = new TaskCompletionSource<int>()
Task.Delay(100).Wait()
tcs.SetResult(10)
tcs.Task
This implementation of DoSomethingAsync has the type unit -> Task<int>.
It's not clear to me exactly what you're trying to do, but why don't you just do the following?
member x.DoSomethingAsync() =
async {
do! Async.Sleep 100
return 10 } |> Async.StartAsTask
This implementation also has the type unit -> Task<int>.
Based on the updated question, here's a way to do it:
member x.DoSomethingAsync(stream:Stream) =
async {
let buffer = Array.create 2048 0uy
let! bytesReadCount =
stream.ReadAsync(buffer, 0, buffer.Length) |> Async.AwaitTask
if bytesReadCount > 0
then
let res =
[0..bytesReadCount]
|> List.tryFind (fun i -> buffer.[i] = 10uy)
return defaultArg res -1
else return -1
}
|> Async.StartAsTask
The DoSomethingAsync function has the type Stream -> System.Task<int>. I didn't know what to do in the else case, so I just put -1, but I'm sure you can replace it with something more correct.

Async Controller Actions in F#

Using C# - ASP.NET MVC 4, I can define an async controller action like:
public async Task<ActionResult> IndexWorks()
{
var data = await DownloadAsync("http://stackoverflow.com");
return Content(data);
}
Is there a way to do something similar, using F#?
I'm aware of that I could use the AsyncManager approach. I'm also aware of that #Tomas Petricek have made a quite neat AsyncActionBuilder, but it just feels like a lot of boilerplate, compared to the C# approach.
async/await uses Tasks, so you'll need to convert back and forth between Task object and F# Async objects. To convert from Task to Async, use Async.AwaitTask. To do the opposite use Async.StartAsTask. Your example becomes:
member x.IndexWorks() =
async {
let! data = Async.AwaitTask (DownloadAsync "http://stackoverflow.com")
return x.Content(data)
} |> Async.StartAsTask
Alternatively, instead of using the async computation expression, you can use a computation expression that works for Tasks out of the box. There's one in FSharpx:
let task = FSharpx.Task.TaskBuilder()
(...)
member x.IndexWorks() = task {
let! data = DownloadAsync "http://stackoverflow.com"
return x.Content(data)
}
It actually seems like a fellow programmer, Dmitry Morozov have made such thing possible. He have made a custom AsyncWorkflowController that makes it possible to return Async<ActionResult> from an ActionResult. The code for the AsyncWorkFlowController can be found at http://fssnip.net/5q.
However, his implementation makes it very difficult to debug, due to the fact that the stack trace wont be preserved when rethrowen in the custom controller. Therefore I've made a little change to make this possible:
member actionDesc.EndExecute(asyncResult) =
match endAsync'.Value(asyncResult) with
| Choice1Of2 value -> box value
| Choice2Of2 why ->
// Preserve the stack trace, when rethrow
ExceptionDispatchInfo.Capture(why).Throw()
obj() (* Satisfy return value *) } } }
Also I've changed the following line: new ReflectedControllerDescriptor(controllerType),
to new ReflectedAsyncControllerDescriptor(controllerType) - However this change is purely optional, as it wont make any difference. I just found it more logical to use the Async one.
The full code would then be:
open System
open System.Web.Mvc
open System.Web.Mvc.Async
open System.Runtime.ExceptionServices
open Unchecked
type AsyncWorkflowController() =
inherit AsyncController()
override __.CreateActionInvoker() =
upcast { new AsyncControllerActionInvoker() with
member __.GetControllerDescriptor(controllerContext) =
let controllerType = controllerContext.Controller.GetType()
upcast { new ReflectedAsyncControllerDescriptor(controllerType) with
member ctrlDesc.FindAction(controllerContext, actionName) =
let forwarder = base.FindAction(controllerContext, actionName) :?> ReflectedActionDescriptor
if(forwarder = null || forwarder.MethodInfo.ReturnType <> typeof<Async<ActionResult>>) then
upcast forwarder
else
let endAsync' = ref (defaultof<IAsyncResult -> Choice<ActionResult, exn>>)
upcast { new AsyncActionDescriptor() with
member actionDesc.ActionName = forwarder.ActionName
member actionDesc.ControllerDescriptor = upcast ctrlDesc
member actionDesc.GetParameters() = forwarder.GetParameters()
member actionDesc.BeginExecute(controllerContext, parameters, callback, state) =
let asyncWorkflow =
forwarder.Execute(controllerContext, parameters) :?> Async<ActionResult>
|> Async.Catch
let beginAsync, endAsync, _ = Async.AsBeginEnd(fun () -> asyncWorkflow)
endAsync' := endAsync
beginAsync((), callback, state)
member actionDesc.EndExecute(asyncResult) =
match endAsync'.Value(asyncResult) with
| Choice1Of2 value -> box value
| Choice2Of2 why ->
// Preserve the stack trace, when rethrow
ExceptionDispatchInfo.Capture(why).Throw()
obj() (* Satisfy return value *) } } }
Usage:
type TestController() =
inherit AsyncWorkflowController()
member x.IndexWorks() = async {
let startThread = Thread.CurrentThread.ManagedThreadId
let! data = asyncDownload "http://stackoverflow.com"
let endThread = Thread.CurrentThread.ManagaedThreadId
return ContentResult(Content = "Start = %i | End = %i" startThread endThread) :> ActionResult }
And to confirm that it actually does everything async, and is not blocking any thread from the ASP.NET Pool, use:
member x.IndexWorks() = async {
let startThread = Thread.CurrentThread.ManagedThreadId
let! data = asyncDownload "http://stackoverflow.com"
let endThread = Thread.CurrentThread.ManagaedThreadId
return ContentResult(Content = "Start = %i | End = %i" startThread endThread) :> ActionResult }
The start and end thread will differ, hence the start thread was put back into the pool, and a new was returned when the async operation had completed.
I think there might be a bunch of people trying to do something like
type SomeController() =
inherit ApiController()
member x.Get() =
let data = Download("http://stackoverflow.com")
x.Ok(data) :> IHttpActionResult // Using built in Ok, BadRequest, etc.
Where type Get() = unit -> Task<IHttpActionResult> as expected from a C# WebApi Controller
If you try to do it as the accepted answer suggests (while trying to use the built-in Ok, BadRequest, etc. methods) you run into
can't access protected members from within a lambda
To solve this I used the ExtensionMethods directly rather than try to do contort between async {} and Task that MVC is expecting
type SomeController() =
inherit ApiController()
member x.Get() = async {
let! data = DownloadAsync("http://stackoverflow.com") |> Async.AwaitTask
return System.Web.Http.Results.OkNegotiatedContentResult(data, x) :> IHttpActionResult // Pass in 'this' pointer (x) into extension method along with data
} |> Async.StartAsTask
This with the additional upcast :> IHttpActionResult you can also return different behavior BadRequest, etc from your model and still have it run async and the type signatures should work out and compile cleanly

Resources