Use windows service to run a method every on second - c#

Hi I wrote a method in my program which call a Rest Api and get some information.
I want to call every minute. I fill OnStart and OnStop and all timer_Elapsed in which my method is there. I install my service and start it but It just run just for the first time and never repeat again would if anyone know the solution help me. In advanced I thanked you
On start :
protected override void OnStart(string[] args)
{
///just for log to show program is working
ayandehBLL.Save_Log("Service started...", nameof(OnStart));
if (timer == null)
{
timer = new Timer();
timer.AutoReset = true;
timer.Interval = 3000; //*
Convert.ToDouble(ConfigurationManager.AppSettings["IntervalMinutes"]);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
}
protected override void OnStop()
{
timer.Stop();
timer.Enabled = false;
ayandehBLL.Save_Log("Service stoped", nameof(OnStop));
//WriteErrorLog("Test window service Stoped");
}
-----------------------------
private void timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
var a = ayandehBLL.GetProductCode();
ayandehBLL.Save_Log($"Request national code is {a}", "test");
if (a != null)
{
Request_DOM request = new Request_DOM();
request.ProductCode= a;
try
{
var result = ayandehBLL.GetMyProductInfo(request);
if (result != null)
{
ayandehBLL.Save_Log(JsonConvert.SerializeObject(result), nameof(OnStart));
}
else
{
ayandehBLL.Save_Log("GetMyProductInfo() returned null", nameof(OnStart));
}
}
catch (Exception ex)
{
ayandehBLL.Save_Log(ex.Message.ToString(), "OnElapsedTime");
}
}
else
{
ayandehBLL.Save_Log("Request national code is null", "OnElapsedTime");
}
//WriteErrorLog("OnElapsedTime done");
}

The method triggered by a timer is being timed and run in a separate thread. If your main thread reaches the program end, the program will stop and the timer is discontinued. Therefore you have to capture the main thread before the end of the program in a loop where the program won't end until you want it to do so.

Related

Threading-Having difficulty. What am I doing wrong?

I've created a thread (or I'm trying to) which will autosave every so many minutes. Whenever I click the button to start the thread, the program doesn't autosave as instructed. So I'm reaching out for help. Here's the code:
private Thread saver;
...
saver.SetApartmentState(System.Threading.ApartmentState.STA);
saver = new Thread(new ThreadStart(SaveRegularly));
saver.Start();
Here's my SaveRegularly method:
private bool stopAndDie = false;
private void SaveRegularly()
{
//DateTime saveDueAt = DateTime.Now.AddMinutes(0.25);
//do
//{
//Thread.Sleep(1000);
//if (DateTime.Now >= saveDueAt)
//{
if (SaveDoc.FileName != "") //ADDED THIS TODAY (24/09)
{
CreateWordDocument(FilePath, SaveDoc.FileName, pathImage);
MessageBox.Show("Updated");
return;
}
else
{
if (SaveDoc.ShowDialog() == DialogResult.OK)
{
CreateWordDocument(FilePath, SaveDoc.FileName, pathImage);
MessageBox.Show("New Save");
return;
}
}
timer1.Start();
}
This is for the FormClosing Event, so the thread stops.
stopAndDie = true;
saver.Join(2000);
timer1.Stop();
When I run the program and I click the save button, I receive an error at the SaveFileDialog line (if (SaveDoc.ShowDialog() == DialogResult.OK)).Here is the error I receive.
Set the thread to STA mode.
saver.SetApartmentState(System.Threading.ApartmentState.STA);
But why aren't you using timers if you want to schedule something periodically?
Something like this:
System.Timers.Timer timer = new System.Timers.Timer(5 * 60 * 1000);
timer.Elapsed += (s, e) =>
{
//Invoke your show dialog on the UI thread here
};
timer.Start();
And when you want it to stop just call timer.Stop();

C# Windows Service timer ticks more than one

I'm trying to make a service that should execute my codes every second after my codes execution ends. But when I start the service and debug it, timer ticks more than one, I mean, my codes executed twice before first execution ends.
here is my codes ;
Timer timer1 = new Timer(1000);
bool _service_working = false;
protected override void OnStart(string[] args)
{
timer1.Elapsed += new ElapsedEventHandler(runProcess);
timer1.Enabled = true;
timer1.Start();
_service_working = false;
}
protected override void OnStop()
{
timer1.Enabled = false;
}
private void runProcess(object sender, ElapsedEventArgs e)
{
try
{
if (_service_working == false)
{
timer1.Enabled=false;
_service_working = true;
}
#region myCodes
}
catch (Exception ex)
{
_logService.insert_log(1022, 2, ex.Message, "Path : runProcess");
}
finally
{
_service_working = false;
timer1.Enabled = true;
}
}
When I debug it, timer ticks again at runProcess if block...
Assuming you're using System.Timers.Timer then Timer events are raised in a background thread usually which means without any locking your timer event methods can overlap.
An easy solution is to set AutoReset to false and instead in your timer event restart it once complete, for example:
private bool terminating;
public Service()
{
terminating = false;
timer = new Timer(1000);
timer.Elapsed += new ElapsedEventHandler(runProcess);
timer.Enabled = true;
timer.AutoReset = false;
}
protected override void OnStart(string[] args)
{
timer.Start();
}
protected override void OnStop()
{
terminating = true;
timer1.Stop();
}
private void runProcess(object sender, ElapsedEventArgs e)
{
// Do stuff
if (!terminating)
timer.Start(); // Restart timer
}

System.Timers.Timer Restart without AutoReset ignores Intervall

I got a System.Timers.Timer (Even if Threading.Timer is more powerfull, I need the restart option) which should call an Event(Function) for data exchange.
My Timer Init:
private System.Timers.Timer _scheduler; //on class level
_scheduler = new System.Timers.Timer(double.Parse(Config.TimeIntervall));
_scheduler.AutoReset = false;
_scheduler.Elapsed += (o, args) => InterfaceSingleRun();
_scheduler.Start();
The function starts a task, and in the finally statement I got
_scheduler.Start()
to restart my Timer, which should start counting down the intervall again
My Problem: I want to prevent overlapping, because I don't know how long the Task will be running (depends on Server), but the _schedulter.Start() just restarts the Elapsed Event, instead of waiting the intervall time.
Could you please tell me if I just misunderstood the MSDN-Site/the Timer got some issues and how to fix them/or my code is just messed up :)
Thanks
EDIT:
Solved the Problem, thanks to Hans Passant.
I was working with seconds, which the program interpreted as milliseconds.
If i understand correct, you want to prevent a second trigger while the code inside the timer_tick is running.
i use a global bool like this:
class Program
{
private static bool timercodeRunning;
static void Main(string[] args)
{
var timer = new System.Timers.Timer(5000);
timer.Elapsed += timer_Elapsed;
timer.Start();
}
static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (!timercodeRunning)
{
timercodeRunning = true;
try
{
//DO SOME STUFF
timercodeRunning = false;
}
catch (Exception)
{
timercodeRunning = false;
throw;
}
}
}
}
instead of bool i recommended you to try locking. here is modified code of Gelootn
class Program
{
private static object timercodeRunning = new object();
static void Main(string[] args)
{
var timer = new System.Timers.Timer(5000);
timer.Elapsed += timer_Elapsed;
timer.Start();
}
static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
lock (timercodeRunning)
{
try
{
//DO SOME STUFF
}
catch (Exception)
{
throw;
}
}
}
}

Bad timer in Windows service

i have timer in my windows service, but the windows service does not do what it should do..
I want ask you, if i have good code with timer?
Part of my code (updated):
protected override void OnStart(string[] args)
{
timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(getFileList);
timer.Interval = 10000;
timer.Enabled = true;
timer.AutoReset = false;
}
private void getFileList(object sender, EventArgs e)
{
//Work with xml...
DeleteOldBackupFiles();
}
private void DeleteOldBackupFiles()
{
string[] Oldfiles = Directory.GetFiles(backup);
foreach (string Ofile in Oldfiles)
{
FileInfo fi = new FileInfo(Ofile);
if (fi.LastWriteTime < DateTime.Now.AddMonths(-2))
{
fi.Delete();
}
}
}
After your ideas i edit my code, but result is the same..
protected override void OnStart(string[] args)
{
timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(getFileList);
timer.Interval = 10000;
timer.Enabled = true;
timer.AutoReset = true;
}
You have most likely an error somewhere in your timer making it throw an exception. You will not detect that since System.Timers.Timer silently ignores all unhandled exceptions.
You'll therefore have to wrap all code with a try/catch block:
private void getFileList(object sender, EventArgs e)
{
try
{
DeleteOldBackupFiles();
}
catch (Exception ex)
{
//log exception or just put a breakpoint here.
}
}
Hence your timer is working, but you are doing something wrong in it.
I would change it to this:
protected override void OnStart(string[] args)
{
timer = new System.Timers.Timer();
timer.Elapsed += new ElapsedEventHandler(getFileList);
timer.Interval = 10000;
timer.AutoReset = false;
timer.Enabled = true;
}
private void getFileList(object sender, EventArgs e)
{
List<string> files = new List<string>();
try
{
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(****);
Setting AutoReset to false causes the Timer to fire just once. In other words, it's like an automatic Stop after the first firing of the Timer. So doing that means you don't need to Stop() the Timer in your getFileList method. This is an important distinction when the Timer interval is small. If you set AutoReset to true and call Stop() at the top of your handler, there's a small chance that your method will get called more than once. Setting AutoReset to false is a more definitive way to get the behaviour you desire.
Calling Start() and setting Enabled to true are redundant, so I removed the Start().
Interval is milliseconds, so I changed that to 10000.
Maybe you are having an Exception thrown somewhere in getFileList, possibly because the service is running with a Current Directory of c:\windows\system32\.
Add a reference to System.Windows.Forms then add Environment.CurrentDirectory = System.Windows.Forms.Application.StartupPath; in your void Main(...) before your service is created.
as #jgauffin pointed out, you should wrap your getFileList body in a 'try catch' and log the error to some absolute path like c:\errors.txt. otherwise you are just guessing whats wrong.

Windows Service acts two different way based on the machine

I wrote a windows service ,that will my class library every 15 mins interval to execute the class.
It works fine when i deployed the windows service in my machine,the timer works well and every 15 mins it calls my class library but when i deployed in my server,it works fine only on onstart after that its not raise the timer or every 15 mins suppose to call my class lib are not happening,some one please guide me what suppose to look here to identify the problem
here is my code
public partial class Service1 : ServiceBase
{
private Timer _timer;
private DateTime _lastRun = DateTime.Now;
public Service1()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
log4net.Config.XmlConfigurator.Configure();
_timer = new Timer(10 * 60 * 1000); // every 10 minutes
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
Shell Distribute= new Shell();
Distribute.Distribute();
_timer.start();//this line was missed in my original code
}
protected override void OnStop()
{
this.ExitCode = 0;
base.OnStop();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//if (_lastRun.Date < DateTime.Now.Date)
//{
try
{
_timer.Stop();
Shell Distribute= new Shell();
Distribute.Distribute();
}
catch(exception ex)
{}
finally
{
_timer.Start();
}
//}
}
}
}
I strongly believe log on issues but am not sure for two reasons,if i start or restart this service in my test server using the same account works well but only timer is not working.
The code is exactly same so i don't worry much about my code bcoz it work timer based in my local machine using the same account.
Thanks in Advance.
Am not sure why my service working now based on timer,all i did is add the log in the code like below to find out what's going on but fortunately it works like a charm.
protected override void OnStart(string[] args)
{
log4net.Config.XmlConfigurator.Configure();
log.Debug("Service Called when Onstart");
_timer = new Timer(10 * 60 * 1000); // every 10 minutes
log.Debug("calling Distributor Method");
Shell Distributor = new Shell();
Distributor.Distribute();
log.Debug("calling timer Elapsed");
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
log.Debug("start the timer");
_timer.Start();
}
protected override void OnStop()
{
log.Debug("stop the timer in OnStop method");
this.ExitCode = 0;
base.OnStop();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
log.Debug("IN Timer Elapsed method");
try
{
log.Debug("IN try block and calling timer stop function");
_timer.Stop();
log.Debug("Distributor Method Called from try block");
Shell Distributor = new Shell();
Distributor.Distribute();
}
catch (Exception ex)
{
log.Debug("IN Catch Block");
log.Debug(ex.Message);
}
finally
{
_lastRun = DateTime.Now;
log.Debug("IN Final Block");
log.Debug("start the timer");
_timer.Start();
log.Debug("Exit the Timer Elapsed Method");
}

Categories

Resources