Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# Async Dispose

I wrote this little web listener simulation:

Agent.Start(fun (_ : MailboxProcessor<unit>) ->
        let listener = new HttpListener()
        listener.Prefixes.Add(addr)
        listener.Start()

        let rec respondOut() = async {
                let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
                use s = context.Response.OutputStream
                let wr = new StreamWriter(s)
                use disp = { new IDisposable with
                                member x.Dispose() =
                                    printfn "Disposing..."
                                    wr.Dispose() }
                wr.Write("Test")
                return! respondOut()
            }

        respondOut()
    )

I don't understand why Dispose is not called on disp on every loop?

As a side question, I'm doing all this because I want to test what is the proper behavior to respond text in a web service. I'm not sure if I should be doing:

use s = Context.Response.OutputStream
use sw = new StreamWriter(s)
    sw.Write("test")

or

Context.Response.Write("Test")
Context.Response.End()

or whatnot.

Thanks!

like image 465
David Grenier Avatar asked Feb 18 '26 02:02

David Grenier


1 Answers

When in doubt, use reflector :). The use keyword create the scope of "using" till then end of the block. When used inside the async workflow if you de-sugar the async keyword you will get something like:

Async.Bind(Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
           (fun context ->
                use s = context.Response.OutputStream
                let wr = new StreamWriter(s)
                use disp = { new IDisposable with
                                member x.Dispose() =
                                    printfn "Disposing..."
                                    wr.Dispose() }
                wr.Write("Test")
                Async.ReturnFrom ( respondOut() )
                )

Now the call Async.ReturnFrom at last will continue calling the function recursively and if you replace the use with " C# using() { } " where the } bracket is after the Async.ReturnFrom then the dispose will never get called

Wrapping the use part in a do block should solve the problem:

let rec respondOut() = async {
                let! context = Async.FromBeginEnd(listener.BeginGetContext, listener.EndGetContext)
                do 
                    use s = context.Response.OutputStream
                    let wr = new StreamWriter(s)
                    use disp = { new IDisposable with
                                    member x.Dispose() =
                                        printfn "Disposing..."
                                        wr.Dispose() }
                    wr.Write("Test")
                return! respondOut()
            }
like image 187
Ankur Avatar answered Feb 20 '26 07:02

Ankur



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!