0

我有一个使用线程运行一系列插件的程序。在此过程中,它将插件的运行时写入 XDocument,以便程序知道自上次运行该插件以来已经过去了多长时间。不过我有问题。大约每天一次(在不可预测的时间)当我加载 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.

我运行了一些跟踪语句,发现在此之前的时间,服务失败,大约有 44 个插件要运行,这显然导致 XDocument 在没有写入文件末尾的情况下关闭。它写入和读取硬盘上的 XML 文件,但它对内存中的 XDocument 执行所有操作,因为我使用 Linq 对数据执行复杂的操作。

有谁知道为什么会发生这种情况?如何加载我的 XDocument,以便在运行过程中发生某些事情时它不会破坏实际文件?

编辑:这是使用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;
    }

问题是一个或多个插件没有正确处理错误,导致它不返回任何响应并使程序崩溃。

4

1 回答 1

1

要在不解析整个内容并将其加载到内存的情况下读取 XML 文件,您可以XmlReader使用. 然后要编写 XML 文件,可以使用XmlWriter. 相应的 MSDN 页面上有一些示例。

但是,您将失去 LINQ 的所有优点,并且它的工作方式大不相同。真的没有办法将 LINQ 的优点与XDocument仅在磁盘上处理 XML 文件相结合。

然后,当您的服务崩溃时,您XmlWriter可能仍然没有得到处理,没有将其缓冲区刷新到磁盘并留下一个不完整的 XML 文件。您应该解决导致服务崩溃的错误。

于 2013-04-02T15:03:46.723 回答