C # - пользовательские настройки не работают - PullRequest
10 голосов
/ 16 февраля 2010

У нас было редкое исключение при чтении стандартных пользовательских настроек .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?

Ответы [ 3 ]

14 голосов
/ 20 сентября 2013

Вот решение, которое не требует, чтобы вы выходили из приложения с благодарностью 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;
    }

По сути, вместо того, чтобы полагаться на результаты сеансов, читайте файл с помощью ConfigurationManager, чтобы версия системы никогда не переходила в плохое состояние.

11 голосов
/ 16 февраля 2010

Способ программного восстановления - сделать то, что вы сделали вручную - удалить файл настроек пользователя. Тогда позвоните Settings.Reset. (Вы также можете написать новый файл пользовательских настроек со значениями по умолчанию вместо того, чтобы удалять его, но если вы правильно используете диспетчер конфигурации, это по сути то же самое.)

Это довольно редкое явление, но оно не совсем неслыханно. Мало того, что ваша программа может аварийно завершить работу при записи файла настроек пользователя, сам файл доступен для записи пользователем, поэтому другие программы, которые запускает пользователь, могут связываться с ним.

Чтобы избежать этой конкретной уязвимости, сохраняйте пользовательские настройки в надежном хранилище с транзакционной целостностью, то есть в базе данных. (У вас все еще будут уязвимости, но только не эта.) Это большая работа, которая в большинстве случаев приведет к незначительному повышению надежности. Но «в большинстве случаев» не означает «во всех случаях»; ваш может это оправдать.

3 голосов
/ 21 сентября 2011
[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();
    }
}
...