ASP.NET Core中异步控制器方法的F#语法 [英] F# syntax for async controller methods in ASP.NET Core

查看:81
本文介绍了ASP.NET Core中异步控制器方法的F#语法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm new to F# and trying to translate some C# ASP.NET Core code into F#

有一个C#控制器这里,以及可正常翻译的F#控制器

There is a C# controller here, and a working translated F# controller here

即使我可以使用它,我似乎也无法弄清楚如何使控制器动作异步.这些方法在注入的Commands对象和Queries对象上调用异步代码.命令和查询当前在C#中实现.

even though I got it working, I can't seem to figure out how to make the controller actions async. The methods call async code on a Commands object and a Queries object that are injected. The Commands and Queries are currently implemented in C#.

例如,几个异步C#控制器方法是:

So for example a couple of the async C# controller methods are:

    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#了:

and I've translated those to F# like this:

    [<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状态代码也不会向浏览器返回任何数据.您可以在

These methods work but I think they are not correctly done since they aren't awaiting the async calls on Queries and Commands. I've thrashed for some hours with trial and error but every attempt I've made to make the controller methods async results in them not returning any data to the browser even though they return a 200 status code. You can see some of my attempts commented out in the F# controller

希望一些F#专家可以帮助我正确翻译这些方法.目前在ASP.NET Core的F#方面存在一些非常糟糕的工具问题,这对于像我这样的新手来说更加困难.我已经在自述文件

Hoping some F# guru(s) could help me translate those methods correctly. There are some pretty bad tooling issues currently in terms of F# with ASP.NET Core which makes it more difficult for a newbie like me. I've mentioned those issues in the readme

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

There are a few additional methods in the code but I figure if I can learn how to solve for these methods then the same solution will probably apply to the other methods.

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

The code is in a public repository so you can easily try it in VS 2015 as long as you have the latest VS updates and the latest ASP.NET Core tooling installed

更新:

由于Mark Seemann的链接,我能够使这种方法异步工作

thanks to the linked post by Mark Seemann, I was able to get this method working async

[<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 }

我仍然在努力使用这种方法

I'm still struggling with this method

[<HttpGet>]
member __.Get() =
    async {
           let! data = __.Queries.GetAll() |> asyncReturn
           return data  }
        |> Async.StartAsTask

从此C#方法翻译的

:

which is translated from this C# method:

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

异步F#方法可以工作,但它产生的json输出与C#版本不同

the async F# method works but it produces different json output than the C# version

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#版本产生预期输出方面使用一些帮助

so I still could use some help on how to make the F# version produce the expected output

推荐答案

更新2016-09-28

UPDATED 2016-09-28

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

Thanks to Ruben Bartelink this is what my controller looks like now correctly implemented as async and handling the nuances that differ between C# and F# async patterns:

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中使用)的人来说,这是

for anyone else interested in learning F# particularly for use in ASP.NET Core, this is part of a proof of concept project on github that has both C# and F# implementations of a ToDo list back end web api both of which are consumed from a front end implemented with polymer web components. Models and data access are also implemented in both languages to provide a good comparison for C# devs like myself to learn F#

这篇关于ASP.NET Core中异步控制器方法的F#语法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆