Я новичок в С# (и разработке в целом). Мне нужно написать метод на C#, который будет выполняться через консоль: - установить Ньюман; - казнить почтальона Беги.
Я создал метод, как показано ниже (я пробовал 2 варианта: ReadToEnd и WaitForExit), но, похоже, он застрял на каждом из этих шагов.
Любая помощь, как сделать так, чтобы обе команды выполнялись последовательно (1-я должна завершиться до 2-го запуска) и выйти после полного выполнения 2-й команды?
Заранее спасибо.
public string Runner ()
{
string readOutput = null;
var psiNpm = new ProcessStartInfo
{
FileName = "cmd",
RedirectStandardOutput = true,
RedirectStandardInput = true,
UseShellExecute = false
};
var pNpmRun = Process.Start(psiNpm);
pNpmRun.StandardInput.WriteLine($"npm install -g newman");
pNpmRun.WaitForExit();
//pNpmRun.StandardOutput.ReadToEnd();
pNpmRun.StandardInput.WriteLine($"newman run " +
$"\"C:\\Postman\\Test.postman.json\" " +
$"--folder \"TestSearch\" " +
$"--environment \"C:\\Postman\\postman_environment.json\" " +
$"--disable-unicode");
pNpmRun.StandardOutput.ReadToEnd();
pNpmRun.WaitForExit();
return readOutput = pNpmRun.StandardOutput.ReadLine();
}
Попробуйте написать команду exit
во входной поток cmd
.
Проблема заключается в том, что отправленные вами команды (npm, newman) выполняются, затем управление возвращается в оболочку (cmd), которая затем ожидает отправки дополнительных данных пользователя. Вам нужно сказать ему выйти, отправив «exit». У вас должен быть только 1 вызов WaitForExit. WaitForExit ожидает завершения процесса cmd
, а не отдельных команд, которые вы ему отправляете.
Далее следует переместить ReadToEnd
после процесс завершился (после WaitForExit
). Вот вопрос, почему: ReadToEnd из стандартного вывода процесса и waitforexit
Итак, что-то вроде этого:
public string Runner ()
{
var psiNpm = new ProcessStartInfo
{
FileName = "cmd",
RedirectStandardOutput = true,
RedirectStandardInput = true,
UseShellExecute = false
};
var pNpmRun = Process.Start(psiNpm);
pNpmRun.StandardInput.WriteLine("npm install -g newman");
pNpmRun.StandardInput.WriteLine("newman run " +
"\"C:\\Postman\\Test.postman.json\" " +
"--folder \"TestSearch\" " +
"--environment \"C:\\Postman\\postman_environment.json\" " +
"--disable-unicode");
pNpmRun.StandardInput.WriteLine("exit");
pNpmRun.WaitForExit();
return pNpmRun.StandardOutput.ReadToEnd();
Вы также можете рассмотреть возможность добавления тайм-аута в файл WaitForExit. Если эти команды по какой-то причине застревают, ваш процесс вызова также застрянет в ожидании их завершения. Обычно лучше в конечном итоге потерпеть неудачу, чем иметь кучу зависших процессов. Затем вы можете убить процесс, если истечет время ожидания.
var tenMin = 10 * 60 * 1000;
if (pNpmRun.WaitForExit(tenMin)) {
return pNpmRun.StandardOutput.ReadToEnd();
} else {
pNpmRun.Kill();
throw new TimeoutException("Command didn't complete in 10 minute timeout");
}
Спасибо @MarkPflug! Это работает так, как мне нужно. Кстати, как мне настроить его, чтобы он не работал и убивал процесс, если cmd завис?
@KVN Обновлено с примером тайм-аута. Обратите внимание, что если процессы npm или newman зависли, они будут уничтожены нет, только процесс cmd.
Большое спасибо @MarkPflug!
@KVN Еще одна вещь, которую вы должны учитывать, - это поведение, если команды npm / newman по какой-то причине не работают. Предположительно, npm может дать сбой, если возникла проблема с сетью и т. д. Вероятно, вам следует проверить коды выхода ваших команд, и если они не равны нулю (сбои), то сообщить об этом вызывающей стороне, используя «exit% errorlevel%». Если вам нужна помощь с этим, вероятно, лучше всего открыть новый вопрос.
Спасибо @MarkPflug. На самом деле, это теперь моя настоящая проблема, если есть проблема с выполнением Newman - он просто зависает и переходит в часть сбоя/убийства IF. Для этого я создал еще один тикет (может быть, вы поможете и с этим): stackoverflow.com/questions/55600299/…
извините, @MarkPflug, похоже, что мое текущее выполнение всегда завершается ошибкой WaitForExit, независимо от того, указываю ли я 0 мс или 10 минут, оно всегда переходит в часть условия Process.Kill(). Но команда newman выполнилась за 2-5 сек. Любые мысли о том, что происходит (неправильно) с ним? Я могу создать новый вопрос, если это необходимо.
Я считаю, что если вы используете как StandardInput, так и StandardOutput, вы должны использовать сделать это асинхронно, чтобы избежать взаимоблокировок.