У меня есть документ settings.xml
, совместно используемый двумя процессами, службой локальной системы и приложением WinForms. Доступ к документу контролируется мьютексом. Оба приложения читают и обновляют файл xml при запуске.
Если во время тестирования я перезапущу тестовый компьютер, чтобы служба автоматически запускалась, а пользовательское приложение запускалось из папки автозагрузки, служба выдает следующее исключение примерно в 10–20 % тестовых прогонов:
Exception Data:
Exception Type: System.InvalidOperationException
Message: There is an error in XML document (0, 0).
Source: System.Xml
Method: System.Object Deserialize(System.Xml.XmlReader, System.String, System.Xml.Serialization.XmlDeserializationEvents)
Stack Trace:
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader)
at lib.ServiceSettings.ReadFromFile() in ServiceSettings.cs:line 107
at svc.SystemService.settingsFile_Changed(Object sender, FileSystemEventArgs e) in Settings.cs:line 152
------------------
InnerException Data:
Exception Type: System.Xml.XmlException
Message: Root element is missing.
Source: System.Xml
Method: Void Throw(System.Exception)
Stack Trace:
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlReader.MoveToContent()
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderServiceSettings.Read4_ServiceSettings()
Это состояние гонки, но я не могу дублировать его во время отладки. Оба приложения используют метод static
из класса ServiceSettings
для чтения файла настроек:
public static ServiceSettings ReadFromFile()
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(ServiceSettings), ServiceConstants.defaultXmlNamespace);
using (FileStream fileStream = new FileStream(ServiceConstants.defaultFileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
using (XmlReader xmlReader = XmlReader.Create(fileStream))
{
return (ServiceSettings)xmlSerializer.Deserialize(xmlReader); // line 107 exception thrown
}
}
}
А стек вызовов указывает на событие FileSystemWatcher.Changed
, при котором файл настроек снова считывается — в данном случае после того, как файл был обновлен пользовательским приложением.
private void settingsFile_Changed(object sender, FileSystemEventArgs e)
{
settingsMutex.WaitOne();
try
{
settings = ServiceSettings.ReadFromFile(); // line 152 exception thrown
}
catch (InvalidOperationException ex)
{
LogExceptionData(ex);
throw;
}
settingsMutex.ReleaseMutex();
}
Когда я просматриваю документ xml, форматирование выглядит так, как ожидалось:
<?xml version="1.0" encoding="UTF-8"?>
<ServiceSettings xmlns="svc.settings">
...
</ServiceSettings>
Я не вижу, что здесь может быть не так. У меня есть подозрение, что это может быть связано с тем, что я использую объект FileStream
, но я не могу понять этого. У кого-нибудь есть подсказки для меня? Заранее спасибо!
Редактировать
Мьютекс создается одинаковым образом для обоих приложений:
private static Mutex settingsMutex = null;
private void InitialiseSettings()
{
settingsMutex = new Mutex(false, ServiceConstants.mutexName);
...
Где класс ServiceConstants
определен в разделяемой библиотеке со статической строкой для имени мьютекса:
public class ServiceConstants
{
public const string mutexName = "svc.settings.mutex";
...
Правильно ли это для создания мьютекса на уровне машины?
"Global\"
к имени вашего мьютекса решило вашу проблему. Если да, то этот вопрос следует закрыть как дубликат вопроса, предложенного комментатором @AlexeiLevenkov. - person Peter Duniho   schedule 31.10.2015