Windows Service acts two different way based on the machine - c#

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");
}

Related

Use windows service to run a method every on second

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.

Create a .NET Threading.Timer with a period Timeout.Infinite

What I want, a windows service that performs a function with a interval, without opening multiple threads.
What I did, using a Threading.Timer I created the following code:
protected override void OnStart(string[] args) {
System.Threading.Timer timer1 = new System.Threading.Timer(new TimerCallback(Risk), null, 60000, Timeout.Infinite);
}
public void Risk(object state) {
try{
//long operation
}
catch(ex){
}
finally{
timer1.Change(1000, Timeout.Infinite);
}
}
My problem, it looks like this code is opening multiple threads. Is this possible? Where did I go wrong? This a good way to get what I want?
UPDATE (using System.Timers.Timer):
protected override void OnStart(string[] args) {
System.Timers.Timer aTimer;
aTimer = new System.Timers.Timer(60000);
aTimer.Elapsed += Risk;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private void Risk(Object source, ElapsedEventArgs e) {
aTimer.Enabled = false;
try{}
catch(ex){}
finally{
aTimer.Interval = 1000;
aTimer.Enabled = true;
}
}
Multiple timer ticks can run concurrently. The timer class does not wait for ticks to complete. (I think it should have such a feature because it's almost always what you want.)
An easy fix is to run an loop with Task.Delay:
while (!cancel) {
DoStuff();
await Task.Delay(...);
}
And you kick that off with Task.Run(() => { AsyncCodeHere(); });.

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;
}
}
}
}

Keep window service live

My code is:
public partial class MainService : ServiceBase
{
public MainService()
{
InitializeComponent();
}
private void timer1_Tick(object sender, System.EventArgs e)
{
TextWriter file = new StreamWriter("C:\\logfile.txt", true);
file.WriteLine("CPU Usage : " + System.DateTime.Now);
file.Close();
}
protected override void OnStart(string[] args)
{
timer1.Enabled = false;
TextWriter file = new StreamWriter("C:\\logfile.txt", true);
file.WriteLine("Service Started");
file.Close();
timer1.Interval = 1000;
timer1.Tick+=new EventHandler(timer1_Tick);
timer1.Enabled = true;
timer1.Start();
}
protected override void OnStop()
{
TextWriter file = new StreamWriter("C:\\logfile.txt", true);
file.WriteLine("Service Restarted");
file.Close();
}
protected override void OnContinue()
{
TextWriter file = new StreamWriter("C:\\logfile.txt", true);
file.WriteLine("Service stopped");
file.Close();
}
}
The code write the time of system each one second. But it run only two times(on OnStart and OnStop). How to keep it live? who explain to me the lifecircle of window service
The problem is that you are using System.Windows.Forms.Timer. This particular component is intended for UI threads that need to do some processing. Windows services do not have UI threads, so this is the wrong choice of timer. More specifically, the problem is that Windows services do not have a UI message pump, so the Tick event is never processed. Replacing System.Windows.Forms.Timer with System.Timers.Timer will give you the expected results (see below).
A few suggestions for you.
Unless you have a pressing need to open and close the file each time you wish to write to it, I would suggest making your System.IO.TextWriter a class variable, open the file in OnStart(), and close it in OnStop().
If you'll put a call to System.Diagnostics.Debugger.Launch() in your OnStart() for example, you'll be prompted to jump into a debug session when you start your service. This will allow you to debug things as you move along.
The OnContinue() callback does not occur when the service is stopped. It occurs when the service is resumed after having been paused. Thus your messages are out of place. The "Service stopped" message should be logged in the OnStop() method. In practice, I haven't seen a need for implementing the pause/resume functionality, so you might consider whether you truly need it in your service.
On with the code...
public partial class Service1 : ServiceBase
{
System.Timers.Timer timer = new System.Timers.Timer();
System.IO.TextWriter file;
public Service1()
{
// Uncomment this line to launch the debugger when starting the service.
//System.Diagnostics.Debugger.Launch();
InitializeComponent();
}
protected override void OnStart(string[] args)
{
file = new StreamWriter("C:\\logfile.txt", true);
file.WriteLine("Service Started");
timer.AutoReset = true;
timer.Interval = 1000;
timer.Elapsed += OnTimerElapsed;
timer.Start();
}
protected override void OnStop()
{
timer.Stop();
timer.Dispose();
file.WriteLine("Service Stopped");
file.Close();
}
private void OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
file.WriteLine("CPU Usage : " + System.DateTime.Now);
}
}

Windows service with timer

I have created a windows service with timer in c#.net. it works fine while i debug/build the project in visual studio but it does not perform its operation after installation.
What might be the reason behind this ?
code :
public partial class Service1 : ServiceBase
{
FileStream fs;
StreamWriter m_streamWriter;
Timer tm = new Timer();
public Service1()
{
InitializeComponent();
this.ServiceName = "timerservice";
tm.Interval = 2000;
tm.Tick += new EventHandler(PerformOperations);
tm.Start();
fs = new FileStream(#"c:\mcWindowsService.txt", FileMode.OpenOrCreate, FileAccess.Write);
m_streamWriter = new StreamWriter(fs);
m_streamWriter.BaseStream.Seek(0, SeekOrigin.End);
}
private void PerformOperations(object sener, EventArgs e)
{
//StreamWriter swr = new StreamWriter("c:\\test_from_database.txt",true);
try
{
OdbcConnection con = new OdbcConnection("DSN=liquor_data");
OdbcDataAdapter adp = new OdbcDataAdapter("", con);
DataSet ds = new DataSet();
string sql = "select * from item_group";
adp.SelectCommand.CommandText = sql;
adp.Fill(ds, "item_group");
foreach (DataRow dr in ds.Tables["item_group"].Rows)
{
// swr.Write(dr["group_name"].ToString() + "\t\t" + DateTime.Now.TimeOfDay.ToString() + "\n");
//Console.WriteLine(dr["group_name"].ToString() + "\t\t" + DateTime.Now.TimeOfDay.ToString() + "\n");
m_streamWriter.WriteLine(dr["group_name"].ToString() + "\t\t" + DateTime.Now.TimeOfDay.ToString() + "\n");
}
m_streamWriter.Flush();
}
catch (Exception ex)
{
// swr.Write("Error :"+ ex.Message + "\t\t" + DateTime.Now.TimeOfDay.ToString() + "\n"); }
}
}
}
First approach with Windows Service is not easy..
A long time ago, I wrote a C# service.
This is the logic of the Service class (tested, works fine):
namespace MyServiceApp
{
public class MyService : ServiceBase
{
private System.Timers.Timer timer;
protected override void OnStart(string[] args)
{
this.timer = new System.Timers.Timer(30000D); // 30000 milliseconds = 30 seconds
this.timer.AutoReset = true;
this.timer.Elapsed += new System.Timers.ElapsedEventHandler(this.timer_Elapsed);
this.timer.Start();
}
protected override void OnStop()
{
this.timer.Stop();
this.timer = null;
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
MyServiceApp.ServiceWork.Main(); // my separate static method for do work
}
public MyService()
{
this.ServiceName = "MyService";
}
// service entry point
static void Main()
{
System.ServiceProcess.ServiceBase.Run(new MyService());
}
}
}
I recommend you write your real service work in a separate static method (why not, in a console application...just add reference to it), to simplify debugging and clean service code.
Make sure the interval is enough, and write in log ONLY in OnStart and OnStop overrides.
Hope this helps!
You need to put your main code on the OnStart method.
This other SO answer of mine might help.
You will need to put some code to enable debugging within visual-studio while maintaining your application valid as a windows-service. This other SO thread cover the issue of debugging a windows-service.
EDIT:
Please see also the documentation available here for the OnStart method at the MSDN where one can read this:
Do not use the constructor to perform processing that should be in
OnStart. Use OnStart to handle all initialization of your service. The
constructor is called when the application's executable runs, not when
the service runs. The executable runs before OnStart. When you
continue, for example, the constructor is not called again because the
SCM already holds the object in memory. If OnStop releases resources
allocated in the constructor rather than in OnStart, the needed
resources would not be created again the second time the service is
called.
Here's a working example in which the execution of the service is started in the OnTimedEvent of the Timer which is implemented as delegate in the ServiceBase class and the Timer logic is encapsulated in a method called SetupProcessingTimer():
public partial class MyServiceProject: ServiceBase
{
private Timer _timer;
public MyServiceProject()
{
InitializeComponent();
}
private void SetupProcessingTimer()
{
_timer = new Timer();
_timer.AutoReset = true;
double interval = Settings.Default.Interval;
_timer.Interval = interval * 60000;
_timer.Enabled = true;
_timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
// begin your service work
MakeSomething();
}
protected override void OnStart(string[] args)
{
SetupProcessingTimer();
}
...
}
The Interval is defined in app.config in minutes:
<userSettings>
<MyProject.Properties.Settings>
<setting name="Interval" serializeAs="String">
<value>1</value>
</setting>
</MyProject.Properties.Settings>
</userSettings>

Categories

Resources