22

I have noticed on a few machines in which my application's user.config file is somehow becoming corrupted and is empty when opening. I can't seem to figure out why this is happened. Is there a common thing that would cause this? Any way to safely prevent this?

My second question is how to do I restore the state? I catch the exception and delete the user.config file, but I cannot find a way to restore the configuration without restarting the application. Everything I do on the Properties object causes the following error:

"Configuration system failed to initialize"

Reset, Reload, and Upgrade all do nothing to solve the problem.

Here is my code for deleting after exception:

catch (System.Configuration.ConfigurationErrorsException ex)
{
    string fileName = "";
    if (!string.IsNullOrEmpty(ex.Filename))
        fileName = ex.Filename;
    else
    {
        System.Configuration.ConfigurationErrorsException innerException = ex.InnerException as System.Configuration.ConfigurationErrorsException;
        if (innerException != null && !string.IsNullOrEmpty(innerException.Filename))
            fileName = innerException.Filename;
    }
    if (System.IO.File.Exists(fileName))
        System.IO.File.Delete(fileName);
}
Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
JeremyK
  • 1,075
  • 1
  • 22
  • 45
  • 2
    If the user.config file is corrrupt, you have to restart, provided you actually store values within the setting's file. The reason you have to restart is obvious, if the file is corrupt, you application is in a unstable state. – Security Hound Mar 05 '12 at 18:57
  • 1
    That is what i figured. I was hoping there was a way to restore the app config to its default settings at run time without needing to restart -- as restart seems to be very unreliable. – JeremyK Mar 05 '12 at 19:00
  • 1
    I have an application that exhibits this same issue from time to time. To date, I have not found a solution to, or the root cause of, this issue. The application has moved from .NET v3.5 to v4.0 so the issue is present in both the v2.0 and v4.0 runtime. Possible duplicate: http://stackoverflow.com/questions/3071651/how-to-catch-exception-when-loading-net-winform-app-user-config-file – harlam357 Feb 25 '13 at 14:47
  • If we restore an old version of the file would it work? Instead of deleting it? – tofutim Sep 21 '15 at 21:54

5 Answers5

21

We had this issue in our app - and I was not able to find out WHY (my guess was that I was writing to Properties.Settings too often but I'm not sure). Anyway, my workaround for is below. The key is to delete corrupted file and call Properties.Settings.Default.Upgrade()

try
{
     ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
}
catch (ConfigurationErrorsException ex)
{
    string filename = ex.Filename;
    _logger.Error(ex, "Cannot open config file");

    if (File.Exists(filename) == true)
    {
        _logger.Error("Config file {0} content:\n{1}", filename, File.ReadAllText(filename));
        File.Delete(filename);
        _logger.Error("Config file deleted");
        Properties.Settings.Default.Upgrade();
        // Properties.Settings.Default.Reload();
        // you could optionally restart the app instead
    }
    else
    {
        _logger.Error("Config file {0} does not exist", filename);
    }
}
avs099
  • 10,937
  • 6
  • 60
  • 110
  • This seemed promising, but when I run Upgrade() I get configuration system failed to initialize. – tofutim Sep 21 '15 at 23:00
  • @tofutim what exactly does it say? And may be try delete + reload() call, on a second thought there was no upgrade in your app.. – avs099 Sep 21 '15 at 23:09
  • 3
    actually, this does work - but it is important to use openexeconfiguration instead of calling for a bad setting, after calling for the bad setting then you are stuck with the configuration system failed to initialize – tofutim Sep 21 '15 at 23:11
  • 2
    this is a winner - the key is openexeconfiguration - you can even swap a backup version of user.config if you don't trip the 'configuration system failed to initialize' error – tofutim Sep 21 '15 at 23:31
  • I needed to do this for an office plugin, OpeningExeConfiguration wasn't enough, I had to attempt to enumerate the sections before it failed. – James Jun 12 '18 at 14:48
  • In some cases, the OpenExeConfiguration won't throw any Exception... Then you must check if the SectionGroups are loaded after OpenExeConfiguration. var UserConfig = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.PerUserRoamingAndLocal); filename = UserConfig.FilePath; var userSettingsGroup = UserConfig.SectionGroups.Get("userSettings"); if (userSettingsGroup != null || userSettingsGroup.IsDeclared == true) filename = null; – Emmanuel Sellier Feb 08 '19 at 12:09
4

I have a similar situation. For me, once I delete the bad configuration file, I just let the application continue. The next access of the settings will use the application defaults.

Matt
  • 49
  • 1
  • 3
  • 1
    If I delete the configuration and they try continue, it remains in a corrupted state and throws an exception every time i use the configuration settings. The configuration system fails to initialize, so trying to use it without restarting would not work. – JeremyK May 09 '12 at 19:30
  • I am also getting the same issue here. after the settings file is corrupt any access to settings property will throw an exception regardless to calls reset() or reload() or after save(). is it possible to handle it some other way. – TrustyCoder Oct 02 '14 at 16:00
4

This might be a bit late, but I've done some more research on this. The user.config file seems to get corrupted for an unknown reason and doesn't let the app start. you could put a small try/catch logic in your app.xaml.cs and check when it launches to make sure this problem is caught at the source. When the app launches and tries to programatically reload settings.default, and fails, it'll go to the exception giving the user an option to delete the file.

try {
Settings.Default.Reload();
} 
catch ( ConfigurationErrorsException ex ) 
{ 
  string filename = ( (ConfigurationErrorsException)ex.InnerException ).Filename;

if ( MessageBox.Show( "<ProgramName> has detected that your" + 
                      " user settings file has become corrupted. " +
                      "This may be due to a crash or improper exiting" + 
                      " of the program. <ProgramName> must reset your " +
                      "user settings in order to continue.\n\nClick" + 
                      " Yes to reset your user settings and continue.\n\n" +
                      "Click No if you wish to attempt manual repair" + 
                      " or to rescue information before proceeding.",
                      "Corrupt user settings", 
                      MessageBoxButton.YesNo, 
                      MessageBoxImage.Error ) == MessageBoxResult.Yes ) {
    File.Delete( filename );
    Settings.Default.Reload();
    // you could optionally restart the app instead
} else
    Process.GetCurrentProcess().Kill();
    // avoid the inevitable crash
}

Credit - http://www.codeproject.com/Articles/30216/Handling-Corrupt-user-config-Settings

Hope this helps someone :)

Arun
  • 41
  • 4
  • 2
    `Reload()` does not help. The next access to `Default.Foo` will throw `ConfigurationErrorsException`. – Martin Feb 19 '15 at 12:38
  • Sorry, I don't understand what you mean.. The reload() function is in a TRY block, and once ConfigurationErrorsException is caught, it will delete the config file and kill the application. When the wpf app is restarted again, it will automatically create a blank config file. This is not as good as it could be, the user will loose any info stored in the configuration file, but at least the application won't become totally unusable. – Arun Mar 12 '15 at 09:20
  • 2
    The second `Reload` is not in a try block (but this is not relevant), and the app will only be killed when the user clicks “No”. When the user clicks “Yes”, the app will keep running, and an exception will be thrown the next time `Default.Foo` will be accessed. Well, at least on my computer... – Martin Mar 16 '15 at 10:38
  • Hmm. Perhaps instead of doing the Yes/No option, make it a MessageBox.Show() that says "Settings file is corrupt. Press OK to reload settings" wtih only the OK button, and once the user presses it, the File.Delete(filename) will be called, after which you can restart the application immediately using `Application.Current.Exit += delegate(object sr, ExitEventArgs ea) { System.Diagnostics.Process.Start(Application.ResourceAssembly.Location); }; Application.Current.Shutdown();` This will restart the application and recreate settings – Arun Mar 17 '15 at 11:37
1

Here is how we solved the problem. This function must be called BEFORE ANY use of Properties.Settings... Else you would be stucked (as described by tofutim and avs099).

private bool CheckSettings()
    {
        var isReset = false;
        string filename = string.Empty;

        try
        {
            var UserConfig = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.PerUserRoamingAndLocal);
            filename = UserConfig.FilePath;
            //"userSettings" should be replaced here with the expected label regarding your configuration file
            var userSettingsGroup = UserConfig.SectionGroups.Get("userSettings");
            if (userSettingsGroup != null && userSettingsGroup.IsDeclared == true)
                filename = null; // No Exception - all is good we should not delete config in Finally block
        }
        catch (System.Configuration.ConfigurationErrorsException ex)
        {
            if (!string.IsNullOrEmpty(ex.Filename))
            {
                filename = ex.Filename;
            }
            else
            {
                var innerEx = ex.InnerException as System.Configuration.ConfigurationErrorsException;
                if (innerEx != null && !string.IsNullOrEmpty(innerEx.Filename))
                {
                    filename = innerEx.Filename;
                }
            }
        }
        catch (System.ArgumentException ex)
        {
            Console.WriteLine("CheckSettings - Argument exception");
        }
        catch (SystemException ex)
        {
            Console.WriteLine("CheckSettings - System exception");

        }
        finally
        { 
            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);
                    }

                    try
                    {
                        Properties.Settings.Default.Upgrade();                          
                    } catch(SystemException ex)
                    {
                        Console.WriteLine("CheckSettings - Exception" + ex.Message);
                    }
                }
            } 
        }
        return isReset;
    }
Emmanuel Sellier
  • 526
  • 1
  • 5
  • 13
0

I did write a class and you can use it in a very easy way.

You can install a nuget package from here:

Nuget Package of LSharpCode.XIO

and instantiate the class in app class just before the first settings call.

using LSharpCode.XIO;
using System;
 
namespace TestRecoverySetting
{
public partial class App
{
//checks settings file consistency
public static readonly CheckSettingsFile CheckSettingsFile = new CheckSettingsFile();
}
}

This class recovery the last valid value of settings if the user.config file is corrupted or recovery the default value if application start for the first time and the usr.config file is corrupted.

Dharman
  • 30,962
  • 25
  • 85
  • 135
luka
  • 605
  • 8
  • 15