Что лучший способ состоит в том, чтобы сделать некоторую долгую инициализацию, когда служба Windows запускает (или возобновляется от того, чтобы быть приостановленным), не блокируя Диспетчер управления службами?
Вы можете использовать BackgroundWorker
для выполнения длительной операции в ответ на событие Service.Start.
Это достаточно просто сделать в методе OnStart ()
вашего класса, производного от ServiceBase
. Также есть разумный хороший пример в 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...
}
Обратите внимание, что вы также можете подписаться на события ProgressChanged
и RunWorkerCompleted
, чтобы вы могли информировать диспетчер управления службами о своем прогрессе и успешном (или неудачном) запуске.
У меня тоже была эта проблема со службой Windows. Я думаю, вам нужно сохранить логику инициализации менее 30 секунд, иначе Windows Service Manager остановит службу.
То, что я сделал, было довольно просто. Я создал метод, в который я поместил всю тяжелую логику, которую необходимо было выполнить, а затем я создал таймер, который сработает через 20 секунд и выполнит этот метод. Таким образом, служба запустится, затем создаст таймер, инициализирует его с интервалом в 20 секунд, а затем завершит инициализацию. Через 20 секунд таймер сработает и запустит бизнес-логику приложения. Конечно, вы можете указать любой желаемый интервал времени.
Вы должны объявить таймер как параметр класса:
public partial class YourService: ServiceBase
{
System.Timers.Timer tmrOnStart;
Затем инициализировать таймер в методе OnStart
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();
}
Когда таймер вызовет событие Elapsed, он выполнит этот метод:
void tmrOnStart_Elapsed(object sender, ElapsedEventArgs e)
{
heavyBusinessLogicMethod();
}
И вы должны нужно поместить вашу логику в метод heavyBusinessLogicMethod.
Обычно мы используем простой таймер для достижения этой функции . Мы установим таймер в службе OnStartup, позволим службе ответить диспетчеру управления службами, а затем через несколько секунд таймер запустит процесс. Этот процесс может идти в отдельном потоке или нет, в зависимости от того, что нужно сделать. Таймер можно использовать повторно, если этот процесс должен происходить через определенные промежутки времени.
Я тоже должен сделать это: я создаю поток при запуске, который выполняет всю его инициализацию и устанавливает частный isInitialized в значение true, когда он завершается. Служба периодически выполняет действия (например, по таймеру) и не будет запускать эти действия, если для isInitialized не установлено значение true.
Лучший практический способ - создать рабочий поток.
Вообще существует другой документированный способ, который я могу объяснить на примере неуправляемого кода.Во время инициализации у службы Windows есть на это немного времени. На этот раз можно изменить где-нибудь в реестре. Если сервису требуется больше, можно вызвать
SetServiceStatus
с dwCurrentState = SERVICE_START_PENDING
, некоторые dwCheckPoint
и dwWaitHint
, из SERVICE_STATUS
struct заполняется так, чтобы dwWaitHint
было расчетным временем, требуемым для отложенной операции запуска в миллисекундах. Прежде чем истечет указанный промежуток времени, служба должна сделать свой следующий вызов функции SetServiceStatus
либо с увеличенным значением dwCheckPoint
, либо с изменением в dwCurrentState
. См. Описание dwWaitHint
на http://msdn.microsoft.com/en-us/library/ms685996 (VS.85) .aspx .