简体   繁体   English

为什么我的XDocument保存的文件不完整?

[英]Why is my XDocument saving an incomplete file?

I have a program that runs a series of plugins using threads. 我有一个使用线程运行一系列插件的程序。 During this process, it writes the runtimes of the plugins to an XDocument so that the program knows how long it's been since the last time that plugin was run. 在此过程中,它将插件的运行时写入XDocument,以便程序知道自上次运行该插件以来已经有多长时间了。 I'm having a problem, though. 不过,我遇到了问题。 About once per day (at unpredictable times) when I load the XDocument I get the following error: 加载XDocument时,大约每天(在不可预测的时间)一次,会出现以下错误:

[04/01/2013 08:17:10.083] Unexpected end of file has occurred. The following elements are not closed: Database, DatabaseList. Line 4043, position 1.

I ran some trace statements and found out that the time before that, the service failed with about 44 plugins left to run, which apparently caused the XDocument to close without writing the end of the file. 我运行了一些跟踪语句,发现在此之前,该服务失败,剩下大约44个插件无法运行,这显然导致XDocument在关闭时未写入文件末尾。 It writes to and reads from an XML file on the hard disk, but it performs all operations on the XDocument in memory because I use Linq to do complex operations on the data. 它可以读写硬盘上的XML文件,但是可以在内存中的XDocument上执行所有操作,因为我使用Linq对数据进行复杂的操作。

Does anybody know why this might happen? 有人知道为什么会发生这种情况吗? How can I load my XDocument so that it won't wreck the actual file if something happens during the running process? 我如何加载我的XDocument,以便在运行过程中发生某些事情时,它不会破坏实际文件?

EDIT: Here's a sample of the code that utilizes the XDocument (named XDoc ): 编辑:这是利用XDocument (名为XDoc )的代码示例:

    private void RunPlugin(object oQueuedPlugin)
    {
        PluginState oPluginState = (PluginState)oQueuedPlugin;
        PluginResponse oResponse = new PluginResponse();
        XElement xPlugin;

        lock (xDoc)
        {
            xPlugin = GetPluginNode(oPluginState.ClientFusionDatabase.Name, oPluginState.Plugin.Name);
        }

        if (xPlugin == null)
        {
            API.Log.Write("ActivityTrace.ShowXMLLog", "XML for " + oPluginState.ClientFusionDatabase.Name + " was null.");
            XElement NewPlugin = new XElement("Plugin",
                new XAttribute("PluginName", oPluginState.Plugin.Name),
                new XAttribute("Running", "true"),
                new XAttribute("LastStart", DateTime.Now.ToString()),
                new XAttribute("LastSuccess", ""),
                new XAttribute("LastExitStatus",""));

            lock (xDoc)
            {
                var Location = from database in xDoc.Root.Elements("Database")
                               where database.Attribute("DatabaseName").Value == oPluginState.ClientFusionDatabase.Name
                               select database;

                Location.FirstOrDefault().Add(NewPlugin);
                xDoc.Save(XmlLogFilePath);
            }

            oResponse = oPluginState.Plugin.Run(oPluginState.ClientFusionDatabase);
            if (oResponse == null)
            {
                API.Log.Write("ActivityTrace.ShowNullReturnLog", oPluginState.ClientFusionDatabase.Name + "- " + oPluginState.Plugin.Name + " returned null.");
            }

            lock (xDoc)
            {
                NewPlugin.Attribute("Running").Value = "false";
                NewPlugin.Attribute("LastExitStatus").Value = oResponse.ResponseType.ToString();
                if (oResponse.ResponseType == PluginResponseTypes.Success || oResponse.ResponseType == PluginResponseTypes.Warning)
                    NewPlugin.Attribute("LastSuccess").Value = DateTime.Now.ToString();
                xDoc.Save(XmlLogFilePath);
            }

            API.Log.Write("ActivityTrace.ShowXMLLog","Completed " + oPluginState.ClientFusionDatabase.Name + "- " + oPluginState.Plugin.Name + " with XML " + NewPlugin.ToString());
            API.Log.Write(oPluginState.Plugin.Name, "(" + oPluginState.ClientFusionDatabase.Connection.Database + " = " + (oResponse.ResponseType + ") ").PadRight(9) + "EXIT MESSAGE: " + (string.IsNullOrEmpty(oResponse.Message) ? "None" : oResponse.Message));
        }
        else
        {
            DateTime dLastRun = (DateTime)xPlugin.Attribute("LastStart");
            bool bRunning = (bool)xPlugin.Attribute("Running");

            if ((DateTime.Now - dLastRun) > oPluginState.Plugin.Interval && !bRunning)
            {
                lock (xDoc)
                {
                    xPlugin.Attribute("LastStart").Value = DateTime.Now.ToString();
                    xPlugin.Attribute("Running").Value = "true";
                    xDoc.Save(XmlLogFilePath);
                }
                oResponse = oPluginState.Plugin.Run(oPluginState.ClientFusionDatabase);

                lock (xDoc)
                {
                    xPlugin.Attribute("Running").Value = "false";
                    xPlugin.Attribute("LastExitStatus").Value = oResponse.ResponseType.ToString();
                    if (oResponse.ResponseType == PluginResponseTypes.Success || oResponse.ResponseType == PluginResponseTypes.Warning)
                        xPlugin.Attribute("LastSuccess").Value = DateTime.Now.ToString();
                    xDoc.Save(XmlLogFilePath);
                }

                API.Log.Write(oPluginState.Plugin.Name, "(" + oPluginState.ClientFusionDatabase.Connection.Database + " = " + (oResponse.ResponseType + ") ").PadRight(9) + "EXIT MESSAGE: " + (string.IsNullOrEmpty(oResponse.Message) ? "None" : oResponse.Message));
            }
            else if (bRunning)
                API.Log.Write(oPluginState.Plugin.Name, "(" + oPluginState.ClientFusionDatabase.Connection.Database + " = " + ("SKIPPED) ").PadRight(9) + "REASON: Plugin already running");
        }

        oPluginState.Complete = true;
    }

The problem is that one or more of the plugins is not handling an error correctly, which causes it to not return any response and crash the program. 问题是一个或多个插件未正确处理错误,这导致它不返回任何响应并使程序崩溃。

To read XML files without parsing the whole thing and loading it into memory, you can use the XmlReader class . 要读取XML文件而不分析整个内容并将其加载到内存中,可以使用XmlReader Then to write XML files, you can use the XmlWriter class . 然后,要编写XML文件,可以使用XmlWriter There are some examples on the respective MSDN pages. 在相应的MSDN页面上有一些示例。

However, you'll lose all benefits of LINQ and it works quite a bit differently. 但是,您将失去LINQ的所有好处,并且它的工作原理也大不相同。 There is really no way to combine the benefits of LINQ and XDocument while working on the XML files only on disk. 仅在磁盘上处理XML文件时,实际上没有办法结合LINQ和XDocument的优点。

And then when your service crashes, your XmlWriter might still not get disposed, not flushing its buffers to disk and leaving you still with an incomplete XML file. 然后,当您的服务崩溃时,您的XmlWriter可能仍然不会被处置,不会将其缓冲区刷新到磁盘上,并留下不完整的XML文件。 You should solve the bug that causes the service to crash instead. 您应该解决导致服务崩溃的错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM