I get a Cannot access a disposed object
error when running the following code (MyClient
is a WCF client generate by a service reference in a C# project).
type Action =
| Add
| Update
let addStuff (myClient:MyClient) arg = async {
let! response = myClient.AddAsync arg |> Async.AwaitTask
return response.ID
}
let updateStuff (myClient:MyClient) arg = async {
let! response = myClient.UpdateAsync arg |> Async.AwaitTask
return response.ID
}
let doStuff arg =
use myClient = new MyClient()
match arg.Action with
| Add -> arg |> addStuff myClient
| Update -> arg |> updateStuff myClient
let args = [Add, Add, Update, Add]
let results =
args
|> List.map doStuff
|> Async.Parallel
It seems the client is being disposed before I expect it to. If I change doStuff
to:
let doStuff arg = async {
use myClient = new MyClient()
return!
match arg.Action with
| Add -> arg |> addStuff myClient
| Update -> arg |> updateStuff myClient
}
The return type of both functions is Async<int>
. Why is the client being disposed early in the first example? I would think both examples are logically identical. My understanding is that the async
workflow is only necessary if you need to use the !
bindings which I do not think is necessary in this case as the actual await is happening in the specific functions.
The problem is with doStuff
:
let doStuff arg =
use myClient = new MyClient()
match arg.Action with
| Add -> arg |> addStuff myClient
| Update -> arg |> updateStuff myClient
You are passing myClient
into an async function which captures the MyClient
instance. However, when doStuff
returns it calls Dispose
on the MyClient
instance and disposes the client. When your async method gets around to running it is using a disposed instance.
Making doStuff
works because the dispose becomes part of the async workflow.
Another option would be to not use
the MyClient
instance but instean have addStuff
and updateStuff
create their own MyClient
instance.