0

I'm writing a C# service and its main function is to pull photos from a database and save them to a directory twice a day. This operation takes about 15 minutes typically (there are a lot of photos). If I put the logic to run the program in OnStart(), then after a minute or so of starting up the service reports that it did not start up successfully. This is because it is in the OnStart() method for too long.

How can I set a timer in the OnStart() method that will call my RunApp() method after about a minute?

Edit: Here is some code. After setting up the scheduler that makes it run daily, I also want to just plain run it. I figured setting a timer for about a minute would work, that way it has time to get out of the OnStart() method. Then when the timer goes off the app will run.

protected override void OnStart(string[] args)
{
    Scheduler sch = new Scheduler("Photo Sync");

    try
    {
      MailConfiguration mailConfig = new MailConfiguration(Properties.Settings.Default.EmailLogTo, Properties.Settings.Default.EmailLogFrom,
                                                           "Photo Sync Photo Service error", Properties.Settings.Default.SmtpServerIp, "Photo Sync");
      sch.MailComponent = mailConfig;
    }
    catch
    {

    }

    sch.SchedulerFired += new EventHandler(RunApp);

    try
    {
      sch.ScheduleDaily(Properties.Settings.Default.DailyScheduledTime);
    }

    RunApp();
}
grantmcconnaughey
  • 10,130
  • 10
  • 37
  • 66
  • 2
    You could have the save functionality run on a separate thread - that way you're not killing the service because it takes too long to start. Simply kick off the save in a separate thread in OnStart. – Tim Mar 27 '13 at 15:59
  • 1
    Google "windows service timer". If you post some code we can help you out, but you have to try first. – Rob Mar 27 '13 at 16:00
  • 1
    Can't you use a [scheduled task](http://support.microsoft.com/kb/308569)? – Hans Kesting Mar 27 '13 at 16:00
  • @Tim: I suggest you add that as an answer. – Jon Skeet Mar 27 '13 at 16:00
  • I have edited the post to add code and a bit more clarity as to what I'm going for here. Tim, would you be able to provide a starting point to your answer? I'm not really familiar with threading. – grantmcconnaughey Mar 27 '13 at 16:06
  • @grantmc - I posted a stub. You should be ok moving your logic above from OnStart into a method (I used SavePhotos in my stub below) that is run on another thread. Let me know if you need more information. – Tim Mar 27 '13 at 16:15

3 Answers3

1

Typically, the normal process to starting a Windows Service is to make a thread, and have that thread perform the service processing, allowing OnStart to exit timely for Windows. The thread is still in the background processing things. For example:

protected CancellationTokenSource _tokenSource = null;

protected override void OnStart(string[] args)
{
    _tokenSource = new CancellationTokenSource();

    Task processingTask = new Task(() =>
       {
           while(!_tokenSource.IsCancellationRequested)
           {
               // Do your processing
           }
       });

    processingTask.Start();
}

protected override void OnStop()
{
    _tokenSource.Cancel();
}

If your service does not need to be running indefinitely, then you might want to consider a scheduled task.

Tejs
  • 40,736
  • 10
  • 68
  • 86
1

Run the save functionality in a separate thread that you start in the OnStart method of your service. Something like this:

protected override void OnStart(string args[])
{

    // your other initialization code goes here

    // savePhotos is of type System.Threading.Thread
    savePhotosThread = new Thread(new ThreadStart(SavePhotos));
    savePhotosThread.IsBackground = true;
    savePhotosThread.Name = "Save Photos Thread";
    savePhotosThread.Start();

}

You'll place the functionality for saving the files in the `SavePhotos` method, maybe something like this:

private void SavePhotos()
{

    // logic to save photos
}

I've used code similar to the above to do logging (I log stats for the service every 5 minutes or so) for an always-on service I wrote a few years back. Don't forget to add System.Threading to your service and the using directive.

Tim
  • 28,212
  • 8
  • 63
  • 76
  • This worked perfectly, thanks! One quick question, is it important that I set IsBackground to true? – grantmcconnaughey Mar 27 '13 at 16:18
  • According to MSDN, the difference between a background thread and a foreground thread is that once all foreground threads are finished, the application terminates and any remaining background threads end as well without completing. In your case, I'd set it to true to ensure that the process to save all the photos completes. Take a look at [Thread.IsBackground Property](http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx) for more information and an example that shows the difference. – Tim Mar 27 '13 at 16:24
0
    System.Threading.Timer Timer1 = new System.Threading.Timer(RunApp, null, 1000, System.Threading.Timeout.Infinite);

void RunApp(object State)
{
}
Michael Ross
  • 572
  • 4
  • 7