在f#工作流中运行c#async方法

use*_*480 4 f# c#-to-f# async-await

我试图让下面的代码在F#异步工作流中工作,但我在表达式中收到错误"Unexpected symbol'}'".我对F#和async都很新.我在这里想念的是什么

let someFunction (req : HttpRequestMesssage) a b = 

    // code
    async{
        let! readToProvider =
            req.Content.ReadAsMultipartAsync(provider)
            |> Async.AwaitIAsyncResult 

    } |> Async.RunSynchronously

    req.CreateResponse(HttpStatusCode.OK)
Run Code Online (Sandbox Code Playgroud)

Dax*_*ohl 6

我担心我之前的回答并不是你想要的.我提供的只是让你完成编译错误.但有一点吧,就是它不是异步运行. Task.Wait并且Async.RunSynchronously将阻止正在运行的线程,直到操作完成.

如果你想实际上异步的,即不是阻塞,你必须将整个方法,或者至少它的最后一部分放入async块中,这样你实际上是将一个async操作返回给调用者.所以答案是

let someFunction (req : HttpRequestMesssage) a b = 
  async {
    let! readToProvider = (req.Content.ReadAsMultipartAsync provider) |> Async.AwaitIAsyncResult 
    return req.CreateResponse HttpStatusCode.OK
  }
Run Code Online (Sandbox Code Playgroud)

选项不返回响应,而是返回Async<Response>.所以现在调用者可以决定如何运行它,阻塞或真正异步.

这样,如果您使用的是处理异步请求的Web服务器,那么您只需将此函数连接到端点(可能在连接点将其转换Async为a Task,因为大多数.net异步Web服务器都是从C#透视图编写的)并且它将在不阻塞线程的情况下异步运行.或者如果你从另一个异步操作中调用它,你可以做do! someFunction ...,它将异步运行.但是如果调用者不关心并且只想同步运行,那么它可以做到someFunction ... |> Async.RunSynchronously.所以你在那里获得更大的灵活性 您可以随时定义这let someFunctionSync ... = someFunction ... |> Async.RunSynchronously是否是更常见的用例.

除非你真的想要强制执行阻止,否则我建议采用这种方式.


Dax*_*ohl 5

你说得对.你只是得到错误,因为你async用一个let!表达式结束你的块.改变它return!,或者do! ... |> Async.Ignore 你会很好.

F#中的块(既不是工作流也不是常规代码块)不应该以let.

当然,如果所有真的做的工作流程是一个电话,你并不需要在所有的工作流程块(你从来没有真正应该需要编写一个块单个呼叫).做就是了

req.Content.ReadAsMultipartAsync provider
  |> Async.AwaitIAsyncResult 
  |> Async.Ignore
  |> Async.RunSynchronously
req.CreateResponse HttpStatusCode.OK
Run Code Online (Sandbox Code Playgroud)

或者就此而言,只需使用内置的Tasks Wait,它与Async.RunSynchron相同:

(req.Content.ReadAsMultipartAsync provider).Wait()
Run Code Online (Sandbox Code Playgroud)