C# - пользовательские настройки не работают

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

Решение

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

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

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

Вот решение, которое не требует от вас выхода из приложения с благодарностью Jarle ( http://www.codeproject.com/Articles/30216/Handling-Corrupt-user-config-Settings?msg=3608682). На ранней стадии, до того, как будут вызваны настройки, используйте это

    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, чтобы версия системы никогда не переходила в плохое состояние.

[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();
    }
}
Другие вопросы по тегам