Sunday, March 9, 2014

Corrupt user.config file

Sometimes – fortunately very seldom – I have the problem that the user.config file is corrupt. When it happens, I get something like

System.Configuration.ConfigurationErrorsException: Configuration system failed to initialize 
---> System.Configuration.ConfigurationErrorsException: Root element is missing. (C:\Users\_user_\AppData\Local\_appdomain_evidenceType_evidenceHash_\_version_\user.config) 
---> System.Xml.XmlException: Root element is missing.

The problem is that in this case I cannot access any setting. No userSettings and also no applicationSettings.

The recommended solution is to delete the user.config file in this case. This is easy since the exception contains the complete file name. And the user has also the permission to delete the file.

However, I didn’t want to bother the user. I thought my program could do the same stuff by itself. Therefore I added the following coding at the beginning of my program (before the first setting will be accessed):

bool isConfigurationValid = false;
while (!isConfigurationValid)
{
  try
  { 
    // access one arbitrary setting
    var x = Settings.Default.Dummy;
    // leave while loop
    isConfigurationValid = true;
  }
  catch (ConfigurationErrorsException e)
  {
    ConfigurationErrorsException innerException = e.InnerException as ConfigurationErrorsException;
    if (innerException != null && innerException.Filename.EndsWith("user.config"))
    {
      File.Delete(innerException.Filename);
      Settings.Default.Reload();
    }
    else
      // other exception; will be not handled here
      throw;
  }
}
The idea was to catch an eventual ConfigurationErrorsException and to delete the corrupt user.config file. So far it worked. But after deleting the file I wanted to reload the settings. And this did not work. The corrupt user.config file remained cached. I also replaced the call of Reload() with Reset() or Upgrade(), but the result remained the same.

The solution was to load the settings explicitly (not via Settings.Default). Instead I used ConfigurationManager.OpenExeConfiguration(). Also this method throws an error when one user.config file is corrupt. But it has no influence on Settings.Default:

bool isConfigurationValid = false;
while (!isConfigurationValid)
{
  try
  {
    AppSettingsSection appSettings = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal).AppSettings;
    isConfigurationValid = true;
  }
  catch (ConfigurationErrorsException e)
  {
    if (e.Filename.EndsWith("user.config"))
      File.Delete(e.Filename);
  }
}

This coding has the additional advantage that I do not have to handle the nested ConfigurationErrorsExceptions. It is only important to call it before the first access to Settings.Default.

No comments:

Post a Comment