gpt4 book ai didi

ASP.NET Core 中异步 Controller 方法的 F# 语法

转载 作者:行者123 更新时间:2023-12-01 12:25:57 25 4
gpt4 key购买 nike

我是 F# 新手,正在尝试将一些 C# ASP.NET Core 代码转换为 F#

有一个C# Controller here , 和一个工作翻译的 F# Controller here

即使我让它工作了,我似乎无法弄清楚如何使 Controller Action 异步。这些方法在注入(inject)的 Commands 对象和 Queries 对象上调用异步代码。命令和查询当前在 C# 中实现。

例如,一些异步 C# Controller 方法是:

    public async Task<IEnumerable<ToDoItem>> Get()
{
return await queries.GetAll();
}

[HttpGet("{id}", Name = "GetTodo")]
public async Task<IActionResult> GetById(string id)
{
var item = await queries.Find(id);
if (item == null)
{
return NotFound();
}
return new ObjectResult(item);
}

public async Task<IActionResult> Create([FromBody] ToDoItem item)
{
if (item == null)
{
return BadRequest();
}
if (string.IsNullOrEmpty(item.Id)) item.Id = Guid.NewGuid().ToString();

await commands.Add(item);
return CreatedAtRoute("GetTodo", new { id = item.Id }, item);
}

我已经将它们翻译成 F#,如下所示:
    [<HttpGet>]
member __.Get() =
__.Queries.GetAll() // this should be awaited

[<HttpGet("{id}", Name = "GetFSTodo")>]
member __.GetToDoItem(id) =
let data = __.Queries.Find(id) // this should be awaited
if isNull data
then __.NotFound() :> IActionResult
else
new ObjectResult(data) :> IActionResult

[<HttpPost>]
member __.Create([<FromBody>] item:ToDoItem) =
item.Id <- Guid.NewGuid().ToString()
(__.Commands.Add(item)) |> ignore // this should be awaited
let rv = new RouteValueDictionary()
rv.Add("id",item.Id)
__.CreatedAtRoute("GetTodo", rv, item) :> IActionResult

这些方法有效,但我认为它们没有正确完成,因为它们没有等待查询和命令上的异步调用。我已经反复试验了几个小时,但我为使 Controller 方法异步所做的每一次尝试都会导致它们没有向浏览器返回任何数据,即使它们返回 200 状态代码也是如此。你可以看到我的一些尝试在 F# controller 中被注释掉了。

希望一些 F# 大师可以帮助我正确翻译这些方法。目前在使用 ASP.NET Core 的 F# 方面存在一些非常糟糕的工具问题,这使得像我这样的新手更加困难。我在 readme 中提到了这些问题。

代码中还有一些其他方法,但我认为如果我可以学习如何解决这些方法,那么相同的解决方案可能会适用于其他方法。

该代码位于公共(public)存储库中,因此只要您安装了最新的 VS 更新和最新的 ASP.NET Core 工具,您就可以在 VS 2015 中轻松试用

更新:

感谢 Mark Seemann 的链接帖子,我能够让这个方法异步工作
[<HttpGet("{id}", Name = "GetFSTodo")>]
member __.GetToDoItem(id) =
async {
let! data = __.Queries.Find(id) |> asyncReturn
if isNull data
then return __.NotFound() :> IActionResult
else
return new ObjectResult(data) :> IActionResult }
|> Async.StartAsTask

通过使用辅助函数
let asyncReturn x = async { return x }

我仍在努力使用这种方法
[<HttpGet>]
member __.Get() =
async {
let! data = __.Queries.GetAll() |> asyncReturn
return data }
|> Async.StartAsTask

这是从这个 C# 方法翻译而来的:
[HttpGet]
public async Task<IEnumerable<ToDoItem>> Get()
{
return await queries.GetAll();
}

异步 F# 方法有效,但它产生与 C# 版本不同的 json 输出
C#
[{"id":"4f4e1596-6a48-4854-9982-7a2568aa1b1b","title":"add input validation","isDone":false,"dateAdded":"2016-09-20T21:16:04.8791044Z"},{"id":"9929b657-6a53-40b6-8c1c-1e4d0db593cd","title":"make F# controller async","isDone":false,"dateAdded":"2016-09-21T19:36:44.6650776Z"},{"id":"5bb5f544-6289-4051-ad65-d0dc016128e7","title":"learn F# basics","isDone":true,"dateAdded":"2016-09-22T11:59:00"},{"id":"e5e06118-c49f-496a-8175-9719ea72beed","title":"monkey business","isDone":false,"dateAdded":"2016-09-22T16:22:20.3133161Z"},{"id":"af0db8f2-6b49-4e31-86fa-e27c8e091f42","title":"funky bidness","isDone":false,"dateAdded":"2016-09-22T16:23:35.1175195Z"}]

F#
{"result":[{"id":"4f4e1596-6a48-4854-9982-7a2568aa1b1b","title":"add input validation","isDone":false,"dateAdded":"2016-09-20T21:16:04.8791044Z"},{"id":"9929b657-6a53-40b6-8c1c-1e4d0db593cd","title":"make F# controller async","isDone":false,"dateAdded":"2016-09-21T19:36:44.6650776Z"},{"id":"5bb5f544-6289-4051-ad65-d0dc016128e7","title":"learn F# basics","isDone":true,"dateAdded":"2016-09-22T11:59:00"},{"id":"e5e06118-c49f-496a-8175-9719ea72beed","title":"monkey business","isDone":false,"dateAdded":"2016-09-22T16:22:20.3133161Z"},{"id":"af0db8f2-6b49-4e31-86fa-e27c8e091f42","title":"funky bidness","isDone":false,"dateAdded":"2016-09-22T16:23:35.1175195Z"}],"id":65,"exception":null,"status":5,"isCanceled":false,"isCompleted":true,"creationOptions":0,"asyncState":null,"isFaulted":false}

所以我仍然可以使用一些帮助来让 F# 版本产生预期的输出

最佳答案

2016 年 9 月 28 日更新

感谢 Ruben Bartelink,这就是我的 Controller 现在正确实现为异步并处理 C# 和 F# 异步模式之间不同的细微差别的样子:

namespace FSharp.WebLib

open System
open Microsoft.AspNetCore.Mvc
open Microsoft.AspNetCore.Routing
open Microsoft.AspNetCore.JsonPatch
open FSharp.Models

module ActionResult =
let ofAsync (res: Async<IActionResult>) =
res |> Async.StartAsTask

[<Route("api/[controller]")>]
type FSToDoController(commands: IToDoCommands, queries: IToDoQueries) =
inherit Controller()

[<HttpGet>]
member this.Get() =
ActionResult.ofAsync <| async {
let! data = queries.GetAll()
return JsonResult(data) :> _ }

[<HttpGet("{id}", Name = "GetFsToDo")>]
member this.Get(id) =
ActionResult.ofAsync <| async {
let! res = queries.Find id
match res with
| None -> return this.NotFound() :> _
| Some data -> return ObjectResult(data) :> _ }

// create
[<HttpPost>]
member this.Post([<FromBody>] item:ToDoItem) =
ActionResult.ofAsync <| async {
if not this.ModelState.IsValid then
return this.BadRequest() :> _
else
let item = { item with Id = Guid.NewGuid() |> string }
do! commands.Add item
let rv = RouteValueDictionary()
rv.Add("id",item.Id)
return this.CreatedAtRoute("GetFsToDo", rv, item) :> _ }

// update
[<HttpPut("{id}")>]
member this.Put(id:String, [<FromBody>] item:ToDoItem) =
ActionResult.ofAsync <| async {
if (not this.ModelState.IsValid) || String.IsNullOrEmpty item.Id then
return this.BadRequest() :> _
else
let! res = queries.Find id
match res with
| None -> return this.NotFound() :> _
| Some toDo ->
do! commands.Update item
return NoContentResult() :> _ }

对于任何有兴趣学习 F# 尤其是在 ASP.NET Core 中使用的人,这是 proof of concept project on github 的一部分它同时具有 ToDo 列表后端 Web api 的 C# 和 F# 实现,这两者都是从使用聚合物 Web 组件实现的前端消耗的。模型和数据访问也以两种语言实现,为像我这样的 C# 开发人员学习 F# 提供了一个很好的比较

关于ASP.NET Core 中异步 Controller 方法的 F# 语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39626220/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com