I have this class
public class ResetClock
{
public delegate void ResetFunc();
private ResetFunc m_ResetFunc;
private event ResetFunc Reseted;
private Timer m_Timer;
public ResetClock(int second)
{
double r = second * 1000;
m_Timer = new Timer(r);
m_Timer.AutoReset = false;
m_Timer.Elapsed += new ElapsedEventHandler(onTimerTick);
Reset();
}
public void SetResetMethod(ResetFunc method)
{
m_ResetFunc = method;
}
public void Terminate()
{
m_Timer.Stop();
m_Timer.Dispose();
m_Timer = null;
}
private void onTimerTick(object sender, ElapsedEventArgs e)
{
if (m_ResetFunc == null)
{
if (Reseted != null) Reseted();
}
else
{
m_ResetFunc();
}
Reset();
}
#region Public
public void Reset()
{
m_Timer.Reset();
}
#endregion
}
internal static class TimerEx{
public static void Reset(this Timer timer){
timer.Stop();
timer.Start();
}
}
My application is showing the reset page when this class reaches the seconds defined in the contractor. when a Reset() method calls, the Timer should reset the it self and begin the timer from 0.
for some reason after the application is running few days the reset event is firing after few seconds and not the number of seconds that i defined in the first application initialization
does anyone have any idea....??? I braking my head through the wall to find the answer..
Related
Hello I have a Blazor server app where some PLC variables are read from a remote production machine.
The code part that is connecting to the PLC and reading the datas is in a sourced service (PLCService.cs). The service is injected and called in a razor page.
If I trigger the reading manualy with a button, all the variables are read correctly. So far no problem. But I want that the variables are read every second from the remote machine's PLC. Therefore I have programmed a timer in the codebehind page of my razor page (not in the service), but the timer is not working. (The values are note read even once)
In the razor page there are also the variables that I read from the PLC, but for making it leaner I have just shown the counter value, that should count each second.
In my razor file:
#inject PLCService PLCService
<button #onclick="Read_CNC_Status">Read PLC Data</button>
<l>#counter_timer</l> // Unfortunately the counter value is always "0"
In my razor.cs file:
using System.Timers;
public partial class Read_PLC_Data
{
public int counter_timer=0;
System.Timers.Timer timer1 = new System.Timers.Timer();
public async void Read_CNC_Status()
{
PLCService.Connect_PLC(); // Connection code is in a sourced service
Initialise_Timer1();
}
public void Initialise_Timer1()
{
timer1.Elapsed += new ElapsedEventHandler(OnTimedEvent1);
timer1.Interval = 1000;
timer1.Enabled = true;
counter_timer = 0;
}
public void OnTimedEvent1(object source, ElapsedEventArgs e)
{
PLCService.Read_PLC_Data();
counter_CNC_status += 1; // This counter is not counting !!!
if(counter_timer >= 30)
{
counter_timer = 0;
timer1.Enabled = false;
}
StateHasChanged();
}
}
Try the periodic timer:
private readonly PeriodicTimer _periodicTimer = new(TimeSpan.FromSeconds(5));
public async void OnGet()
{
while(await _periodicTimer.WaitForNextTickAsync())
{
await ConnectPlc();
}
}
UPDATE 1
If you want to go with your approach you should use InvokeAsync(StateHasChanged) because Blazor would not recognize the state change and not refresh the UI
<h3>#_currentCount</h3>
#code {
private int _currentCount;
private System.Timers.Timer _timer;
protected override void OnInitialized()
{
_timer = new();
_timer.Interval = 1000;
_timer.Elapsed += async (object? sender, ElapsedEventArgs e) =>
{
_currentCount++;
await InvokeAsync(StateHasChanged);
};
_timer.Enabled = true;
}
}
Don't forget to invoke the StateHasChanged method
UPDATE 2
If you want to use the periodic timer that i initially suggest, you can use it this way:
First let's assume that you have a class that is responsible for PLC data and implements the INotifyPropertyChanged interface:
public class PlcData : INotifyPropertyChanged
{
private readonly ILogger<PlcData> _logger;
public event PropertyChangedEventHandler? PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private int _counter;
public int Counter
{
get { return _counter; }
set
{
if (_counter != value)
{
_counter = value;
NotifyPropertyChanged(nameof(Counter));
}
}
}
public PlcData(ILogger<PlcData> logger)
{
_logger = logger;
}
public async Task GetFromPlcAsync()
{
_logger.LogInformation("Get new info: {c}", ++Counter);
await Task.CompletedTask;
}
}
Then Create a background service
public class PlcService : BackgroundService
{
private readonly PlcData _plc;
private readonly PeriodicTimer _timer;
public PlcService(PlcData plc)
{
_plc = plc;
_timer = new(TimeSpan.FromSeconds(1));
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while(await _timer.WaitForNextTickAsync(stoppingToken)
&& !stoppingToken.IsCancellationRequested)
{
await _plc.GetFromPlcAsync();
}
}
}
In razor page your need to inject the PlcData
#inject PlcData plcData
<h3>#_currentCount</h3>
#code {
private static int _currentCount;
protected override void OnInitialized()
{
plcData.PropertyChanged += OnIncrement;
}
private async void OnIncrement(object? sender, PropertyChangedEventArgs e)
{
_currentCount = plcData.Counter;
await InvokeAsync(() =>
{
StateHasChanged();
});
}
}
Also you need to add services to the container.
builder.Services.AddHostedService<PlcService>();
...
...
builder.Services.AddSingleton<PlcData>();
Here is a typical Program.cs from .net6 Blazor-Server And that's it!
UPDATE 3
Using System.Threading
#page "/"
#using System.Threading;
<h3>#_currentCount</h3>
#code {
private int _currentCount;
protected override void OnInitialized()
{
var timer = new Timer(new TimerCallback(_ =>
{
_currentCount++;
InvokeAsync(() =>
{
StateHasChanged();
});
}), null, 1000, 1000);
}
}
I don't see where you are calling the Read_CNC_Status() method. If you don't call it, then nothing you wrote about the timer is ever executed. You can call it in the component's OnAfterRender function (or in the constructor of your partial class).
protected override void OnAfterRender(bool firstRender)
{
if (firstRender)
{
Read_CNC_Status();
}
base.OnAfterRender(firstRender);
}
I ran the rest of the code and it works.
EDIT: It's not necessary, but I also recommend that you make sure the handler is not called again before the previous execution is finished (this could happen for example if Read_PLC_Data() is slow and takes more than the timer's Interval to complete). To do that, you can set the AutoReset property of your timer to false and manually restart the timer each time at the end of your handler, like this:
public async void Read_CNC_Status()
{
PLCService.Connect_PLC(); // Connection code is in a sourced service
Initialise_Timer1();
}
public void Initialise_Timer1()
{
timer1.Elapsed += new ElapsedEventHandler(OnTimedEvent1);
timer1.Interval = 1000;
timer1.AutoReset = false;
counter_CNC_status = 0;
timer1.Start();
}
public void OnTimedEvent1(object source, ElapsedEventArgs e)
{
try
{
PLCService.Read_PLC_Data();
counter_CNC_status += 1; // This counter is not counting !!!
}
finally
{
if(counter_CNC_status >= 30)
{
counter_CNC_status = 0;
timer1.Enabled = false;
}
else
{
timer1.Start();
}
}
StateHasChanged();
}
The best approach for me is to use QUARTZ.NET
Recently, I am learning unit test and try to use this skill in my project.
However, I have some question about how to test following code.
public class Class1
{
private Timer _timer = new Timer();
public Class1()
{
_timer.Interval = 1000;
_timer.Elapsed += _timer_Elapsed;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
//some works
}
public void start()
{
_timer.Start();
//some works
}
public void stop()
{
_timer.Stop();
//some works
}
}
I truly don't know how to test this class without breaking its encapsulation.
Should I expose '_timer_Elapsed' method? Evan if do so, next question comes to how to test method 'start' and 'stop'. Should I use stub object to substitute the Timer in order to test this class? if that, this class will be too complex because I need to make an interface and make a class which encapsulates Timer and implement the interface above.
public interface IEncal
{
double Interval { get; set; }
event ElapsedEventHandler Elapsed;
void Stop();
void Start();
}
public class MyClass : IEncal
{
Timer timer = new Timer();
public double Interval { get { return timer.Interval; } set { timer.Interval = value; } }
public event ElapsedEventHandler Elapsed
{
add { timer.Elapsed += value; }
remove { timer.Elapsed -= value; }
}
public void Start()
{
timer.Start();
}
public void Stop()
{
timer.Stop();
}
}
public class Class1
{
private IEncal _timer;
public Class1(IEncal timer)
{
_timer = timer;
_timer.Interval = 1000;
_timer.Elapsed += _timer_Elapsed;
}
public void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
//some works
}
public void start()
{
_timer.Start();
//some works
}
public void stop()
{
_timer.Stop();
//some works
}
}
Is there any better way to test this class?
The following is the real code I use.
I've written the unit test for ISender class and IInfoProducer class.
Since it's my first time to use unit test, I would like to think about each class for learning.
Back to the question, this class is basically a Timer class. When elapsing ,
it sends a info. So how should I test this timing sending process?
public class InfomationSender
{
private readonly Timer _timer = new Timer();
private readonly ISender _sender;
private readonly IInfoProducer _producer;
public InfomationSender(ISender sender, IInfoProducer producer)
{
_sender = sender;
_producer = producer;
_timer.Interval = 1000;
_timer.Elapsed += _timer_Elapsed;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
var info = _producer.getInfo();
_sender.send(info);
}
public void start()
{
_timer.Start();
}
public void stop()
{
_timer.Stop();
_sender.Dispose();
}
}
You should be able test the class without mocking. Less mocking more valuable tests are.
But you didn't provide information about what your code is doing in // some works areas. Because this is what you want to test, timer is just implementation details.
For testing "some works" class should provide some public access to the result of "some works" or result will be "exposed" through injected dependency (repository, logger etc)
Assume class will execute "some work" every second and update Result property after Stop method is called.
public class LiveCalculator
{
private readonly Timer _timer;
private List<int> _allValues
private int _lastSum;
public int LastSum => _lastSum;
public LiveCalculator()
{
_allValues = new List<int>();
_timer = new Timer { Interval = 1000 };
_timer.Elapsed += _timer_Elapsed;
}
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
_allValues.Add(42);
}
public void start()
{
_timer.Start();
}
public void stop()
{
_timer.Stop();
_lastResult = _allValues.Sum();
}
}
Tests
[Fact]
public async Task AfterFiveSeconds_LastResultEquals210()
{
var calculator = new LiveCalculator();
calculator.Start();
await Task.Delay(5100);
calculator.Stop();
calculator.LastResult.Should().Be(210);
}
I have WinForms App where I am using the code in this following Post to check the InActivity Status of my app (Please see the accepted answer in the post). InActivity In WinForms. Once the app reaches inactivity its stopping the inactivity monitor. But then I want to restart the time once the user logs in.
So I have a notification mechanism when the user logs in and I am calling the start timer method again. I get the Started Monitor Message but the app never tracks inactivity and I don't get Timer reporting app is InACTIVE message at all. Please help.
public static System.Windows.Forms.Timer IdleTimer =null;
static int MilliSeconds = 60000;
static void Main(string[] args)
{
f = new GeneStudyForm(true, arguments.SystemTimeOutFolder, arguments.SystemTimeOutFile, StartInActivityMonitor);
int x = StartInActivityMonitor();
}
public static void StartInActivityMonitor()
{
IdleTimer = new Timer();
LeaveIdleMessageFilter limf = new LeaveIdleMessageFilter();
Application.AddMessageFilter(limf);
IdleTimer.Interval = MilliSeconds; //One minute; change as needed
Application.Idle += new EventHandler(Application_Idle);
if (IdleTimer != null)
{
MessageBox.Show(IdleTimer.Interval.ToString());
}
IdleTimer.Tick += TimeDone;
IdleTimer.Tag = InActivityTimer.Started;
MessageBox.Show("starting");
IdleTimer.Start();
}
static private void Application_Idle(object sender, EventArgs e)
{
if (!IdleTimer.Enabled) // not yet idling?
IdleTimer.Start();
}
static private void TimeDone(object sender, EventArgs e)
{
try
{
MessageBox.Show("Stopped");
IdleTimer.Stop(); // not really necessary
f.MonitorDirectory();
f.UpdateInActivityStatus();
IdleTimer.Tick -= TimeDone;
Application.Idle -= new EventHandler(Application_Idle);
}
catch(Exception ex)
{
MessageBox.Show(ex.InnerException + ex.Data.ToString());
}
}
Here is my GeneStudyForm
public partial class GeneStudyForm
{
GeneStudySystemTimeOutIO GeneStudyIO;
Func<int> StartTimer;
//Passing the StartInActivityMonitor Method as Func Delegate
public GeneStudyForm(bool isStandalone, string TimeOutFolder, string TimeOutFile, System.Func<int> MyMethod)
{
GeneStudyIO = GeneStudySystemTimeOutIO.GetInstance(TimeOutFolder, TimeOutFile);
UpdateActivityStatus(AppName.GeneStudyStatus, ActivityStatus.Active);
this.StartTimer = MyMethod;
}
public void UpdateActivityStatus(AppName name, ActivityStatus status)
{
if (GeneStudyIO != null)
{
GeneStudyIO.WriteToFile(name, status);
}
}
public void MonitorDirectory()
{
FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(GeneStudyIO.GetDriectory());
fileSystemWatcher.NotifyFilter = NotifyFilters.LastWrite;
fileSystemWatcher.Filter = "*.json";
fileSystemWatcher.Changed += FileSystemWatcher_Changed;
fileSystemWatcher.EnableRaisingEvents = true;
}
public void UnRegister(FileSystemWatcher fileSystemWatcher)
{
fileSystemWatcher.Changed -= FileSystemWatcher_Changed;
}
// I am writing the inactive status to a file. So this event will fill
private void FileSystemWatcher_Changed(object sender, FileSystemEventArgs e)
{
try
{
var root = GeneStudyIO.GetDesrializedJson();
if (root != null && root.AllApplications != null)
{
var item = root.AllApplications.Any(x => x.Status == ActivityStatus.Active.ToString());
if (!item)
{
if (InActivecount == 0)
{
GeneStudyAndApplicationCommon.TimeStatus = InActivityTimer.Ended;
MessageBox.Show("I am hiding");
this.Hide();
InActivecount++;
}
}
else
{
if (GeneStudyAndApplicationCommon.TimeStatus == InActivityTimer.Ended)
{
MessageBox.Show("I am showing");
this.Show();
UnRegister(sender as FileSystemWatcher);
UpdateActivityStatus(AppName.GeneStudyStatus, ActivityStatus.Active);
MessageBox.Show("Updated Status");
if (StartTimer != null)
{
MessageBox.Show("Starting Timer again");
if (StartTimer() == -1)
{
MessageBox.Show("Couldn't start timer");
}
}
}
}
}
}
catch (Exception ex)
{
SystemDebugLogLogger.LogException(ex);
}
}
}
This soulution is quite different from what I have posted. But I could solve my problem with this. But I want to post it if it helps someone. Here is the post I am following Last User Input
I created a class called IdleCheck where I am getting LastUserInput as follows
public static class IdleCheck
{
[StructLayout(LayoutKind.Sequential)]
private struct LASTINPUTINFO
{
[MarshalAs(UnmanagedType.U4)]
public int cbSize;
[MarshalAs(UnmanagedType.U4)]
public int dwTime;
}
[DllImport("user32.dll")]
private static extern bool GetLastInputInfo(ref LASTINPUTINFO x);
public static int GetLastInputTime()
{
var inf = new LASTINPUTINFO();
inf.cbSize = Marshal.SizeOf(inf);
inf.dwTime = 0;
return (GetLastInputInfo(ref inf)) ? Environment.TickCount - inf.dwTime : 0;
}
}
Next in the actual Form this is my code. I am using a simple yes no message box to see if the timer can be stopped and recalled again when needed. You can apply your own locking mechanism.
I want the app to time out if it is InActive for 20 seconds. Change it as needed.
public partial class Form1 : Form
{
Timer timer;
const int TIMEOUT_DONE = 20000;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Reset();
}
void timer_Tick(object sender, EventArgs e)
{
//var ms = TIMEOUT_DONE - IdleCheck.GetLastInputTime();
if (IdleCheck.GetLastInputTime() > TIMEOUT_DONE)
{
DialogResult dialogResult = MessageBox.Show("Sure", "Some Title", MessageBoxButtons.YesNo);
if (dialogResult == DialogResult.Yes)
{
Stop();
Reset();
}
}
}
public void Reset()
{
timer = new Timer();
timer.Interval = 10000;
timer.Tick += timer_Tick;
timer.Start();
}
public void Stop()
{
timer.Tick -= timer_Tick;
timer.Stop();
}
}
I have implemented a SqlListener class that uses SqlDependency to wait for changes in SQL database. At one point in my business workflow I need to wait for a record turning up in the database. The SqlListener triggers an event when requested record is found. This works fine. I can make it work by entering a While-loop and wait until I detect the event being returned. But this is not ideal design. It makes the processor spin a lot in vain.
I would like to wait for the event in a more intelligent manner. I read a lot of suggestions on using Task, NotificationDelegate, ManualResetEvent, etc. .... but I was not able to get it all together.
A simplified example will probably make it easier to understand. This is my current setup that works. But if possible I would like to get rid of the ugly while loop.
private const int MaxWaitTime = 5;
private SqlListener<RecordType> _recordListener;
private RecordType _record;
/// <summary>
/// Request a record and wait until it is found.
/// </summary>
public RecordType GetRecordAwait(int requestedId)
{
// Initiate listening for record
_recordListener = new SqlListener<RecordType>();
_recordListener.SqlModified += SqlListener_SqlModified;
_recordListener.StartListening(requestedId);
// Wait until record is found
var startTime = DateTime.Now;
while (_record == null &&
DateTime.Now.Subtract(startTime).TotalSeconds < MaxWaitTime)
{
Thread.Sleep(1);
}
// Stop listening
_recordListener.SqlModified -= SqlListener_SqlModified;
_recordListener.Dispose();
_recordListener = null;
// Return record
return _record;
}
private void SqlListener_SqlModified(object sender, SqlModifiedArgs args)
{
_record = (RecordType)args.Record;
}
Instead of using While, you could go with Timer and events. Something like:
public class ListenerWaiting
{
public ListenerWaiting(int waitingTimeSeconds)
{
_waitSeconds = waitingTimeSeconds;
}
private int _waitSeconds;
private System.Timers.Timer _timer;
private Listener _listener;
public event EventHandler<string> ListenerDone;
public void Listen(int listeningPeriodSeconds)
{
_listener = new Listener(listeningPeriodSeconds * 1000);
_listener.ListenerCompleted += ListenerListenerCompleted;
_timer = new System.Timers.Timer(_waitSeconds * 1000) {Enabled = true};
_timer.Elapsed += TimerElapsed;
}
void ListenerListenerCompleted(object sender, string e)
{
StopTimer();
StopListener();
if (ListenerDone != null)
ListenerDone(this, "Waiting success! Message was: " + e);
}
void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
StopTimer();
StopListener();
if (ListenerDone != null)
ListenerDone(this, "Waited longer than set, aborted waiting...");
}
private void StopTimer()
{
_timer.Stop();
_timer.Elapsed -= TimerElapsed;
_timer = null;
}
private void StopListener()
{
_listener.ListenerCompleted -= ListenerListenerCompleted;
_listener = null;
}
}
public class Listener
{
private System.Timers.Timer _timer;
private string _listeningPeriodSeconds;
public event EventHandler<string> ListenerCompleted;
public Listener(int listeningPeriodSeconds)
{
_listeningPeriodSeconds = listeningPeriodSeconds.ToString();
_timer = new System.Timers.Timer(listeningPeriodSeconds) { Enabled = true };
_timer.Elapsed += TimerElapsed;
}
private void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_timer.Elapsed -= TimerElapsed;
_timer = null;
if (ListenerCompleted != null)
ListenerCompleted(this, _listeningPeriodSeconds);
}
}
...and then consume it with:
static void Main(string[] args)
{
var wait = new ListenerWaiting(5);
wait.ListenerDone += WaitListenerDone;
wait.Listen(3);
Console.ReadLine();
}
static void WaitListenerDone(object sender, string e)
{
Console.WriteLine(e);
}
I guess I could find better names for classes, but you'll get the idea ;)
In fact the solution was more simple than I first thought. When I rephrased my question and searched again I found it. The ManualResetEvent as mentioned already in my question turned out to be the simplest way to solve it.
All I had to do was to add a ManualResetEvent and set it to wait ;-)
private const int MaxWaitTime = 5000;
private SqlListener<RecordType> _recordListener;
private RecordType _record;
private readonly ManualResetEvent _recordWaiter = new ManualResetEvent(false);
/// <summary>
/// Request a record and wait until it is found.
/// </summary>
public RecordType GetRecordAwait(int requestedId)
{
// Initiate listening for record
_recordListener = new SqlListener<RecordType>();
_recordListener.SqlModified += SqlListener_SqlModified;
_recordListener.StartListening(requestedId);
// Wait synchronously until record is found
_recordWaiter.WaitOne(MaxWaitTime);
// Stop listening
_recordListener.SqlModified -= SqlListener_SqlModified;
_recordListener.Dispose();
_recordListener = null;
// Return record
return _record;
}
private void SqlListener_SqlModified(object sender, SqlModifiedArgs args)
{
_record = (RecordType)args.Record;
_recordWaiter.Set();
}
I've got a custom cache dependency
class MyCacheDependency : CacheDependency
{
private const int PoolInterval = 5000;
private readonly Timer _timer;
private readonly string _readedContent;
public MyCacheDependency()
{
_timer = new Timer(CheckDependencyCallback, this, PoolInterval, PoolInterval);
_readedContent = ReadContentFromFile();
}
private void CheckDependencyCallback(object sender)
{
lock (_timer)
{
if (_readedContent != ReadContentFromFile())
{
NotifyDependencyChanged(sender, EventArgs.Empty);
}
}
}
private static string ReadContentFromFile()
{
return File.ReadAllText(#"C:\file.txt");
}
protected override void DependencyDispose()
{
if (_timer != null) _timer.Dispose();
base.DependencyDispose();
}
}
It works perfectly, but Im wondering how to make a refresh of all the object in one time. Here I put into cache 2 objects
Cache.Insert("c1", "var1", new MyCacheDependency());
Cache.Insert("c2", "vae2", new MyCacheDependency());
Its fine, but when c1 will detect change how to force c2 to don't wait 5 seconds to check but I want to call itself DependencyDispose when c1 do it.
In other words, if c1 detects change, c2 also should call DependencyDispose
Maybe you could add a static event which would be fired in your CheckDependencyCallback()-method. In your constructor for the MyCacheDependency you would then attach an eventhandler. When the event is fired you could call NotifyDependencyChanged or DependencyDispose from there. In this way all MyCacheDependency-objects would react to a change.
class MyCacheDependency : CacheDependency
{
private const int PoolInterval = 5000;
private readonly Timer _timer;
private readonly string _readedContent;
public static event EventHandler MyEvent;
public MyCacheDependency()
{
_timer = new Timer(CheckDependencyCallback, this, PoolInterval, PoolInterval);
_readedContent = ReadContentFromFile();
MyEvent += new EventHandler(MyEventHandler);
}
protected void MyEventHandler(object sender, EventArgs e) {
NotifyDependencyChanged(sender, e);
}
private void CheckDependencyCallback(object sender)
{
lock (_timer)
{
if (_readedContent != ReadContentFromFile())
{
if(MyEvent!=null)
MyEvent(sender, EventArgs.Empty);
}
}
}
private static string ReadContentFromFile()
{
return File.ReadAllText(#"C:\file.txt");
}
protected override void DependencyDispose()
{
if (_timer != null) _timer.Dispose();
base.DependencyDispose();
}
}