I have a windows service project with this code:
protected override void OnStart(string[] args)
{
InitializeScheduler();
var timer = new Timer {Interval = 10 * 60 * 1000};
timer.Elapsed += (ss, ee) => InitializeScheduler();
timer.Start();
}
private void InitializeScheduler()
{
_taskScheduler = new TaskScheduler() { Enabled = true };
// do something
}
in TaskScheduler class:
private Timer _triggerTimer;
public TaskScheduler()
{
_triggerTimer = new Timer(1000);
_triggerTimer.Elapsed += (TriggerTimerTick);
}
When I instance "TaskScheduler" in "InitializeScheduler()", _triggerTimer is not dispose and add another timer. How can I dispose it and restart all things in InitializeScheduler() method?
Try to dispose the timer before creating a new one.
private void InitializeScheduler()
{
if( _taskScheduler != null)
_taskScheduler.Dispose();
_taskScheduler = new TaskScheduler() { Enabled = true };
// do something
}
TaskScheduler class:
private Timer _triggerTimer;
public TaskScheduler()
{
_triggerTimer = new Timer(1000);
_triggerTimer.Elapsed += (TriggerTimerTick);
}
public Dispose()
{
if(_triggerTimer != null){
_triggerTimer.Dispose()
_triggerTimer = null;
}
Related
I have a windows service implemented in C#. The service watches a number of directories for a file to be saved. However to make it more robust I am trying to get it to check the folders after a period of time.
The inner class called a Watcher initialises both the fileSystemWatcher and DispatchTimer.
public class Watcher
{
FileSystemWatcher fileSystemWatcher = null;
public delegate void TimerInvokedHandler(object sender);
public event TimerInvokedHandler TimerInvoked;
public DispatcherTimer Timer { get; set; }
public int TimerMinutes { get; set; }
public Watcher()
{
}
public Watcher(String directory, String filter, String dap)
{
this.DAP = dap;
this.Directory = directory;
this.Filter = filter;
}
public Boolean EnableRaisingTimerEvents
{
get { return this.Timer.IsEnabled; }
set
{
this.Timer.IsEnabled = value;
if (value)
{
this.Timer.Start();
Log("Timer Started");
}
else
{
this.Timer.Stop();
Log("Timer Stopped");
}
}
}
private void Timer_Tick(object sender, EventArgs e)
{
StopWatch();
TimerInvoked?.Invoke(sender);
}
public void StartWatch()
{
if (fileSystemWatcher == null)
{
fileSystemWatcher = new FileSystemWatcher();
fileSystemWatcher.Filter = Filter;
fileSystemWatcher.Path = Directory;
fileSystemWatcher.Created += FileSystemWatcher_Created;
fileSystemWatcher.Renamed += FileSystemWatcher_Renamed;
fileSystemWatcher.Error += FileSystemWatcher_Error;
}
if (this.Timer == null)
{
Log("Initialising Timer");
this.Timer = new DispatcherTimer();
this.Timer.Interval = new TimeSpan(0, this.TimerMinutes, 0);
this.Timer.Tick += Timer_Tick;
}
this.EnableRaisingFileSystemsEvents = true;
this.EnableRaisingTimerEvents = true;
Log(String.Format("Watching Directory {0}", Directory));
}
// stops timer and file system events
public void StopWatch()
{
if (fileSystemWatcher != null)
EnableRaisingFileSystemsEvents = false;
if (Timer != null)
{
EnableRaisingTimerEvents = false;
}
Log(String.Format("Watching {0} Switched Off", this.Directory));
}
private void Log ( String Message )
{
LogEvent?.Invoke(this, Message);
}
}
The outer class creates a list of these watchers, this is based on ServiceBase, as in it is a service and so only ends when it gets a stopped within the Windows Service Manager
foreach (nhs_acquisition_profile pfl in p)
{
Watcher w = null;
String filePattern = String.Empty;
try
{
profileWatcherLog.WriteEntry(String.Format("Attempting to set-up watcher on {0} for DAP {1}",pfl.dap_file_location,pfl.dap_name));
if (pfl.dap_acquisition_method_loca.ToLower() == "xml") w = new Watcher(pfl.dap_file_location, "*.xml", pfl.dap_name);
else w = new Watcher(pfl.dap_file_location, "*.*", pfl.dap_name);
profileWatcherLog.WriteEntry("Initialising Event Handlers");
// initialise event handlers
w.FileCreated += W_FileCreated;
w.FileRenamed += W_FileRenamed;
w.TimerInvoked += W_TimerInvoked;
w.LogEvent += W_LogEvent;
profileWatcherLog.WriteEntry("Event Handlers initialised");
// dispatch timer
w.TimerMinutes = Convert.ToInt32(Properties.Settings.Default.TimerDelay);
w.StartWatch();
profileWatcherLog.WriteEntry("Watch started....Adding to Watcher List");
// add the watcher to the list of watchers
FileWatcherList.Add(w);
profileWatcherLog.WriteEntry("Added to list of file watchers");
profileWatcherLog.WriteEntry(String.Format("Watching {0} for files matching *.* for DAP {1}",pfl.dap_file_location,pfl.dap_name));
}
catch
{
throw;
}
}
The variable FileWatcherList is a field of the ProfileWatcher class which forms the service as a whole.
What I am finding is that the DispatchTimer Tick event never happens. I'm reasonable certain that this is not an instance of the DispatchTimer being disposed of before the Tick, but can't see why it is not firing.
Dmitri is correct, I should have been using a Timer and not a DispatchTimer. Once I moved to that it worked fine.
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 am new to C# and try to create a setInterval and clearInterval function which is exactly working like the same functions in javascript.
I do it mainly for practice and to learn what can be done in C# and what not.
setInterval
Requirements: Create a new timer and return it, also run a anonymous function or a predefined function again and again in the given interval.
Timer setInterval(Func<int> myMethod, int intervalInMs)
{
var timer = new Timer();
timer.Start();
while (true) { //probably a infinite loop
if (timer.ElapsedMilliseconds >= intervalInMs)
{
myMethod();
timer.Restart();
}
}
return timer; //Code does never reach this part obviously because of the while loop
}
clearInterval
Requirements: Stop the timer.
void clearInterval(Timer timer)
{
timer.Stop();
}
Planned Usage
Timer myTimer = setInterval(delegate {
MessageBox.Show(
"test",
"test",
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
return 1;
}, 5000);
//somewhere in code...
clearInterval(myTimer);
How is it possible to solve this with C#, by using Events?
The .Net framework provides at least three different timers - System.Timers.Timer, System.Threading.Timer and System.Windows.Forms.Timer.
The System.Diagnostic.Stopwatch is not a timer and should not be used as one. It only measures how much time have passed between the Start() and Stop().
I would suggest using one of the timers provided by the .Net framework instead of re-inventing the wheel.
update
Well, since you insisted,
Here is a simple implementation NOT FOR USE IN PRODUCTION CODE since it's very easy to create memory leaks with it:
public static class Interval
{
public static System.Timers.Timer Set(System.Action action, int interval)
{
var timer = new System.Timers.Timer(interval);
timer.Elapsed += (s, e) => {
timer.Enabled = false;
action();
timer.Enabled = true;
};
timer.Enabled = true;
return timer;
}
public static void Stop(System.Timers.Timer timer)
{
timer.Stop();
timer.Dispose();
}
}
You can see a live demo on rextester.
I managed to solve it by using events. It is maybe not the best solution, but as I already mentioned, I am a C# beginner.
Example:
This example shows a message box every 5000 ms, after three Messageboxes the interval is changed and at 10 boxes the interval is cleared. You can also stop the interval by pressing the button.
using System;
using System.Windows.Forms;
namespace Intervals
{
public partial class Form1 : Form
{
Interval ival1 = new Interval();
private int _A;
public int A
{
get { return _A; }
set {
_A = value;
if (value == 3) {
if (ival1 != null) {
MessageBox.Show(
"changeInterval Triggered",
A.ToString(),
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
ival1.changeInterval(1000);
}
}
if (value >= 10)
{
if (ival1 != null)
{
MessageBox.Show(
"clearInterval Triggered",
A.ToString(),
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
ival1.clearInterval();
}
}
}
}
public Form1()
{
InitializeComponent();
int interval = 5000;
ival1.setInterval(delegate {
A++;
MessageBox.Show(
A.ToString(),
"A",
MessageBoxButtons.OK,
MessageBoxIcon.Warning
);
}, interval);
}
private void stopInterval_Click(object sender, EventArgs e)
{
ival1.clearInterval();
}
}
}
I created a new class Interval which is needed in order for this program to work.
using System;
namespace Intervals
{
public class Interval
{
private System.Timers.Timer timer;
private Action main;
public Interval()
{
timer = new System.Timers.Timer();
}
public void setInterval(Action pAction, int interval)
{
if (interval <= 0) { interval = 100; }
timer.Interval = interval;
main = new Action(delegate{
timer.Stop();
pAction?.Invoke();
timer.Start();
});
timer.Elapsed += (sender, e) => TimerEventProcessor(sender, e);
timer.Start();
}
public void changeInterval(int interval)
{
timer.Stop();
timer.Interval = interval;
timer.Start();
}
public void clearInterval()
{
main?.EndInvoke(null);
main = delegate
{
timer.Stop();
timer.Dispose();
};
}
public void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
{
main?.Invoke();
}
}
}
Memory Usage Test (260 Minutes):
Timer is working only one time. This service must be work in every 2minutes...
public partial class Service1 : ServiceBase
{
RuleContext entity = new RuleContext();
private int id;
private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
OnTimer();
}
public void OnTimer()
{
Timeout.Infinite);
_timer = new Timer();
_timer.Interval = 2 * 60 * 1000;
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Enabled = true;
_timer.AutoReset = true;
_timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// ignore the time, just compare the date
if (_lastRun.Date <= DateTime.Now.Date)
{
GetRule();
}
}
protected override void OnStop()
{
}
public void GetRule()
{
var query = from ruleset in entity.RuleSets
join rule in entity.Rules on ruleset.Id equals rule.RuleSetId
join schedulerule in entity.Schedules on rule.ScheduleId equals schedulerule.Id
select new
{
Id = ruleset.Id,
daily = schedulerule.Daily,
mountly = schedulerule.Monthly,
dayofMounth = schedulerule.DayOfMonth,
};
foreach (var q in query.ToList())
{
if (q.mountly && q.daily)
{
if (q.dayofMounth == (int)DateTime.Now.Day)
{
UpdateValue(q.Id);
}
}
else if (q.daily)
{
UpdateValue(q.Id);
}
else if (q.mountly)
{
if (q.dayofMounth == (int)DateTime.Now.Day)
{
UpdateValue(q.Id);
}
}
}
}
public void UpdateValue(int id)
{
var ruleSet = entity.RuleSets.First(k => k.Id == id);
ruleSet.RcvByte = 0;
ruleSet.SentByte = 0;
entity.SaveChanges();
}
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// ignore the time, just compare the date
if (_lastRun.Date <= DateTime.Now.Date)
{
GetRule();
}
}
Since the AutoReset property is set to true, no need to Stop and Start timer.
_timer.Stop();
this line is causing this problem. Remove it
I've been trying to implement a windows service that would keep vpn connection alive. I've found that it is possible to achieve using DotRas library by subscribing to RasConnectionWatcher.Disconnected event:
public class SampleService {
public SampleService() {
this.shutdownEvent = new ManualResetEvent(false);
this.connectionWatcher = new RasConnectionWatcher();
this.connectionWatcher.Disconnected += onVpnDisconnected;
}
// redial
void onVpnDisconnected(Object sender, RasConnectionEventArgs e) {
this.DialUp();
}
void DialUp() {
// connection setup is omitted
// keep the handle of the connection
this.connectionWatcher.Handle = dialer.Dial();
}
public void Start() {
this.thread = new Thread(WorkerThreadFunc);
this.thread.IsBackground = true;
this.thread.Start();
}
public void Stop() {
this.shutdownEvent.Set();
if(!this.thread.Join(3000)) this.thread.Abort();
}
private void WorkerThreadFunc() {
this.DialUp();
while(!this.shutdownEvent.WaitOne(0)) Thread.Sleep(1000);
}
}
When I start the service vpn connection opens without any problem, but when I manually interrupt the connection it seems that Disconnected event doesn't fire up.
solution 1
Found similar question/answer here:
http://social.msdn.microsoft.com/Forums/en-US/56ab2d0d-2425-4d76-81fc-04a1e1136141/ras-connection-application-and-service?forum=netfxnetcom.
solution 2
Got an answer from Jeff Winn yesterday:
https://dotras.codeplex.com/discussions/547038
public class VpnKeeperService : IService {
private ManualResetEvent shutdownEvent;
private RasConnectionWatcher connWatcher;
private Thread thread;
public VpnKeeperService() {
this.shutdownEvent = new ManualResetEvent(false);
this.connWatcher = new RasConnectionWatcher();
this.connWatcher.EnableRaisingEvents = true;
this.connWatcher.Disconnected += (s, args) => { this.DialUp(); };
}
Boolean DialUp() {
try {
using(var phoneBook = new RasPhoneBook()) {
var name = VpnConfig.GetConfig().ConnectionName;
var user = VpnConfig.GetConfig().Username;
var pass = VpnConfig.GetConfig().Password;
var pbPath = VpnConfig.GetConfig().PhoneBookPath;
phoneBook.Open(pbPath);
var entry = phoneBook.Entries.FirstOrDefault(e => e.Name.Equals(name));
if(entry != null) {
using(var dialer = new RasDialer()) {
dialer.EntryName = name;
dialer.Credentials = new NetworkCredential(user, pass);
dialer.PhoneBookPath = pbPath;
dialer.Dial();
}
}
else throw new ArgumentException(
message: "entry wasn't found: " + name,
paramName: "entry"
);
}
return true;
}
catch {
// log the exception
return false;
}
}
public void Start() {
this.thread = new Thread(WorkerThreadFunc);
this.thread.Name = "vpn keeper";
this.thread.IsBackground = true;
this.thread.Start();
}
public void Stop() {
this.shutdownEvent.Set();
if(!this.thread.Join(3000)) {
this.thread.Abort();
}
}
private void WorkerThreadFunc() {
if(this.DialUp()) {
while(!this.shutdownEvent.WaitOne(0)) {
Thread.Sleep(1000);
}
}
}
}
Hope it helps someone.