我在两个进程,本地系统服务和WinForms应用程序之间共享了一个settings.xml
文档。对文档的访问由互斥锁控制。两个应用程序都在启动时读取并更新xml文件。
在测试期间,如果我重新启动测试计算机以使服务自动启动并且User App从Startup文件夹启动,服务会在大约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";
...
创建机器范围的互斥锁是否正确?