In my web socket wcf service I'm using timer elapsed event to do some logic on my object and after that send information to client (by callback object). I also track callback closed event to clean all object that I'm using in timer elapsed event handler. The problem that i occured is that, when I'm trying to dispose my object i get errors that is still working and to prevent that i try to use lock in both code (timer elapsed event and closed channel event) but it not working correctly (i'm still getting errors that i'm calling method on my object that is no allowed for this moment - this mean that timer elapsed and also call it in the same time).
Is WCF do something special which causes to lock don't work as I expected ?
Here is some of my code:
[ServiceContract(CallbackContract = typeof(IWebSocketsCallback))]
public interface IWebSockets
{
[OperationContract(IsOneWay = true, Action = "*")]
void Start(Message msg);
}
[ServiceContract]
public interface IWebSocketsCallback
{
[OperationContract(IsOneWay = true, Action = "*")]
void SendToClient(Message msg);
}
public class WebSockets : IWebSockets
{
private IWebSocketsCallback callback;
private bool handlePIChanges = false;
private PIDataPipe pipe;
private PIEventsProducer piEventsProducer;
private Timer timer;
private readonly object timerLock = new object();
private readonly object pipeLock = new object();
private bool isPipeClosed = false;
public WebSockets()
{
callback = OperationContext.Current.GetCallbackChannel<IWebSocketsCallback>();
((IChannel)callback).Closed += WebSockets_Closed;
}
public void Start(Message msg)
{
// some custom logic that i ommited ...
timer = CreateTimer();
timer.Elapsed += (sender, e) => PIQueryingCallback(pipe, timer);
}
private void WebSockets_Closed(object sender, EventArgs e)
{
lock (timerLock)
{
handlePIChanges = false;
if (timer != null)
{
timer.Stop();
timer.Dispose();
piEventsProducer.Clear();
}
}
lock (pipeLock)
{
if (pipe != null)
{
pipe.RemoveSignups(pipe.AsReadOnly()); // this cause error, because GetObserverEvents not stopped working
pipe.Close();
isPipeClosed = true;
}
}
}
private void PIQueryingCallback(PIDataPipe pipe, Timer myTimer)
{
bool moreIndicator;
AFErrors<PIPoint> errors;
lock (pipeLock)
{
do
{
if (handlePIChanges && !isPipeClosed)
{
try
{
errors = pipe.GetObserverEvents(2000, out moreIndicator); // this method calls make block for other call on this object untill it return results
}
catch (Exception e)
{
moreIndicator = false;
continue;
}
}
else
{
moreIndicator = false;
}
}
while (moreIndicator);
}
if (handlePIChanges)
{
lock (timerLock)
{
if (handlePIChanges)
{
myTimer.Start();
}
}
}
}
// this method is called after GetObserveEventsCompleted
private void HandlePIDataEventProducerChanges(string msg)
{
if (handlePIChanges && !isPipeClosed)
{
if (((IChannel)callback).State == CommunicationState.Opened)
{
try
{
callback?.SendPIDataChangesToClient(CreateMessage(msg));
}
catch (Exception ex)
{
}
}
}
}
}