13

我们在读取标准 .Net 用户设置时发生了一个罕见的异常(这是在 VS 2008 的“项目属性”中找到的设置):

System.Configuration.ConfigurationErrorsException was caught
  Message="Configuration system failed to initialize"
  Source="System.Configuration"
  BareMessage="Configuration system failed to initialize"
  Line=0
  StackTrace:
       at System.Configuration.ConfigurationManager.PrepareConfigSystem()
       at System.Configuration.ConfigurationManager.GetSection(String sectionName)
       at System.Configuration.PrivilegedConfigurationManager.GetSection(String sectionName)
       at System.Diagnostics.DiagnosticsConfiguration.GetConfigSection()
       at System.Diagnostics.DiagnosticsConfiguration.Initialize()
       at System.Diagnostics.DiagnosticsConfiguration.get_IndentSize()
       at System.Diagnostics.TraceInternal.InitializeSettings()
       at System.Diagnostics.TraceInternal.get_Listeners()
  InnerException: System.Configuration.ConfigurationErrorsException
       Message="Unexpected end of file has occurred. The following elements are not closed: setting, SettingsTest.Properties.Settings, userSettings, configuration. Line 7, position 1. (C:\\Documents and Settings\\USER\\Local Settings\\Application Data\\Hitcents\\SettingsTest.vshost.exe_Url_ghwhc20utv4toanuinmj0pfsljthcugo\\1.0.0.0\\user.config line 7)"
       Source="System.Configuration"
       BareMessage="Unexpected end of file has occurred. The following elements are not closed: setting, SettingsTest.Properties.Settings, userSettings, configuration. Line 7, position 1."
       Filename="C:\\Documents and Settings\\USER\\Local Settings\\Application Data\\Hitcents\\SettingsTest.vshost.exe_Url_ghwhc20utv4toanuinmj0pfsljthcugo\\1.0.0.0\\user.config"
       Line=7
       StackTrace:
            at System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean ignoreLocal)
            at System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(ConfigurationSchemaErrors schemaErrors)
            at System.Configuration.BaseConfigurationRecord.ThrowIfInitErrors()
            at System.Configuration.ClientConfigurationSystem.OnConfigRemoved(Object sender, InternalConfigEventArgs e)
       InnerException: System.Xml.XmlException
            Message="Unexpected end of file has occurred. The following elements are not closed: setting, SettingsTest.Properties.Settings, userSettings, configuration. Line 7, position 1."
            Source="System.Xml"
            LineNumber=7
            LinePosition=1
            SourceUri=""
            StackTrace:
                 at System.Xml.XmlTextReaderImpl.Throw(Exception e)
                 at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
                 at System.Xml.XmlTextReaderImpl.Throw(Int32 pos, String res, String arg)
                 at System.Xml.XmlTextReaderImpl.ThrowUnclosedElements()
                 at System.Xml.XmlTextReaderImpl.ParseElementContent()
                 at System.Xml.XmlTextReaderImpl.Read()
                 at System.Xml.XmlTextReader.Read()
                 at System.Xml.XmlTextReaderImpl.Skip()
                 at System.Xml.XmlTextReader.Skip()
                 at System.Configuration.XmlUtil.StrictSkipToNextElement(ExceptionAction action)
                 at System.Configuration.BaseConfigurationRecord.ScanSectionsRecursive(XmlUtil xmlUtil, String parentConfigKey, Boolean inLocation, String locationSubPath, OverrideModeSetting overrideMode, Boolean skipInChildApps)
                 at System.Configuration.BaseConfigurationRecord.ScanSectionsRecursive(XmlUtil xmlUtil, String parentConfigKey, Boolean inLocation, String locationSubPath, OverrideModeSetting overrideMode, Boolean skipInChildApps)
                 at System.Configuration.BaseConfigurationRecord.ScanSections(XmlUtil xmlUtil)
                 at System.Configuration.BaseConfigurationRecord.InitConfigFromFile()
            InnerException: 

*注意:这是从测试应用程序重新创建的。

我调出 user.config 文件,其中一半丢失了。

我希望我们的应用程序由于某种原因突然终止。

这似乎非常罕见,这是我们与设置交互的方式:

//How we read
Settings settings = Settings.Default;
_ourStaticMemberVariable = settings.OurValue;

//How we save
Settings settings = Settings.Default;
settings.OurValue = "Our Value";
settings.Save();

我们使用它的方式有什么问题吗?两个调用都有一个 try-catch 来放置一些默认值,但是这些值需要能够从我们的应用程序中重置。

在这种状态下,我们的应用程序无法保存新设置——而且我想不出一种以编程方式恢复的好方法。我不得不手动找到 user.config 并将其删除。

我也尝试调用 Settings.Reset() 等,但得到相同的异常。

有想法该怎么解决这个吗?还是我们最好编写自己的设置系统或以其他方式保存持久设置?

编辑:如果您收到 ConfigurationErrorsException,解决方法是从代码中删除文件。

有人知道如何获取 user.config 文件的完整路径吗?

4

3 回答 3

16

这是一个不需要您退出应用程序并感谢 Jarle 的解决方案(http://www.codeproject.com/Articles/30216/Handling-Corrupt-user-config-Settings?msg=3608682#xx3608682xx)。早期,在设置被调用之前,使用这个

    public static bool CheckSettings()
    {
        var isReset = false;

        try
        {
            ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
        }
        catch (ConfigurationErrorsException ex)
        {
            string filename = string.Empty;
            if (!string.IsNullOrEmpty(ex.Filename))
            {
                filename = ex.Filename;
            }
            else
            {
                var innerEx = ex.InnerException as ConfigurationErrorsException;
                if (innerEx != null && !string.IsNullOrEmpty(innerEx.Filename))
                {
                    filename = innerEx.Filename;
                }                   
            }

            if (!string.IsNullOrEmpty(filename))
            {
                if (System.IO.File.Exists(filename))
                {
                    var fileInfo = new System.IO.FileInfo(filename);
                    var watcher
                         = new System.IO.FileSystemWatcher(fileInfo.Directory.FullName, fileInfo.Name);
                    System.IO.File.Delete(filename);
                    isReset = true;
                    if (System.IO.File.Exists(filename))
                    {
                        watcher.WaitForChanged(System.IO.WatcherChangeTypes.Deleted);
                    }
                }
            }
        }

        return isReset;
    }

本质上,与其依赖 Sittings 抛出错误,不如使用 ConfigurationManager 读取文件,这样系统的版本就不会进入错误状态。

于 2013-09-19T22:12:39.847 回答
11

以编程方式恢复的方法是手动执行 - 删除用户设置文件。 然后调用Settings.Reset。(您也可以使用默认值编写一个新的用户设置文件,而不是删除它,但如果您正确使用配置管理器,这本质上是一样的。)

这是非常罕见的情况,但并非完全闻所未闻。不仅您的程序在写入用户设置文件时会崩溃,而且文件本身是用户可写的,因此用户运行的其他程序可能会弄乱它。

为避免此特定漏洞,请将用户设置保存在具有事务完整性的持久存储(即数据库)中。(您仍然会有漏洞,只是没有这个漏洞。)这需要做很多工作,因为在大多数情况下,可靠性会略有提高。但“在大多数情况下”并不意味着“在所有情况下”;你的可能会保证。

于 2010-02-15T23:54:27.117 回答
3
[STAThread]
private static void Main(string[] args)
{
    try
    {
        // ...
    }
    catch (System.Configuration.ConfigurationErrorsException ex)
    {   
        var config = ((System.Configuration.ConfigurationErrorsException)ex.InnerException).Filename;
        // notify user, ask them to restart
        System.IO.File.Delete(config);
        Application.Exit();
    }
}
于 2011-09-20T22:57:40.053 回答