Ошибка во время выполнения .Net, останавливающая службу; Необработанное исключение ввода-вывода

#c# #.net #windows-services

#c# #.net #windows-services

Вопрос:

Мне было поручено обновить службу, которая считывает текстовый файл и создает PDF-файлы из разделов текстового файла и отправляет PDF-файлы по электронной почте. Недавно я внес некоторые изменения в службу и использовал .Net 4.0 Framework. При обновлении на сервере была установлена платформа 4.0, прежде чем я смог переместить свои файлы и успешно запустить службу — ранее она использовала 2.0. Служба выполняется до тех пор, пока не достигнет кода, который пытается очистить каталог с файлами pdf. Служба останавливается, когда код пытается удалить файл pdf, который «используется другим процессом». Код ищет это исключение и должен подождать около 30 секунд и повторить попытку удаления. Локально я запускаю эту службу через тестовый жгут, и она выполняется до тех пор, пока файл не станет доступен для удаления (в среднем это занимает около 5 минут), но на сервере служба останавливается с необработанным исключением IOException, найденным в журнале событий приложения. Я не понимаю, почему он продолжит обработку локально, но не на сервере. Любые идеи или другая информация были бы высоко оценены.

Вот ошибка в журнале событий:

Процесс был завершен из-за необработанного исключения.

Информация об исключении: System.IO.IOException Stack: при System.IO.__Error.Ошибка WinIOError (Int32, System.Строка) в системе.Консоль.GetBufferInfo(логическое значение, Boolean ByRef) в processorName.FileProcessingThread.CleanUpDirectory (System.Объект) в системе.Многопоточность.ThreadHelper.ThreadStart_Context (система.Объект) в системе.Многопоточность.ExecutionContext.Run (Система.Многопоточность.ExecutionContext, System.Многопоточность.ContextCallback, система.Объект, логическое значение) в системе.Многопоточность.ExecutionContext.Run (Система.Многопоточность.ExecutionContext, System.Многопоточность.ContextCallback, система.Объект) в системе.Многопоточность.ThreadHelper.ThreadStart (система.Объект)

Также эта ошибка появляется в журнале событий:

Тип события clr20r3, P1 myServiceName.exe, P2 1.0.1.0, P3 4db6e85d, P4 mscorlib, P5 4.0.0.0, P6 4d53693b, P7 3dab, P8 23b, P9 исключение system.io.ioexception, P10 НОЛЬ.

Вот код, который должен обрабатывать исключение, подождите и повторите попытку удаления файлов.

 while (!isDone)
{
    bool myRetVal = true;
    string myErrorMsg = String.Empty;
    string myFile = String.Empty;
    //give it time to finish processing
    Thread.Sleep(30 * 1000);
    //
    //delete Files in folder
    foreach (string file in Directory.GetFiles(myDirectory, "*.PDF"))
    {  //delete all the *.PDF files
        try
        {
            File.Delete(file);
        }
        catch (Exception ex)
        {
            myErrorMsg = "...rn"   ex.Message;
            m_Log.Writeline("Unable to delete "  file   ". MESSAGE:"  myErrorMsg,3);
            myFile = file;
            myRetVal = false;
        }
    }
    //
    //now move the in-progress File to the processed directory
    if (myRetVal)
    {
        foreach (string file in Directory.GetFiles(myDirectory, "*.InProgress"))
        {
            try
            {
                if (File.Exists(m_ConfigFile.ProcessedFolderName   Path.GetFileNameWithoutExtension(file)   ".done"))
                {
                    File.Delete(file);
                }
                else
                {
                    File.Move(file, m_ConfigFile.ProcessedFolderName   Path.GetFileNameWithoutExtension(file)   ".done");
                }
            }
            catch (Exception ex)
            {
                if (ex.Message.Contains("file already exists"))
                {

                }
                else
                {
                    myErrorMsg = "...rn"   ex.Message;
                    myFile = file;
                    myRetVal = false;
                }
            }
        }
    }
    //
    //if empty, delete the SendMailFolder subfolder
    if (myRetVal)
    {
        try
        {
            if (Directory.GetFiles(myDirectory, "*.*").Length == 0) Directory.Delete(myDirectory);
        }
        catch (Exception ex)
        {
            myErrorMsg = "...rn"   ex.Message;
            myFile = myDirectory;
            myRetVal = false;
        }
    }

    if (Console.CursorLeft > 0) Console.WriteLine("rn");

    if (myRetVal)
    {
        Console.WriteLine(DateTime.Now.ToLocalTime()   " CleanUp SendMailFolder...Done");
        isDone = true;
    }
    else
    {
        if (myErrorMsg.Contains("is being used by another process."))
        {
            myErrorMsg = " is still in use.";
            Console.WriteLine(DateTime.Now.ToLocalTime()   " CleanUp SendMailFolder..."   Path.GetFileName(myFile)   myErrorMsg);
        }
        else
        {
            Console.WriteLine(DateTime.Now.ToLocalTime()   " CleanUp SendMailFolder..."   Path.GetFileName(myFile)   myErrorMsg);
            m_Log.Writeline(DateTime.Now.ToLocalTime()   " CleanUp SendMailFolder..."   Path.GetFileName(myFile)   myErrorMsg, 3);
            isDone = true;
        }
    }
}
  

Ответ №1:

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

ОТРЕДАКТИРУЙТЕ, чтобы уточнить:

Вы можете создать окно консоли вручную с помощью AllocConsole вызова P / Invoke, если вам это абсолютно необходимо. По умолчанию служба не взаимодействует с вашим рабочим столом, поэтому создание окна консоли было бы плохой идеей. Для того, чтобы это сработало, вам необходимо настроить службу с включенным параметром «Разрешить службе взаимодействовать с рабочим столом». Это имеет последствия для безопасности, особенно для компьютеров с несколькими пользователями, поэтому я бы не советовал этого делать.

Комментарии:

1. Является ли это причиной ошибки? Я также не понимаю, почему это было написано с помощью консоли, и я не думаю, что это необходимо, поскольку некоторые из входов в службу уже записываются в файл журнала.

2. 1. Обратите внимание на трассировку исключения: at System.Console.GetBufferInfo(Boolean, Boolean ByRef) Проблема заключается в использовании консоли, которая не взаимодействует с файлами. Я бы удалил или изменил вызовы на Console.CursorLeft и Console.WriteLine

Ответ №2:

Похоже, что ошибка возникает до того, как вы попытаетесь поймать. Учитывая, что вы должны увидеть конкретное сообщение, выводимое вашим протоколированием (я предполагаю, что оно попадает в журнал событий). Я не вижу сообщения, похожего на то, что есть в вашем журнале. Возможно, вам захочется иметь обработчик исключений домена приложения для перехвата любых исключений и их регистрации.

Комментарии:

1. Ведение журнала в коде выполняется в файл или на консоль (что я могу видеть при локальном тестировании через мой жгут). Журналы и содержимое каталога указывают на тот факт, что файлы pdf удаляются до тех пор, пока код не достигнет того, который все еще используется (и каким процессом используется, я понятия не имею), поэтому из каталога удалены файлы, а основной текстовый файл все еще там с . Расширение InProgress, которое означает, что оно никогда не перемещается в обработанный каталог. Разве я не должен получать исключение при локальном тестировании, если оно находится за пределами моего try catch?

2. Не уверен. Если каталог не существует на сервере, то что-то еще может дать сбой и вызвать исключение IOException. Вот почему я думаю, что вы видите что-то за пределами вашего кода.

Ответ №3:

Также вы должны убедиться, что ваша процедура m_log имеет надлежащую обработку ошибок, поскольку это также может быть причиной.