-1

Id like to build a windows Service in C#.

This service needs to be run periodically like every 10s.

Questions:

  1. What is the difference between Timers.timer and Threading.timer?

  2. How can I call CheckingThings with parameters?

  3. If i run this code, it does invoke CheckingThings more than once every second like declared in here:

_timer = new Timer(new TimerCallback(CheckingThings), autoEvent, 5000, 1000);

Here is what i've got so far:

public partial class WindowsService1 : ServiceBase
{

    // Logging
    private static Serilog.Core.Logger _logEvent;


    public WindowsService1()
    {
        InitializeComponent();
    }

    public void OnDebug() {
        OnStart(null);
    }


    protected override void OnStart(string[] args)
    {

        //Logging
        try {
            _logEvent = new LoggerConfiguration()
                .WriteTo.File(AppDomain.CurrentDomain.BaseDirectory + @"Logs\Logfile.txt", rollingInterval: RollingInterval.Month)
                .CreateLogger();
        }
        catch (Exception e)
        {
            _logEvent.Error("The logging service is not working as expected: {errorMsg}", e);
        }

        try
        {
        // initializing some data here

                var autoEvent = new AutoResetEvent(true);
                while (true)
                {
                    _timer = new Timer(new TimerCallback(CheckingThings), autoEvent, 5000, 1000);
                }
        }
        catch (Exception e) {
            _logEvent.Error("An error occured while initializing service: {0}", e);
        }
    }

    private static void CheckingThings(object stateInfo) 
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;

    //These things needs to run periodically every 10s
    }

    protected override void OnStop()
    {
        _logEvent.Information("Stopping  Service ...");
    }

}

2letuknow
  • 1
  • 3
  • Your first question has already been answered here: https://stackoverflow.com/questions/1416803/system-timers-timer-vs-system-threading-timer – Klaus Gütter Oct 26 '20 at 09:59
  • 1
    you seem to create an unlimited amount of timers `while (true) _timer = new Timer(new TimerCallback(CheckingThings), autoEvent, 5000, 1000);` – Patrick Beynio Oct 26 '20 at 10:00
  • if i remove the while loop it only run once – 2letuknow Oct 26 '20 at 10:03
  • You want to **build** a windows service or you want to **run it** periodically? – Camilo Terevinto Oct 26 '20 at 10:05
  • Thanks Klaus, thanks for the link, i think i switch from threading.timer to timers.timer – 2letuknow Oct 26 '20 at 10:05
  • 1
    *How can I call CheckingThings with parameters?* - if you say to a timer "here, call this method every 10 seconds and supply various parameters", how are you expecting the timer to know what parameters to supply? How do you expect your phone's 8am alarm to turn on your coffee maker? How do you expect it to dial into the conference number and PIN for your 10am meeting? (Hint; it doesn't - it just alerts you to the current time, and you have to do those things in consequence) – Caius Jard Oct 26 '20 at 10:06
  • @CamiloTerevinto: Yes, programming a service that checking things periodically. And of course i like to execute/run this to have that work done =) – 2letuknow Oct 26 '20 at 10:08
  • I like to read a ini file to change the things to check, if i need to - without change the program. These are the parameters i like to pass – 2letuknow Oct 26 '20 at 10:13

1 Answers1

0

Here's a skeleton for a service class that does something every minute, using a System.Timers.Timer:

public partial class XService : ServiceBase
{
    private Timer _minute = new Timer(60000);

    public XService()
    {
        InitializeComponent();

        _minute.Elapsed += Minute_Elapsed;
    }

    //this is async because my 'stuff' is async
    private async void Minute_Elapsed(object sender, ElapsedEventArgs e)
    {
        _minute.Stop();
        try
        {
            //stuff
        }
        catch (Exception ex)
        {
            //log ?
        }
        finally
        {
            _minute.Start();
        }
    }

    protected override void OnStart(string[] args)
    {
        _minute.Start();            //this or..

        Minute_Elapsed(null, null); //..this, if you want to do the things as soon as the service starts (otherwise the first tick will be a minute after start is called
    }

 ...

I typically stop my timers while I do my thing - no point starting a job that takes 10 minutes and then another one a minute later, hence the stop/try/finally/start pattern

Edit:

Here's the tail part of the class and how it's started/launched both in debug (inside visual studio) and in release (as an installed windows service):

        //just an adapter method so we can call OnStart like the service manager does, in a debugging context
        public void PubOnStop()
        {
            OnStop();
        }
    }// end of XService class
        static void Main(string[] args)
        {
#if DEBUG
            new XService().PubStart(args);
            Thread.Sleep(Timeout.Infinite);
#else

            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new XService()
            };
            ServiceBase.Run(ServicesToRun);
#endif
        }
Caius Jard
  • 72,509
  • 5
  • 49
  • 80
  • Many Thanks!!! And what if i have to read the things to check from a text/ini file? Is it possible to pass those ones? – 2letuknow Oct 26 '20 at 10:20
  • There is literally no limit to what the code in Minute_Elapsed can do.. Well, unless you'/re running the service as a user that has no access to local disk resources... Read your INI at the start of the process (or at the very least check if your INI file modified date has changed since the last time you read it, and reread it if it has), if you don't want to have to stop and restart the service to get the new settings – Caius Jard Oct 26 '20 at 10:21
  • I tried your skeleton but its not doing the loop timer?! – 2letuknow Oct 26 '20 at 10:47
  • Er.. I pulled it straight out of a working service that checks every minute for videos it has to encode. How are you starting the service? – Caius Jard Oct 26 '20 at 12:17
  • This is how i start the Service backgroundTask = Task.Factory.StartNew(() => CheckingThings(cancellation), cancellation, TaskCreationOptions.LongRunning, TaskScheduler.Default); backgroundTask.Wait(); while (!cancellation.IsCancellationRequested) { // Main thread needs to be there to work } – 2letuknow Oct 27 '20 at 08:47
  • Now: The Service wont start correctly - Its because i call CheckingThings as an background task i suppose – 2letuknow Oct 27 '20 at 08:49
  • sorry about that =D I tried your skeleton but the service is starting and stops immediatly =( I have the Inital things in the start routine now and got rid of the task things – 2letuknow Oct 27 '20 at 13:07
  • Many Thanks its working =D I run it in debugging mode and did not added "Thread.Sleep(Timeout.Infinite);" in the debug case. Why do i need this in debugging case but not in "regular execution"? – 2letuknow Oct 27 '20 at 13:30
  • A service is mostly no different to any normal program, with the difference that you can't start a service exe from the command line.. A proper service uses servicebase.run and it does not return until the service is stopped so that's what is used in production. In debug operation you can't call servicebase.run so the simplest way to debug a service is just to run it like a basic command line app, arrange a way to call OnStart (like the windows service manager does) and then sleep the thread forever so the exe doesn't exit immediately. When you publish your service, add an installer and use SC – Caius Jard Oct 27 '20 at 16:04