Ошибка записи в один файл в веб-сервисе в .NET - PullRequest
6 голосов
/ 23 сентября 2008

Я создал веб-сервис в .net 2.0, C #. Мне нужно записывать некоторую информацию в файл всякий раз, когда клиенты веб-службы вызывают разные методы.

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

Процесс не может получить доступ к файлу, поскольку он используется другим процессом.

Решения, которые я попытался реализовать в C # и потерпели неудачу, перечислены ниже.

  1. Реализован одноэлементный класс, содержащий код для записи в файл.
  2. Использовал оператор блокировки для переноса кода, записывающего в файл.
  3. Я также пытался использовать log4net с открытым исходным кодом, но это также не идеальное решение.
  4. Я знаю о входе в системный журнал событий, но у меня нет такого выбора.

Я хочу знать, существует ли идеальное и полное решение такой проблемы?

Ответы [ 11 ]

10 голосов
/ 23 сентября 2008

Возможно, блокировка не удалась, потому что ваш веб-сервис выполняется более чем одним рабочим процессом. Вы можете защитить доступ с помощью именованного мьютекса, который используется всеми процессами, в отличие от блокировок, которые вы получаете, используя lock(someobject) {...}:

Mutex lock = new Mutex("mymutex", false);

lock.WaitOne();

// access file

lock.ReleaseMutex();
1 голос
/ 23 сентября 2008

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

Думаю, я бы выбрал решение, которое вы предлагаете себе, Прадип, создать один объект, который выполняет всю запись в файл журнала. Внутри этого объекта у меня будет Очередь, в которую записываются все данные для регистрации. Я бы хотел отдельный поток, читающий из этой очереди и записывающий в файл журнала. В хостинговой среде с пулами потоков, такой как IIS, кажется, не слишком приятно создавать другой поток, но он только один ... Имейте в виду, что очередь в памяти не переживет перезагрузки IIS; Вы можете потерять некоторые записи, которые «в полете», когда процесс IIS останавливается.

Другие альтернативы, безусловно, включают использование отдельного процесса (например, службы) для записи в файл, но это требует дополнительных затрат на развертывание и затрат на IPC. Если это не сработает, поезжайте с синглтоном.

0 голосов
/ 24 сентября 2008

Джоэл: Когда вы говорите «очередь», вы означает создание отдельной темы, которая работает в цикле, чтобы продолжать проверять очереди, а также записать в файл, когда он не заблокирован?

Да, это в основном то, о чем я думал. Создайте другой поток с циклом while, пока он не сможет получить доступ к файлу и сохранить его, а затем завершить.

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

0 голосов
/ 23 сентября 2008

Будет ждать освобождения мьютекса ....

0 голосов
/ 23 сентября 2008

Koth,

Я реализовал блокировку Mutex, которая устранила ошибку «переполнение стека». Мне еще предстоит провести нагрузочное тестирование, прежде чем я смогу сделать вывод, работает ли он нормально во всех случаях.

Я читал об объектах Mutex на одном из веб-сайтов, где говорится, что Mutex влияет на производительность. Я хочу знать одну вещь, поставив блокировку через Mutex.

Предположим, что пользовательский процесс1 выполняет запись в файл, и в то же время пользовательский процесс2 пытается выполнить запись в тот же файл. Поскольку Process1 установил блокировку для блока кода, Process2 будет продолжать пытаться или просто умрет после первой попытки итерации .?

спасибо pradeep_tp

0 голосов
/ 23 сентября 2008

В качестве альтернативы, вы можете захотеть войти в базу данных об ошибках (если вы ее используете)

0 голосов
/ 23 сентября 2008

Чтобы узнать, что я пытаюсь сделать в своем коде, ниже приведен класс-одиночка, который я реализовал в C #

открытый закрытый класс FileWriteTest {

private static volatile FileWriteTest instance;

private static object syncRoot = new Object();

private static Queue logMessages = new Queue();

private static ErrorLogger oNetLogger = new ErrorLogger();

private FileWriteTest() { }

public static FileWriteTest Instance
{
    get
    {
        if (instance == null)
        {
            lock (syncRoot)
            {
                if (instance == null)
                {
                    instance = new FileWriteTest();
                    Thread MyThread = new Thread(new ThreadStart(StartCollectingLogs));
                    MyThread.Start();

                }
            }
        }

        return instance;
    }
}

private static void StartCollectingLogs()
{

    //Infinite loop
    while (true)
    {
        cdoLogMessage objMessage = new cdoLogMessage();
        if (logMessages.Count != 0)
        {
            objMessage = (cdoLogMessage)logMessages.Dequeue();
            oNetLogger.WriteLog(objMessage.LogText, objMessage.SeverityLevel);

        }
    }
}

public void WriteLog(string logText, SeverityLevel errorSeverity)
{
    cdoLogMessage objMessage = new cdoLogMessage();
    objMessage.LogText = logText;
    objMessage.SeverityLevel = errorSeverity;
    logMessages.Enqueue(objMessage);

}

}

Когда я запускаю этот код в режиме отладки (имитирует доступ только одного пользователя), я получаю сообщение об ошибке «переполнение стека» в строке, где очередь исключена.

Примечание. В приведенном выше коде ErrorLogger - это класс, в котором есть код для записи в файл. objMessage - это класс сущностей для переноса сообщения журнала.

0 голосов
/ 23 сентября 2008

Проблема всех приближенных попыток состоит в том, что несколько потоков могут вводить код. То есть несколько потоков пытаются получить и использовать обработчик файлов - отсюда и ошибки - вам нужен один поток вне рабочих потоков для выполнения работы - с открытым дескриптором файла.

Вероятно, проще всего было бы создать поток во время запуска приложения в Global.asax и прослушать синхронизированную очередь в памяти (System.Collections.Generics.Queue). Пусть поток открыт и принадлежит время жизни дескриптора файла, только этот поток может записывать в файл.

Клиентские запросы в ASP на мгновение блокируют очередь, помещают новое сообщение регистрации в очередь, затем разблокируют.

Поток регистратора будет периодически опрашивать очередь на наличие новых сообщений - когда сообщения поступают в очередь, поток считывает и отправляет данные в файл.

0 голосов
/ 23 сентября 2008

Джоэл и Чарльз. Это было быстро! :)

Джоэл: Когда вы говорите «линия очереди», вы имеете в виду создание отдельного потока, который запускается в цикле для проверки очереди, а также записи в файл, когда он не заблокирован?

Чарльз: Я знаю о комбинации служб MSMQ и Windows, но, как я уже сказал, у меня нет другого выбора, кроме записи в файл из веб-службы:)

спасибо pradeep_tp

0 голосов
/ 23 сентября 2008

Вы можете поместить результаты в очередь MSMQ, и служба Windows выберет элементы из очереди и зарегистрирует их. Это немного тяжело, но должно работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...