How to call WriteBytesAsync in a loop

60 views Asked by At

I need a flavor of htmlView that accepts an XmlNode list instead of an XmlNode.

I tried to writing the code 3 different ways and I got 3 different compile-time errors. Here's my latest attempt:

let htmlViews (htmlNodes : XmlNode list)(_ : HttpFunc) (ctx: HttpContext) : HttpFuncResult =
    task {
        let bytesList = List.map RenderView.AsBytes.htmlDocument htmlNodes
        ctx.SetContentType "text/html; charset=utf-8"
        let mutable ctx = Some(ctx)
        // for bytes in bytesList do
        for bytes in bytesList do
            match ctx with
                | Some(x) -> let! newCtx = x.WriteBytesAsync bytes; ctx <- newCtx
                | None -> ()
        return ctx
    }

This code fails to compile with the error:

No overloads match for method 'Bind'.Known types of arguments: unit * ('a -> TaskCode<'b,unit>)Available overloads: - member TaskBuilderBase.Bind: computation: Async<'TResult1> * continuation: ('TResult1 -> TaskCode<'TOverall,'TResult2>) -> TaskCode<'TOverall,'TResult2> // Argument 'computation' doesn't match - member TaskBuilderBase.Bind: task: Threading.Tasks.Task<'TResult1> * continuation: ('TResult1 -> TaskCode<'TOverall,'TResult2>) -> TaskCode<'TOverall,'TResult2> // Argument 'task' doesn't match - member TaskBuilderBase.Bind: task: ^TaskLike * continuation: ('TResult1 -> TaskCode<'TOverall,'TResult2>) -> TaskCode<'TOverall,'TResult2> when ^TaskLike: (member GetAwaiter: unit -> ^Awaiter) and ^Awaiter :> Runtime.CompilerServices.ICriticalNotifyCompletion and ^Awaiter: (member get_IsCompleted: unit -> bool) and ^Awaiter: (member GetResult: unit -> 'TResult1) // Argument 'task' doesn't match

I can't make sense of that error message, and I'm lost in the details of async and options.

Full code is here: https://github.com/surferjeff/blazor-compared/blob/c8000ef5855a9ba52463abe2ff1ddd5a1467ecc9/GiraffeApp/Program.fs#L26

1

There are 1 answers

0
Brian Berns On BEST ANSWER

I think the use of let! with a semicolon is confusing the compiler, although I'm not sure why. It might be related to this open issue: usage of semicolon in computation expression valid, but not on a single line?.

Whatever the cause, it's easy to work around. If you write the two expressions on separate lines instead, the compiler error goes away:

            match ctx with
                | Some(x) ->
                    let! newCtx = x.WriteBytesAsync bytes
                    ctx <- newCtx
                | None -> ()

If you really want them on the same line, you can use in instead of a semicolon:

            match ctx with
                | Some(x) ->
                    let! newCtx = x.WriteBytesAsync bytes in ctx <- newCtx
                | None -> ()