Reputation: 125
We have a Client class which extends a BaseClass.
The BaseClass has this methods:
protected void Proxy()
{
Error = null;
_proxy = new WebServiceClient<T>(_fullURL);
Error = _proxy.Error;
}
protected virtual void Cleanup()
{
if (_proxy != null)
{
_proxy.Dispose();
_proxy = null;
}
}
And the Client contains several operations that are being called in parallel. Client is not a Singleton, we generate one instance every time.
The operations are like:
public void OperationAsync(Action<BaseResult> callback)
{
TaskCompletionSource<String> taskSrc = new TaskCompletionSource<String>();
Task<String> tsk = taskSrc.Task;
try
{
Proxy();
ThreadPool.QueueUserWorkItem(t =>
{
try
{
String result = _proxy.Channel.ExecuteOperation(SecurityToken());
taskSrc.SetResult(result);
}
catch (Exception ex)
{
taskSrc.SetException(ex);
}
});
tsk.Wait();
BaseResult r = new BaseResult();
r.Value = tsk.Result;
r.Error = tsk.Exception;
Cleanup();
if (callback != null)
{
callback(r);
}
}
catch (Exception ex)
{
FileManager.Log(ex);
}
}
As you can see, each operation calls the Proxy and CleanUp operations.
We did not discover any pattern of behavior yet, but sometimes (maybe once a day) we see this error in the log file:
One or more errors occurred.. InnerException: System.ObjectDisposedException: Cannot access a disposed object. Object name: 'System.ServiceModel.Channels.ServiceChannel'.
It doesn´t happen on any specific operation. It varies all times. I believe that the Proxy needs to be done during the constructor and the CleanUp during the dispose, but it implies to change several things and I want to be sure.
I would really appreciate any idea on how can improve it.
Upvotes: 1
Views: 726
Reputation: 117084
Since you original code was calling tsk.Wait();
you were blocking the calling thread while you run your proxy code on a background thread. There's no benefit and likely increased overhead doing it like this.
So, here's how to prevent the race condition:
public void OperationAsync(Action<BaseResult> callback)
{
try
{
var r = new BaseResult();
using (var proxy = new WebServiceClient<T>(_fullURL))
{
try
{
r.Value = proxy.Channel.ExecuteOperation(SecurityToken());
}
catch (Exception ex)
{
r.Error = ex;
}
}
if (callback != null)
{
callback(r);
}
}
catch (Exception ex)
{
FileManager.Log(ex);
}
}
Upvotes: 1