2008-12-11 6 views
17

У меня есть служба, которая иногда вызывает пакетный файл. Пакетный файл занимает 5-10 секунд, чтобы выполнить:Служба зависает в WaitForExit после вызова командного файла

System.Diagnostics.Process proc = new System.Diagnostics.Process(); // Declare New Process 
    proc.StartInfo.FileName = fileName; 
    proc.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden; 
    proc.StartInfo.CreateNoWindow = true; 
    proc.Start(); 
    proc.WaitForExit(); 

файл существует и код работает, когда я запускаю тот же код в-консоли. Однако, когда он запускается внутри службы, он зависает на WaitForExit(). Мне нужно убить командный файл из процесса, чтобы продолжить. (Я уверен, что файл существует, как я вижу его в списке процессов.)

Как я могу исправить эту зависание?

Update # 1:

код Кевина позволяет мне получить выход. Один из моих пакетных файлов все еще висит.

"C: \ EnterpriseDB \ Postgres \ 8.3 \ Bin \ pg_dump.exe" -i -h локальный -p 5432 -U Postgres -F -a р -D -v -f «C: \ backupcasecocher \ . backupdateevent2008.sql "-t "\" общественность \" \ "dateevent \" " "DBTEST"

другой пакетный файл:

" C: \ EnterpriseDB \ Postgres \ 8.3 \ bin \ vacuumdb.exe "-U postgres -d DbTest

Я проверил путь, и путь postgresql в порядке. Каталог вывода существует и по-прежнему работает вне службы. Есть идеи?

Update # 2:

Вместо пути пакетного файла, я написал "C: \ EnterpriseDB \ Postgres \ 8.3 \ Bin \ pg_dump.exe" для proc.StartInfo.FileName и добавлены все параметры proc.StartInfo.Arguments. Результаты не изменяются, но я вижу pg_dump.exe в окне процесса. Опять же это происходит только внутри службы.

Update # 3:

я запустить службу с пользователем в группе администраторов, но безрезультатно. Я восстановил null имя пользователя сервиса и пароль

Update # 4:

Я создал простую службу, чтобы написать след в журнале событий и выполнить командный файл, который содержит «Dir» в нем. Теперь он будет зависать на proc.Start();. Я попытался сменить учетную запись с LocalSystem на User, и я установил пароль администратора и пароль, но ничего.

+0

@nzpcmad: Где у вас возникла идея сменить тег OP? – GEOCHET 2008-12-11 21:57:26

+0

Я не nzpcmad, но я предполагаю: поскольку он говорит: «У меня есть веб-сервис», я предполагаю, что у него есть веб-служба (.asmx), а не служба Windows. – 2008-12-11 22:06:32

+0

@ Майкл: Я не вижу, как это оправдывает/меняет/тег OP. – GEOCHET 2008-12-11 22:08:29

ответ

28

Вот что я использовать для выполнения пакетных файлов:

proc.StartInfo.FileName     = target; 
proc.StartInfo.RedirectStandardError = true; 
proc.StartInfo.RedirectStandardOutput = true; 
proc.StartInfo.UseShellExecute   = false; 

proc.Start(); 

proc.WaitForExit 
    (
     (timeout <= 0) 
      ? int.MaxValue : timeout * NO_MILLISECONDS_IN_A_SECOND * 
       NO_SECONDS_IN_A_MINUTE 
    ); 

errorMessage = proc.StandardError.ReadToEnd(); 
proc.WaitForExit(); 

outputMessage = proc.StandardOutput.ReadToEnd(); 
proc.WaitForExit(); 

Я не знаю, если это будет делать трюк для вас, но у меня нет проблемы он висит.

3

Что делает командный файл? Вы уверены, что процесс запускается с достаточным количеством привилегий для выполнения командного файла? Услуги могут быть ограничены тем, что им разрешено делать.

Также убедитесь, что если вы делаете что-то вроде Усина команды копирования, чтобы перезаписать файл, который вы делаете что-то вроде:

echo Y | copy foo.log c:\backup\ 

Кроме того, убедитесь, что вы используете полные пути для пакетных команд и т.д. Если командный файл запускает графическое приложение в каком-то режиме «Консоль», это может быть проблемой. Помните, что у служб нет «рабочего стола» (если только вы не разрешаете «взаимодействовать с рабочим столом»), чтобы рисовать любые окна или окна сообщений. В вашей программе вы можете открыть каналы stdout и stderr и прочитать их во время выполнения, если вы получаете сообщения об ошибках или что-то еще.

WebServices, вероятно, выполняется как учетная запись IUSR или анонимная учетная запись, которая когда-либо была так, что может быть проблемой для вас. Если он работает, когда вы запускаете его в консоли, это только первый шаг. :)

Я не помню, если System.Diagnostics. доступны только в отладке или нет. Наверное, нет, но некоторые из них могут быть. Я должен проверить это для тебя.

Надеюсь, это даст вам некоторые идеи.

Ларри

3

pg_dump.exe, вероятно, побуждая для ввода данных пользователем. Требует ли эта база данных аутентификация? Вы полагаетесь на любые переменные ОКРУЖАЮЩЕЙ СРЕДЫ, которые не будут присутствовать в сервисе? Я не знаю pg_dump, но каковы другие возможные причины, по которым он будет запрашивать ввод?

3

Следующим шагом, который я хотел бы предпринять, является запуск отладчика и просмотр того, что вы можете сказать о том, что ожидает программа. Если вы отлаживаетесь при отладке в сборке, вы можете получить ИДЕИ того, что происходит с помощью таких инструментов, как ProcExp, FileMon и т. Д.

Будучи службой Windows SERVICE, а не веб-службой, имеет немалую разницу , В любом случае, вы попробовали мое предложение установить «Разрешить службу взаимодействовать с рабочим столом»?

Если вы в отчаянии, попробуйте запустить cmd.exe вместо вашего пакетного файла. Затем, используя параметры cmd.exe, вы можете запустить пакетный файл. Это, вероятно, даст вам окно подсказки cmd для просмотра фактического вывода, если вы включите взаимодействие с рабочим столом.

Для получения полной справки по cmd.exe просто введите cmd /? в любой командной строке.

Larry

1

Вот решение. Решение непонятно, потому что я изменил так много времени на код, и теперь он работает!

Я попытался использовать учетную запись пользователя, и это не то, что сработало. Используйте LocalSystem. Вот код, который выполняется, в основном то, что дал мне Кевин.

  System.Diagnostics.Process proc = new System.Diagnostics.Process(); 
      proc.StartInfo.FileName = fileName; 
      proc.StartInfo.RedirectStandardError = true; 
      proc.StartInfo.RedirectStandardOutput = true; 
      proc.StartInfo.UseShellExecute = false; 


      proc.Start(); 
      proc.WaitForExit(); 
      output1 = proc.StandardError.ReadToEnd(); 
      proc.WaitForExit(); 
      output2 = proc.StandardOutput.ReadToEnd(); 
      proc.WaitForExit(); 

Благодарю вас, я буду голосовать всеми и принимать Кевина, так как он помогает мне с самого начала. Очень странно, потому что сейчас это работает ...

1

Даок, похоже, единственное, что вы изменили, это период ожидания на начальном WaitForExit(). Вы должны быть ОЧЕНЬ осторожны. Если что-то ДЕЛАЕТ повесить ваш сервис, он НИКОГДА не вернется (и хорошо, в значительной степени работа, как это было для вас до сих пор .. хех), но это будет нехорошо для конечных пользователей ...

Теперь, возможно, что вы знаете, что причиной этого, чтобы повесить, вы можете отлаживать его дальше и найти полное решение ...

Это, или спин это в каком-нибудь нить, что вы можете контролировать, и убить, если он висит слишком долго.

Только мои 2 цента стоит, что обычно не много. ;)

11

с использованием системы; с использованием System.Collections.Generic; с использованием System.Linq; с использованием System.Text; с использованием System.Diagnostics; пространства имен В.Г. { класс VGE { [STAThread] статической силы основных (String [] арг) { Процесс Proc = NULL; try {
string targetDir = string.Format (@ "D: \ adapters \ setup"); // здесь находится mybatch.bat proc = new Process(); proc.StartInfo.WorkingDirectory = targetDir; proc.StartInfo.FileName = "mybatch.bat"; proc.StartInfo.Arguments = string.Format ("10"); // это аргумент proc.StartInfo.CreateNoWindow = false; proc.Start(); proc.WaitForExit(); } catch (Exception ex) { Console.WriteLine ("Исключено: {0}, {1}", ex.Message, ex.StackTrace.ToString()); }} }}

4
  string targetDir = string.Format(@"D:\");//PATH 
      proc = new Process(); 
      proc.StartInfo.WorkingDirectory = targetDir; 
      proc.StartInfo.FileName = "GetFiles.bat"; 
      proc.StartInfo.Arguments = string.Format("10");//argument 
      proc.StartInfo.CreateNoWindow = false; 
      proc.Start(); 
      proc.WaitForExit(); 

испытано, работает ясно.