2010-02-15 2 views
5

У нас было редкое исключение происходит при чтении стандартных пользовательских настроек .Net (это те, найденные в «свойствах проекта» в VS 2008):C# - Настройки пользователя сломаны

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() и т. Д., Но получить то же исключение.

Любые идеи о том, как исправить это? Или нам лучше писать собственную систему настроек или сохранять постоянные настройки по-другому?

EDIT: Обходной путь заключается в удалении файла из кода, если вы получите исключение ConfigurationErrorsException.

Кто-нибудь знает, как получить полный путь к файлу user.config?

ответ

9

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

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

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

+0

Как я могу получить путь к файлу настроек пользователя? База данных для моего сценария слишком сложна. – jonathanpeppers

+0

Обратите внимание, что InnerException, типа System.Configuration.ConfigurationErrorsException, имеет свойство Filename ... – technophile

+0

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

2
[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(); 
    } 
} 
+0

Это именно то, что я сделал, за исключением того, что я повторно запускал свое приложение как новый процесс, а не выходя. – jonathanpeppers

8

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

Смежные вопросы