Осмысленное использование консольных приложений в C#

от автора

Когда что-то уже написано, оттестировано и достойно справляется со своей работой, то лучше использовать это средство, нежели изобретать велосипед. Например, есть консольная утилита cpctest.exe, которая позволяет выполнять все те-же действия что и графическая оболочка, и масса других утилит из стандартного набора Windows. На разработку, отладку и покрытие тестами аналогичной функциональности уйдет драгоценное время. Так зачем его прожигать? Приступим.

Для начала нам нужно залезть на MSDN и посмотреть синтаксис стандартных команд. В результате мы увидим, что запуск любого консольного приложения состоит из имени приложения и его параметров. Приложение инстанцируется системным классом Process. Прототип нашей функции для запуска консольного приложения будет выглядеть следующим образом:

	bool Execute(string commandName, IEnumerable<string> paramsList) 

Если мы захотим получать результат выполнения запущенного приложения и обрабатывать его, нам потребуется соответствующий метод:

string GetResult (string commandName, IEnumerable<string> paramsList) 

Далее идем снова на MSDN и смотрим ProcessStartInfo Arguments, UseShellExecute, RedirectStandardOutput и RedirectStandardError, если Вы будете строго обрабатывать исключения как в Java. В итоге для инициализации процесса нам потребуется свойство, которое будет определять режим запуска консольного приложения и метод для инициации процесса. Для своего класса я использовал паттерн Facade.

public  class CommandHelpers     {         public CommandHelpers()         {             Invisible = true;         }  public bool Invisible { get; set; }  private Process CreateProcess(string commandName, IEnumerable<string> paramsList, bool output = false)         {             string paramString = paramsList.Aggregate<string, string>(null,                 (current, param) => current + " " + param);             return new Process             {                 StartInfo =                 {                     FileName = commandName,                     Arguments = paramString,                     UseShellExecute = output ? !output : !Invisible,                      RedirectStandardOutput = output                 }             };         } 

Необходимо учесть, что запускаемое приложение может работать бесконечно долго, например, ping –t youwebsite.org. Для его запуска нам потребуется соответствующий метод:

public Task<bool> ExecuteAsync(string commandName, IEnumerable<string> paramsList) 

Исходный код:

Пример использования:

public class CspHelpers     {         private readonly CommandHelpers _cryptoconsole;         private readonly string _command = @"c:\Program Files\Crypto Pro\CSP\csptest";          public CspHelpers()         {             _cryptoconsole = new CommandHelpers();         }         /// <summary>         /// Импорт сертификата в контейнер         /// </summary>         /// <param name="driveName">Имя сменного носителя</param>         /// <param name="containerName">Имя контейнера</param>         /// <param name="type">Тип импортируемого серификата exchange или signature</param>         /// <param name="certPath">Полный путь до сертификата</param>         /// <param name="password">Пароль на контейнер</param>         /// <returns>Сведения о выполнении</returns>         public string ImportToContainer(string driveName, int containerName, KeyType type, string certPath,             string password)         {             var Params = new List<string>();             Params.Add("-keyset");             Params.Add("-container");             Params.Add(string.Format(@"\\.\FAT12_{0}\{1}", driveName[0], containerName));             Params.Add("-password");             Params.Add(password);             Params.Add("-keytype");             Params.Add(type.ToString());             Params.Add("-impcert");             Params.Add(certPath);             return _cryptoconsole.GetResult(_command, Params);         }     }  

CommandHelpers.cs

using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks;  namespace Common.Security {     /// <summary>     ///     See for correct use https://technet.microsoft.com/en-us/library/bb491070.aspx     /// </summary>     public class CommandHelpers     {         public CommandHelpers()         {             Invisible = true;         }          /// <summary>         ///     Not show CMD window         /// </summary>         public bool Invisible { get; set; }          /// <summary>         ///     Execete CMD command         /// </summary>         /// <param name="commandName">Command name only</param>         /// <param name="paramsList">Params and keys for command</param>         public bool Execute(string commandName, IEnumerable<string> paramsList)         {             return CreateProcess(commandName, paramsList).Start();         }          /// <summary>         ///     Async execete CMD command         /// </summary>         /// <param name="commandName">Command name only</param>         /// <param name="paramsList">Params and keys for command</param>         public Task<bool> ExecuteAsync(string commandName, IEnumerable<string> paramsList)         {             return Task<bool>.Factory.StartNew(() => CreateProcess(commandName, paramsList).Start());         }          /// <summary>         ///     Returns result of command execution         /// </summary>         /// <param name="commandName">Command name only</param>         /// <param name="paramsList">Params and keys for command</param>         /// <returns></returns>         public string GetResult(string commandName, IEnumerable<string> paramsList)         {             var bufer = new StringBuilder();             using (var proc = CreateProcess(commandName, paramsList, true))             {                 proc.Start();                 while (!proc.StandardOutput.EndOfStream)                 {                     bufer.AppendLine(proc.StandardOutput.ReadLine());                 }             }             return bufer.ToString();         }          /// <summary>         ///     Returns result of command execution         ///     Experemental. Not Tested.         /// </summary>         /// <param name="commandName">Command name only</param>         /// <param name="paramsList">Params and keys for command</param>         /// <returns></returns>         public string GetResultAsync(string commandName, IEnumerable<string> paramsList)         {             var bufer = new StringBuilder();             using (var proc = CreateProcess(commandName, paramsList, true))             {                 proc.OutputDataReceived += (sender, e) =>                 {                     if (!string.IsNullOrEmpty(e.Data))                     {                         bufer.AppendLine(e.Data);                     }                 };                 proc.BeginOutputReadLine();                 proc.EnableRaisingEvents = true;                 proc.WaitForExit();             }             return bufer.ToString();         }           private Process CreateProcess(string commandName, IEnumerable<string> paramsList, bool output = false)         {             var paramString = paramsList.Aggregate<string, string>(null,                 (current, param) => current + " " + param);             return new Process             {                 StartInfo =                 {                     FileName = commandName,                     Arguments = paramString,                     UseShellExecute = output ? !output : !Invisible,                     RedirectStandardOutput = output                 }             };         }     } } 

UPD:

Дополнительные материалы:

Источник вдохновения для статьи:
От пользователя vedmaka: toster.ru/q/7644

GUI обертка для консольного приложения: ru.jakeroid.com/gui-obertka-dlya-konsolnogo-prilozheniya-na-csharp.html

От пользователя evgenyl: habrahabr.ru/post/136766

ссылка на оригинал статьи https://habrahabr.ru/post/276443/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *