Reputation: 1858
I am trying to get the below code to work in a F# async workflow, but I am getting the error "Unexpected symbol '}' in expression". I am fairly new to both F# and async in general. What am I missing here.
let someFunction (req : HttpRequestMesssage) a b =
// code
async{
let! readToProvider =
req.Content.ReadAsMultipartAsync(provider)
|> Async.AwaitIAsyncResult
} |> Async.RunSynchronously
req.CreateResponse(HttpStatusCode.OK)
Upvotes: 4
Views: 1432
Reputation: 10781
I worry that my previous answer wasn't quite what you want. What I supplied just got you through the compile error. But one thing about it, is that it does not run asynchronously. Task.Wait
and Async.RunSynchronously
will both block the running thread until the operation is complete.
If you want to actually be async, i.e. not blocking, you have to put the entire method, or at least the last part of it, into the async
block, such that you're actually returning an async
op to the caller. So the answer would be
let someFunction (req : HttpRequestMesssage) a b =
async {
let! readToProvider = (req.Content.ReadAsMultipartAsync provider) |> Async.AwaitIAsyncResult
return req.CreateResponse HttpStatusCode.OK
}
This option returns not the response, but an Async<Response>
. So now the caller can decide how to run it, either blocking or truly asynchronously.
This way if you're using a web server that handles asynchronous requests, then you can simply connect this function to an endpoint (probably converting the Async
to a Task
at the point of connection, since most .net async web servers are written from C# perspective) and it'll run asynchronously without blocking a thread. Or if you're calling it from another async op you can do do! someFunction ...
and it'll run asynchronously. But if the caller doesn't care and just wants to run synchronously, it can do someFunction ... |> Async.RunSynchronously
. So you get more flexibility there. And you can always define let someFunctionSync ... = someFunction ... |> Async.RunSynchronously
if that's the more common use case.
I'd recommend going this way unless you really want to enforce blocking.
Upvotes: 6
Reputation: 10781
You're doing it right. You're only getting the error because you're ending your async
block with a let!
expression. Change it to return!
, or do! ... |> Async.Ignore
and you'll be good.
Blocks in F# (neither workflows nor regular code blocks) should not end with let
.
Of course if all you're really doing in the workflow is that one call, you don't need the workflow block at all (you never really should need to write a block for a single call). Just do
req.Content.ReadAsMultipartAsync provider
|> Async.AwaitIAsyncResult
|> Async.Ignore
|> Async.RunSynchronously
req.CreateResponse HttpStatusCode.OK
Or for that matter, just use the built in Tasks Wait, which does the same thing as Async.RunSynchronously:
(req.Content.ReadAsMultipartAsync provider).Wait()
Upvotes: 5