【发布时间】:2016-09-21 20:41:16
【问题描述】:
我是 F# 新手,正在尝试将一些 C# ASP.NET Core 代码转换为 F#
有一个 C# 控制器 here 和一个工作翻译的 F# 控制器 here
即使我得到它的工作,我似乎无法弄清楚如何使控制器动作异步。这些方法在注入的 Commands 对象和 Queries 对象上调用异步代码。命令和查询目前在 C# 中实现。
例如,一些异步 C# 控制器方法是:
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
这些方法有效,但我认为它们没有正确完成,因为它们没有等待查询和命令上的异步调用。我已经反复试验了几个小时,但我为使控制器方法异步所做的每一次尝试都会导致它们不会向浏览器返回任何数据,即使它们返回 200 状态代码也是如此。你可以在F# controller看到我的一些尝试被注释掉了
希望一些 F# 大师可以帮助我正确翻译这些方法。目前在使用 ASP.NET Core 的 F# 方面存在一些非常糟糕的工具问题,这使得像我这样的新手更加困难。我在readme中提到了这些问题
代码中有一些额外的方法,但我认为如果我可以学习如何解决这些方法,那么相同的解决方案可能会适用于其他方法。
代码位于公共存储库中,因此只要您安装了最新的 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# 方法有效,但生成的 json 输出与 C# 版本不同
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# 版本产生预期的输出
【问题讨论】:
-
尝试 Async.AwaitTask
-
你可以在这篇博文的最后看到一个异步控制器动作的例子:blog.ploeh.dk/2016/04/11/async-as-surrogate-io这有帮助吗?
-
@mark-seemann 谢谢!感谢您的帖子,我取得了一些进展,并更新了我的问题,希望获得进一步的见解
-
queries.GetAll()的返回类型是什么?
标签: f# asp.net-core