Даже несмотря на то, что он работает как выпускная версия, вам все равно будет предоставлена возможность подключиться к отладчику при сбое приложения ... вы просто не увидите символы отладки, просто сборка:)
Я полагаю, что это процесс доктора Ватсона, который улавливает ошибки приложения для отладки ... Поскольку ваше приложение является службой, доктор Ватсон не может взаимодействовать с рабочим столом, что выдает ошибку, которую вы видите. Вы можете перейти к свойствам службы и отметить «разрешить службе взаимодействовать с рабочим столом», расположенной на вкладке «Вход в систему», которая должна дать вам всплывающее окно «Доктор Ватсон» при сбое приложения.
Шаги, чтобы отключить доктора Ватсона здесь:
http://support.microsoft.com/kb/188296
Если вы хотите отлаживать приложение на сервере, вы можете включить удаленную отладку на сервере и подключить Visual Studio к процессу ... если вы хотите попробовать это, я могу дать вам больше советов по отладке окон обслуживание удаленно.
НТН,
Джеймс
* Редактировать *
Исходя из предоставленного вами кода, я рассмотрю следующие области:
Правильно ли установлен AppSettings.Default.FTPRootPath
в App.Config
?
Есть ли какие-либо изменения, происходящие с этим каталогом сразу после запуска службы? У вас есть таймер с комментариями «проверять каждые пять минут», что немного сбивает с толку, потому что FileSystemWatcher
начнет получать события, как только вы установите для EnableRaisingEvents
значение true. Таким образом, проблема может лежать в пределах fileCreatedOrChanged
Вдоль этих строк у вас есть один BackgroundWorker
, обслуживающий несколько событий, и, что еще хуже, вы запускаете обработчик асинхронно. Это, скорее всего, мое подозрение, потому что если вы снова наберете _worker.RunWorkerAsync()
во время выполнения первого задания, вы получите InvalidOperationException
. Хотя я не уверен, почему вы не увидите этого в журнале
Вы используете таймер для обновления времени последней записи для всех файлов в просматриваемой директории, и вы делаете это каждые пять секунд. Это кажется очень плохой идеей ... Я не уверен, что вы пытаетесь достичь. Это запустит ваше измененное событие FileSystemWatcher
, которое объяснит, почему вы потерпели крах менее чем через 10 секунд после запуска (начальный тик таймера настроен на немедленное срабатывание, то есть через пять секунд вы меняете все времена файла вызывая FileSystemWatcher
несколько раз вскоре после этого)
Так что я думаю, что в течение пяти секунд вы начали использовать несколько RunWorkAsync()
вызовов для одного и того же BackgroundWorker
, что является "нет-нет":)
Установка статической переменной _isBusy в значение true / false не является надежной, поскольку вы используете многопоточность с помощью BackgroundWorkers ... вам нужно использовать Mutex или какую-либо другую блокировку, но это на самом деле не противоречит цели используя BackgroundWorker?
Кроме того, если вы хотите использовать что-то вроде флага isBusy, оно должно выглядеть примерно так:
while (_isBusy) {
System.Threading.Thread.Sleep(5000);
}
_isBusy = true;
_worker.RunWorkerAsync(eventArgs);
Вам нужно, чтобы значение _isBusy было ложным, прежде чем пытаться запустить Фоновый рабочий ... как у вас есть, если событие запускается 100 раз, вы сделаете 100 вызовов.
Самым простым решением вашей проблемы было бы создание нового BackgroundWorker в методе fileCreatedOrChanged каждый раз, когда происходит событие ... при создании такого количества новых потоков возникают дополнительные затраты, но если работа, выполняемая с помощью этого метода, значительна, это будет стоить накладных расходов.
Возможно, вы сможете положиться на встроенное свойство BackgroundWorker.IsBusy, но, опять же, мне придется усомниться в преимуществах асинхронной потоковой обработки, если вы просто собираетесь блокировать, пока не завершится фоновый рабочий.
** Редактировать **
Теперь я понимаю, что вы пытаетесь достичь с помощью изменений временных меток файлов ... Думаю, вам лучше оставить метки времени в покое, а просто запустить цикл запуска для обработки существующих файлов. Вы можете создать фоновый рабочий поток для каждого из них, так же, как вы делаете это в примечаниях FileSystemWatcher. То, как вы справляетесь с этим, преднамеренно создает побочный эффект, чтобы вызвать желаемый результат.
Я немного сбился с пути из-за растущей сложности ... вся эта очередь / очередь может быть ненужной. Или, может быть, я просто не вижу потребности, которая действительно существует. Опять же, меня поразило то, что вы запускаете фоновый рабочий асинхронно, а затем переводите основной поток в спящий режим до его завершения.
Когда вы переводите основной поток в спящий режим, никакие события не обрабатываются, поэтому вы действительно ограничиваете многопоточность одним потоком. Я вижу, что вы хотите записать в журнал событий, сколько времени потребовалось для завершения потока. Я начну второй ответ, чтобы ответить на этот вопрос, если я получу шанс, но суть его в том, чтобы передать класс Stopwatch
(который даст вам точное количество миллисекунд или тактов ЦП, которые проходят во время операции) для свойство DoWorkEventArgs.Result.
Но код, который вы просили! По сути, куда бы вы ни решили позвонить _worker.RunWorkerAsync(queuedFile)
, вместо того, чтобы запускать один класс BackgroundWorker
, каждый раз создавайте новый. Передайте все те же параметры для обработчиков событий и т. Д. Ваша точка входа в службу отбросит все ссылки BGW и будет выглядеть так:
protected override void OnStart(string[] args)
{
try
{
_keys.AddRange(new string[] { "csv", "xml", "zip", "rivx" });
_watcher = new FileSystemWatcher(AppSettings.Default.FTPRootPath, "*.*");
_watcher.IncludeSubdirectories = true;
_watcher.NotifyFilter = sysIO.NotifyFilters.DirectoryName | sysIO.NotifyFilters.FileName | sysIO.NotifyFilters.LastAccess | sysIO.NotifyFilters.CreationTime | sysIO.NotifyFilters.LastWrite;
_watcher.Created += new sysIO.FileSystemEventHandler(fileCreatedOrChanged);
_watcher.Changed += new sysIO.FileSystemEventHandler(fileCreatedOrChanged);
_watcher.EnableRaisingEvents = true;
WriteToEventLog("Exit Start", EventLogEntryType.Information);
}
и код, где вы запускаете BGW асинхронно, станет:
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
worker.DoWork += new DoWorkEventHandler(BackgroundWorkerDoWork);
worker.ProgressChanged += BackgroundWorkerProgressChanged; // Note you don't need
worker.RunWorkerCompleted += BackgroundWorkerRunWorkerCompleted; // the 'new' here
worker.RunWorkerAsync(queuedFile); // goes to BackgroundWorkerDoWork(object sender, DoWorkEventArgs e) //