I am using an API provided by a data vendor to pull data into a C#/WPF application. I have the connections working fine and data is pulling. I put in a check to verify periodically that connection has not been lost and reconnect if that happens. That check gets executed by a timer but it doesn't work for some reason even though it's the same code that gets called and works anywhere else in my application.
I think it has something to do with the fact that there's a singleton instance and the timer is a separate thread. But I'm not sure how to fix it.
This gets called after InitializeComponent
public void OpenConnections()
{
DataServices.Instance.StateChanged += OnStateChanged;
DataServices.Instance.Initialize(AppName);
_timeSeries = DataServices.Instance.TimeSeries;
_timeSeries.ServiceInformationChanged +=
timeSeries_ServiceInformationChanged;
}
The event handlers OnStateChanged and timeSeries_ServiceInformationChanged just update the UI to show the user the connection status.
These 4 lines work fine when called upon startup or where from the UI via a "reconnect" button or anything like that but not via an elapsed timer event, even if I use the lock keyword as such:
private static readonly object padlock = new object();
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
if (DataServices.Instance.State == DataServicesState.Up &&
_timeSeries.ServiceInformation.State == ServiceState.Up)
{
//do nothing, services are up and connected.
}
else
{
lock(padlock)
{
OpenConnections();
}
}
}
EDIT:
Here is the timer code, as requested.
System.Timers.Timer ConnectionCheckerTimer;
private void InitializeConnectionCheckerTimer()
{
ConnectionCheckerTimer = new System.Timers.Timer(5000);
ConnectionCheckerTimer.Elapsed += OnTimedEvent;
ConnectionCheckerTimer.AutoReset = true;
ConnectionCheckerTimer.Enabled = true;
}
And InitializeConnectionCheckerTimer() is called after InitalizeComponent()
EDIT #2 I got it to work. The issue was a threading problem and the API will only connect from the UI thread which created it. I'm not sure why this is, but the way around it is by calling the code we want directly from the UI thread by manually invoking as follows
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
if (DataServices.Instance.State == DataServicesState.Up &&
_timeSeries.ServiceInformation.State == ServiceState.Up)
{
}
else
{
Application.Current.Dispatcher.Invoke(
() =>
{
OpenConnections();
});
}
}