views:

66

answers:

5

What's the best way to do some lengthy initialization when a Windows service starts up (or resumes from being paused) without blocking the Service Control Manager?

+8  A: 

You can use a BackgroundWorker to perform your lengthy operation in response to the Service.Start event.

It's easy enough to do so in the OnStart() method of your ServiceBase-derived class. There's also a reasonable good example on MSDN.

protected override void OnStart(string[] args)
{
    var worker = new BackgroundWorker();
    worker.DoWork += DoSomeLongOperation;

    worker.RunWorkerAsync();
}

private void DoSomeLongOperation(object sender, DoWorkEventArgs e)
{
   // do your long operation...
}

Note that you can also subscribe to the ProgressChanged and RunWorkerCompleted events, so that you can inform the service control manager of your progress and startup success (or failure).

LBushkin
+1  A: 

I have to do this as well: I spawn a thread on startup that does all of its initialization and sets a private 'isInitialized' to true when it's finished. The service does actions periodically (ie, on a timer) and won't begin those actions if isInitialized isn't set to true.

SnOrfus
A: 

We typically use a simple timer to achieve this functionality. We'll set the timer up in the service OnStartup, let the service respond back the Service Control Manager and then have the timer kick off the process after a few seconds. That process can go in a separate thread or not depending on what needs to be done. The timer can be reused if this process needs to happen at regular intervals.

Walter
A: 

The best pragmatical way is creating a working thread.

In general exist another documented way, which I can explain on the example of unmanaged code. During initialization a windows service have a small time to do this. This time can be change somewhere in registry. If service need more if can call

SetServiceStatus with dwCurrentState=SERVICE_START_PENDING some dwCheckPoint and dwWaitHint, of SERVICE_STATUS struct filled so that dwWaitHint is The estimated time required for a pending start operation in milliseconds. Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function with either an incremented dwCheckPoint value or a change in dwCurrentState. See description of dwWaitHint on http://msdn.microsoft.com/en-us/library/ms685996(VS.85).aspx.

Oleg
+1  A: 

I also had this problem with a Windows Service. I think you have to keep the initialization logic under 30 seconds, otherwise the Windows Service Manager will stop the service.

What I did was quite simple. I created a method where I put all of the heavy logic that needed to be executed and then I created a timer that would tick after 20 seconds and execute that method. So the service would start, then create the timer, initialize it with an interval of 20 seconds and then finish the initialization. After 20 seconds the timer would tick and start the business logic of the application. Of course you can specify whatever interval of time you want.

You should declare the timer as a parameter of the class:

public partial class YourService: ServiceBase
{
   System.Timers.Timer tmrOnStart;

Then initialize the timer in the OnStart method

protected override void OnStart(string[] args)
{
    //set the interval to 20 seconds
    tmrOnStart = new Timer();
    tmrOnStart.Interval = 20000;
    tmrOnStart.Enabled = true;
    tmrOnStart.AutoReset = false;
    tmrOnStart.Elapsed += new ElapsedEventHandler(tmrOnStart_Elapsed);
    tmrOnStart.Start();
}

When the timer will trigger the Elapsed event, it will execute this method:

void tmrOnStart_Elapsed(object sender, ElapsedEventArgs e)
{
    heavyBusinessLogicMethod();
}

And you would have to put your logic in the heavyBusinessLogicMethod method.

Andrei