【问题标题】:C# - User Settings brokenC# - 用户设置损坏
【发布时间】:2011-01-17 04:33:22
【问题描述】:

我们在读取标准 .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 文件的完整路径吗?

【问题讨论】:

    标签: c# .net settings application-settings


    【解决方案1】:

    这是一个不需要您退出应用程序并感谢 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 读取文件,这样系统的版本就不会进入错误状态。

    【讨论】:

    • FileWatcher 有什么用??我认为删除文件在删除之前不会返回
    • 你会感到惊讶
    【解决方案2】:

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

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

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

    【讨论】:

    • 如何获取用户设置文件的路径?数据库对于我的场景来说太过分了。
    • 请注意,System.Configuration.ConfigurationErrorsException 类型的 InnerException 具有 Filename 属性...
    • string filename = ((ConfigurationErrorsException)e.InnerException).Filename; 应该这样做。
    • 在删除文件后调用 Reset() 会导致同样的异常抛出。删除配置文件后,您必须重新启动应用程序。详情在这里:connect.microsoft.com/VisualStudio/feedback/details/497189/…
    • 重启应用不是很好...想知道是否可以修复
    【解决方案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();
        }
    }
    

    【讨论】:

    • 这正是我所做的,只是我将我的应用程序作为一个新进程重新运行而不是退出。
    猜你喜欢
    • 1970-01-01
    • 2011-12-03
    • 2011-08-03
    • 1970-01-01
    • 2015-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多