Right now I'm using a timer to trigger my method. But how can I make the service run my method as soon as it has finished?
private Timer timer;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
DoSomething();
timer = new Timer();
timer.Enabled = true;
timer.Interval = 60000;
timer.AutoReset = true;
timer.Start();
timer.Elapsed += timer_Elapsed;
}
protected override void OnStop()
{
base.OnStop();
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
DoSomething();
}
Get rid of the timer and use recursion:
public Service()
{
InitializeComponent();
DoSomething();
}
private void DoSomething()
{
// some code that takes a while to execute
// make recursive call to self
DoSomething();
}
EDIT The answer as accepted won't work in the context of a service (actually, it will execute, but the service itself will be forever stuck in 'Starting' status, and will generate a 1503 error).
Here is the full code for a service that will continuously execute a method:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
namespace recursion
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
System.Threading.Thread thread;
protected override void OnStart(string[] args)
{
System.IO.File.WriteAllText(#"C:\Temp\Foo.txt", "Starting at: " + System.DateTime.Now.ToString());
thread = new System.Threading.Thread(DoSomething);
thread.Name = "Worker Thread";
thread.IsBackground = true;
thread.Start();
}
private void DoSomething() {
while (true)
{
System.IO.File.WriteAllText(#"C:\Temp\Foo.txt", "The Time is now: " + System.DateTime.Now.ToString());
System.Threading.Thread.Sleep(1000);
}
}
protected override void OnStop()
{
}
}
}
#cslecours you were wrong that it would cause a StackOverflow, but you were right in that causing the OnStart method not to exit would cause and error for a Windows service.
Use a Thread and an infinite while loop.
private void Start()
{
while(true)
DoSomething();
}
protected override void OnStart(string[] args)
{
Task.Factory.StartNew(() => Start());
}
Related
hi, i have send form context to another class to run function there, but the fun show out the messagebox but not update form text , why ?
i need the function start to update form title
i sending form context to timer class as parameter
the function start work in interval but the method cant update the
form control
this is form class
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication8
{
public partial class Form1 : Form
{
public Form1()
{
//form constractor
InitializeComponent();
}
timer mytimer;
private void Form1_Load(object sender, EventArgs e)
{
}
private void Elipse()
{ //the code for timer :) //yazeed coding
//MessageBox.Show(" ");
this.Text=" jkghjg";
}
private void button1_Click(object sender, EventArgs e)
{
mytimer = new timer();
mytimer.elipse += Elipse;
mytimer.Interval = 1000;
mytimer.start(this);
}
}
}
this is timer class
class timer
{
bool isstart;
public delegate void Del();
public Del elipse;
public static void UserRep() { }
public bool Enable { get; set; }
public int Interval { get; set; }
public timer()
{
Enable = false;
Interval = 1000;//default is 1 sec
isstart = false;
elipse = new Del(UserRep);
}
public void start(Form Context)
{
Context.BeginInvoke((MethodInvoker)async delegate
{
Enable = true;
isstart = true;
do
{
await Task.Delay(Interval);
new Thread(() =>
{
elipse(); //the replacment running now (interface thrad protected)
}).Start();
}
while (isstart);
Enable = false;
});
}
public void stop()
{
isstart = false;
}
}
AND thanks
As you are starting a new thread, you need to call elipse in the Form context:
Replace:
new Thread(() =>
{
elipse();
}).Start();
with
new Thread(() =>
{
Context.BeginInvoke(elipse);
}).Start();
Thanks Robert, good improvement , the code running successfully i add the post to see what others say, for code correct :) i keep this method like this for other developer to understand that they can add more code here
i find lot of post that they use long code to perform small task,
here is light code for many methods used in many project and helpful
this code is same as Microsoft timer implemented by me
here it is
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication8
{
public partial class Form1 : Form
{
public Form1()
{
//form constractor
InitializeComponent();
}
timer mytimer;
private void Form1_Load(object sender, EventArgs e)
{
//perform event click for button automaticly
button1.PerformClick();
}
private void Elipse()
{
//the code for timer :) //yazeed coding ,,,, write any other code
new Thread(() => MessageBox.Show("Successful")).Start();
Text = DateTime.Now.TimeOfDay.Seconds.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
mytimer = new timer();
mytimer.elipse += Elipse;
mytimer.Interval = 1000;
mytimer.Enable = true;
mytimer.start(this);
}
}
}
class timer
{
bool isstart;
internal delegate void Del();
internal Del elipse;
static void UserRep() { }
internal bool Enable { get; set; }
internal int Interval { get; set; }
internal timer(int val=100)
{
Enable = false;
Interval = val>0?val:100;//default is 1 sec
isstart = false;
elipse = new Del(UserRep);
}
internal void start(Form Context)
{
new Thread(async () =>
{
isstart = true;
do
{
await Task.Delay(Interval);
new Thread(() => Context.BeginInvoke((MethodInvoker)delegate
{
elipse(); //the replacment running now (interface thrad protected)
})).Start();
}
while (isstart);
}).Start();
}
internal void stop()
{
isstart = false;
}
}
I'm currently trying to create a service that will execute a metod every 14 days, (is 20 sec now, becasue of testing). I have currently these lines of code in my service and i cant seem to get it to run the AddDataToDb() metod. Anyone got any idea of what i can do to get the timer to work?
public partial class Service1 : ServiceBase
{
System.Timers.Timer oTimer = null;
double interval = 2000;
public Service1()
{
InitializeComponent();
IntializeService();
}
void IntializeService()
{
oTimer = new System.Timers.Timer(interval);
oTimer.Enabled = true;
oTimer.AutoReset = true;
oTimer.Start();
oTimer.Elapsed += new ElapsedEventHandler(oTimer_Elapsed);
}
void oTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Data.mData data = new mData();
data.AddDataToDb();
}
protected override void OnStart(string[] args)
{
oTimer.Enabled = true;
oTimer.Start();
}
protected override void OnStop()
{
oTimer.Stop();
}
}
I am developing a windows service that sends automated e-mail in every 15 minutes. I am using a timer to use the service again after a fixed time interval (15 minutes) but its not working.
namespace Mailer
{
public partial class Mailer : ServiceBase
{
System.Timers.Timer createOrderTimer;
public Mailer()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
sendmail(); //function to send email.
createOrderTimer = new System.Timers.Timer();
createOrderTimer.Elapsed += new System.Timers.ElapsedEventHandler(createOrderTimer_Elapsed);
createOrderTimer.Interval = 15000;
createOrderTimer.Enabled = true;
createOrderTimer.AutoReset = true;
createOrderTimer.Start();
}
protected void createOrderTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs args)
{
createOrderTimer.Stop();
ServiceController controller = new ServiceController("Mailer");
controller.Start();
}
protected void sendmail
{
//code to send email.
}
protected override void OnStop() { }
}
}
Initially the email is sent but I want the email sending to be performed in every 15 minutes.
You need to change the code like this
namespace Mailer
{
public partial class Mailer : ServiceBase
{
System.Timers.Timer createOrderTimer;
public Mailer()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
createOrderTimer = new System.Timers.Timer();
createOrderTimer.Elapsed += new System.Timers.ElapsedEventHandler(sendmail);
createOrderTimer.Interval = 900000; // 15 min
createOrderTimer.Enabled = true;
createOrderTimer.AutoReset = true;
createOrderTimer.Start();
}
protected void sendmail(object sender, System.Timers.ElapsedEventArgs args)
{
//code to send email.
}
protected override void OnStop() { }
}
}
Is there any chance that timer_Tick could be called after myForm_FormClosing
in the code below.
If there is a chance: Is it sufficient to call timer.Stop() within myForm_FormClosing in order to avoid that timer_Tick gets called after myForm_FormClosing?
using System;
using System.Windows.Forms;
using System.ComponentModel;
namespace Test
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
}
}
class MyForm : Form
{
private IContainer components;
private Timer timer;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
public MyForm()
{
components = new Container();
timer = new Timer(components);
timer.Interval = 50;
timer.Tick += timer_Tick;
timer.Enabled = true;
FormClosing += myForm_FormClosing;
}
private void timer_Tick(object sender, EventArgs e)
{
}
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
}
}
}
Update:
After receving a few hints (thanks for helping) I basically have chosen the following code to achive what I want.
Please not that timer1_Tick could still be called after myForm_FormClosing was called!
This solution just introduces a flag (i called it doWork) which stops the code within timer1_Tick to be executed after myForm_FormClosing was called.
using System;
using System.Windows.Forms;
using System.ComponentModel;
namespace Test
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyForm());
}
}
class MyForm : Form
{
private IContainer components;
private Timer timer;
private bool doWork = true;
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
public MyForm()
{
components = new Container();
timer = new Timer(components);
timer.Interval = 50;
timer.Tick += timer_Tick;
timer.Enabled = true;
FormClosing += myForm_FormClosing;
}
private void timer_Tick(object sender, EventArgs e)
{
if (doWork)
{
//do the work
}
}
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
doWork = false;
}
}
}
Yes it is possible. According to the docs ...
Occurs before the form is closed.
When a form is closed, it is disposed, releasing all resources
associated with the form.
The timer will not be disposed until after the FormClosing event. Here is a very contrived example of how it can happen. You will see that you hit the debugger breakpoint on the Timer tick after FormClosing has been called.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
private System.Windows.Forms.Timer _time = new System.Windows.Forms.Timer();
private Task _t1 = null;
private Task _t2 = null;
private bool _closingFlag = false;
public Form1()
{
InitializeComponent();
_time.Interval = 50;
_time.Tick += (s, e) => {
textBox1.Text = DateTime.Now.ToString();
if (_closingFlag) Debugger.Break();
};
_time.Start();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
_closingFlag = true;
_t1 = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
_t2 = Task.Factory.StartNew(() => { Thread.Sleep(1000); });
Task.WaitAll(_t1, _t2);
}
}
}
If you use a the timer System.Windows.Forms.Timer the UI thread must be idle to process a tick from the timer, so from my understanding that's is not possible.
Could happen if you use a timer with its own thread, as a System.Timers.Timer. In this case we could avoid what you mention by implementing something like this:
class MyForm : Form
{
private System.Timers.Timer timer;
private Object justForLocking = new Object();
private Boolean safeToProceed = true;
[...]
public MyForm()
{
components = new Container();
timer = new System.Timers.Timer();
timer.Interval = 50;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Start();
FormClosing += myForm_FormClosing;
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// In case that this code is being executed after
// the method myForm_FormClosing has adquired the
// exclusive lock over our dummy resource,
// the timer thread will wait until the resource if released.
// Once is released, our control flag will be set to false
// and the timer should just return and never execute again.
lock(justForLocking)
{
if (safeToProceed)
{
// Do whatever you want to do at this point
}
}
}
private void myForm_FormClosing(object sender, FormClosingEventArgs e)
{
lock(justForLocking)
{
safeToProceed = false;
}
timer.Stop();
// Do something else
}
[...]
}
This other SO question has relevant information.
EDIT: the code above is only valid if a System.Timers.Timer is used instead of System.Windows.Forms.Timer
I dont believe so but it would be best anyways to call timer.stop() regardless. if you were needing it to though you should create the timer object in program.cs
I am new to C# and I am having a problem. I have a Form that runs a thread which receives input from a serial port. However when the window is closed the thread keeps running. I tried overriding virtual void OnClosing(object sender, CancelEventArgs e) but the MessageBox keeps popping up which means the thread is still running. What am I doing wrong? Which is the best lifecycle method to override to do cleanup before the window is closed?
DisplayForm.cs
using System;
using System.ComponentModel;
using System.Drawing;
using System.IO.Ports;
using System.Threading;
using System.Windows.Forms;
namespace project
{
public partial class DisplayForm : Form
{
private Thread readThread;
private SerialPort port;
private bool running;
public DisplayForm(String portName)
{
InitializeComponent();
port = new SerialPort(portName);
port.Open();
readThread = new Thread(Read);
running = true;
readThread.Start();
}
public void Read()
{
while (running)
{
try
{
string message = port.ReadLine();
Console.Write(message);
MessageBox.Show(message);
}
catch (TimeoutException)
{
}
}
}
protected virtual void OnClosing(object sender, CancelEventArgs e)
{
running = false;
readThread.Join();
port.Close();
}
}
}
You need to use Abort() and not Join().
protected virtual void OnClosing(object sender, CancelEventArgs e)
{
running = false;
readThread.Abort();
port.Close();
}
OnClosing or OnClosed event call try to see any child thread running and abort them all...in your code first call port.close and then runThread which you already have access to it in Oncl