2017-01-04 5 views
0

Я написал набор веб-сервисов с использованием Web Api 2. Они в конечном итоге вызывают программу CMD, которая запускает клиент OpenEdge Progress, передает форматированную XML-строку и затем вставляет записи в OpenEdge Progress базы данных, вызывая процедуру .p (WebSpeed ​​не является опцией).Дождитесь окончания файла

Файл .P имеет набор бизнес-логики для работы с приложением Progress. Затем он создает XML-файл по завершении, содержащий узел < Error>. Если этот узел пуст, значит, он сработал. Если файл не существует или узел содержит текст ... это не удалось. Затем я прочитал этот XML-файл и передал содержимое узла Error> < обратно клиенту в Web Api.

На данный момент существует статическая задержка в 10 секунд после вызова апплета CMD/Progress, попытки чтения XML-файла, чтобы дать серверу время запуска файла .P и создать указанный XML-файл. Однако это не очень удобно, и иногда клиенту возвращается ошибка, потому что он не может найти файл, но файл был создан через 1 секунду после того, как ответ был возвращен из-за ненормально высоких нагрузок сервера. В качестве альтернативы, люди вынуждены ждать 10 секунд, когда ответ может быть обработан через 2 секунды.

Мне нужно придумать способ «проверить, пока файл не существует», пока не истечет время ожидания. Я провел некоторое исследование и не нашел ничего подходящего для среды Web Api. У кого-нибудь есть предложения?

Код ниже - простите меня. Я очень многому научился, поскольку я шел и очень новичок в этом!

Контроллер

// the request date/time 
DateTime requestDate = DateTime.Now; 
// list of validation errors 
List<string> ohValidation = new List<string>(); 

...

WebExtensions.callInsertProgram(xml, "JOBLOG"); 
ohValidation =  XmlExtensions.ReadProgressXmlFileWithArray(job.logjob.placeref, requestDate, "joblogging"); 

CallInsertProgram

public static void callInsertProgram(string xml, string program) 
    { 

     try 
     { 
      using (Process p = new Process()) 
      { 
       p.StartInfo.FileName = @"C:\Rubixx\runProgress.exe"; 
       p.StartInfo.WorkingDirectory = @"C:\Rubixx"; 
       // stop windows from appearing on the server 
       p.StartInfo.UseShellExecute = false; 
       p.StartInfo.CreateNoWindow = true; 
       // set the arguments for running. The program name and xml are passed in as arguments 
       // wrapped in escaping "\" to stop spaces from being treated as a separator 
       p.StartInfo.Arguments = "\"" + program + "," + xml + "\""; 
       p.Start(); 
      } 
     } 
     catch (Exception e) 
     { 
      throw new OpenHousingException(e.Message.ToString()); 
     } 

    } 

ReadProgressXMLWithArray

public static List<string> ReadProgressXmlFileWithArray(string reference, DateTime requestDateTime, string folder) 
    { 
     // new empty list 
     List<string> output 
      = new List<string>(); 

     // wait X seconds before doing anything 
     // to ensure the XML file has time to be created 
     Delay_Start(fileDelay); 

     // 
     string filename = fullFileName(jobno, folder, requestDateTime); 
     string filepath = getFullFilepath(filename, folder); 
     if (checkXmlFileExists(filepath)) 
     { 
      // if so check for the existence of an error message 
      output = getXmlErrorArray(filepath); 
     } 
     else 
     { 
      // if no file is found - the call to Progress hasn't executed. So tell the end user. 
      throw new OpenHousingException("No OpenHousing file could be found"); 
     } 

     return output; 
    } 

Delay_Start

private static void Delay_Start(int Seconds) 
    { 
     DateTime StartTime; 
     DateTime EndTime; 

     StartTime = DateTime.Now; 
     EndTime = StartTime.AddSeconds(Seconds); 

     do 
     { StartTime = DateTime.Now; } while (StartTime < EndTime); 
    } 

FullFileName (необходимо, потому что я не могу быть уверен в XML файла, пока не создано. Формат файла - UniqueReference_DateTimeFileCreated.xml (xxxxxxxx_20160401-1100.xml) Итак, у меня есть подстановочный поиск в папке с уникальной ссылкой).

public static string fullFileName(string jobNo, string folder, DateTime createdDate) 
    { 
     string fileName = string.Empty; 
     string folderPath = fileLocation + folder; 
     DirectoryInfo dir = new DirectoryInfo(folderPath); 
     FileInfo[] files = dir.GetFiles(jobNo + "*", SearchOption.TopDirectoryOnly).Where(f => f.CreationTimeUtc > createdDate || f.LastWriteTimeUtc > createdDate).ToArray() ; 
     foreach (var item in files) 
     { 
      fileName = item.Name; 
     } 

     if (string.IsNullOrEmpty(fileName)) 
      throw new OpenHousingException("No OpenHousing file could be found"); 

     return fileName; 
    } 

GetFullFilePath (вероятно, может быть объединены в FullFileName)

private static string getFullFilepath(string filename, string folder) 
    { 
     return fileLocation + folder + @"\" + filename; 
    } 

CheckXMLFileExists

private static bool checkXmlFileExists(string filepath) 
    { 
     bool fileExists = false; 

     if (File.Exists(filepath)) 
     { 
      fileExists = true; 
     } 

     return fileExists; 
    } 

GetXMLErrorArray

private static List<string> getXmlErrorArray(string filepath) 
    { 

     List<string> output 
      = new List<string>(); 

     // read the text from XML file 
     using (TextReader txtReader = new StreamReader(filepath)) 
     { 
      XmlSerializer xs 
       = new XmlSerializer(typeof(JobError)); 

      // de-serialise the xml text 
      // to a strongly typed object 
      JobError result = (JobError)xs.Deserialize(txtReader); 

      // if the xml file contains an error - return it to the client 
      if (!string.IsNullOrEmpty(result.ErrorText)) 
       output.Add(result.ErrorText); 

      //check for SoR errors that are created under a different node 
      if (result.LineError != null) 
      { 
       List<LineError> lineErrs = result.LineError.ToList(); 

       foreach (LineError le in lineErrs) 
       { 
        output.Add(le.SorCode + ":" + le.Error); 
       } 
      } 
     } 

     return output; 

    } 
+1

Выполняет ли программа CMD синхронно или асинхронно? Если это синхронно, вы можете просто подождать, пока это закончится, а затем прочитайте выходной файл. Если это асинхронно, то самый простой подход - просто опросить файловую систему каждые 1 секунду, чтобы узнать, был ли еще создан файл: 'while (! File.Exists (« myfile.xml »)) {Thread.Sleep (1000); } ' –

+0

SignalR может помочь - https://www.asp.net/signalr или ручной опрос (HEAD-запрос) с фиксированными интервалами до тех пор, пока файл не будет доступен – Developer

+0

@Developer. Из его вопроса я думаю, что он нормально с клиентским вызовом синхронно ждет, пока файл доступен - он просто хочет, чтобы это было как можно быстрее и надежнее. ** Адам **: Можете ли вы это прояснить? –

ответ

0

OK - так что я думаю, что я усложнять в Prob Лем.

Вместо того, чтобы ждать, пока файл будет существовать, я добавил строку в свой метод CallInsertProgram, как показано ниже (как было предложено RB ...

public static void callInsertProgram(string xml, string program) 
{ 

    try 
    { 
     using (Process p = new Process()) 
     { 
      p.StartInfo.FileName = @"C:\Rubixx\runProgress.exe"; 
      p.StartInfo.WorkingDirectory = @"C:\Rubixx"; 
      // stop windows from appearing on the server 
      p.StartInfo.UseShellExecute = false; 
      p.StartInfo.CreateNoWindow = true; 
      // set the arguments for running. The program name and xml are passed in as arguments 
      // wrapped in escaping "\" to stop spaces from being treated as a separator 
      p.StartInfo.Arguments = "\"" + program + "," + xml + "\""; 
      p.Start(); 

      // ADDED 
      p.WaitForExit(60000); 
     } 
    } 
    catch (Exception e) 
    { 
     throw new OpenHousingException(e.Message.ToString()); 
    } 

} 

Это гарантирует, что CMD апплет Прогресс завершен, прежде чем перейти на следующую строку - и в этот момент будет уже создан XML (или нет, если это не удалось). Первоначальное тестирование работает хорошо. Может ли кто-нибудь предвидеть какие-либо проблемы с этим подходом?

+1

'throw new OpenHousingException (e.Message.ToString());' это отличная идея. вы теряете много информации, делая «throw new OpenHousingException» («callInsertProgram failed», e); 'передаст все исключение в качестве внутреннего исключения и сохранит информацию, такую ​​как трассировка стека, неповрежденной. –

Смежные вопросы