开发者

How to catch exception when loading .NET WinForm app user.config file?

Sometimes in .NET (2.0) WinForm desktop apps which use the default configuration system, the user.config file will become corrupted and can't be loaded anymore (when the configuration system tries to load it, it'll throw a System.Xml.XmlException).

Putting aside the question开发者_运维技巧 of "why did the file get corrupted in the first place" (maybe it was cosmic rays, or HDD problems, or something else you can't control), the question then becomes "how can one catch this exception and do something meaningful with it?

Microsoft's Connect site has a report on this sort of problem. Unfortunately, their report isn't very helpful.

Is it possible to catch exceptions that originate in the default configuration system loader itself? Or would you have to roll your own configuration system to be able to catch this type of exception?


Turns out you can catch this exception. The hint I needed came from this question:

C# - User Settings broken

In my case, (WinForms app), the exception handler I have in my parent (startup) form catches this exception. But I suppose you could use the MyApplication_UnhandledException handler in ApplicationEvents as well. Bottom line is, you need some sort of high-level "unhandled exception" handler to catch this.

Additionally, you can look at the exception's InnerException and see if it is of type System.Configuration.ConfigurationErrorsException. If it is, then you can look at the .FileName property of this InnerException to get the full file name of the user.config file.

Once you have this, you can do something about it - try to check its contents to see what's wrong with it, or (worst case) delete it and restart the app so it is re-created with all the default settings.

As I said before, this is a very rare exception, probably caused by sudden system shutdowns or other uncontrollable events (e.g., power outage). Nevertheless, it is nice to finally be able to do something about it.


I had the same problem. There has to be an error in the Framework, because no one else writes the file. I created a little class that can heal most of the problems.

The only thing you have to do is to call HealUserSettings at the start of your program and call BackupUserSettings when saving your settings.

If you like you can eliminate the Messagebox that informs your user that all his settings are lost.

public static class SettingsFileRecovery
{
    public static void HealUserSettings()
    {
        string file;
        try
        {
            file = GetUserSettingsFile();
        }
        catch (ConfigurationException ex)
        {
            file = ex.Filename;
            if (File.Exists(file))
            {
                if (!RestoreUserSettings(file))
                {
                    MessageBox.Show("Settings are lost.", "Error", MessageBoxButtons.OK,
                                    MessageBoxIcon.Error);

                    // must delete wrong file
                    File.Delete(file);
                }
                Application.Restart();
            }
        }

        // does not exist
        if (!File.Exists(file))
        {
            if (RestoreUserSettings(file))
            {
                Application.Restart();
            }
        }


    }

    public static string GetUserSettingsFile()
    {
        Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
        return config.FilePath;
    }

    public static string GetBackupFile(string file)
    {
        return file + ".bak";
    }

    public static void BackupUserSettings()
    {
        try
        {
            Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
            config.SaveAs(GetBackupFile(config.FilePath));
        }
        catch (Exception)
        {
            // file is corrupt but no problem because no backup is written
        }
    }

    public static bool RestoreUserSettings(string file)
    {
        string backupFile = GetBackupFile(file);
        if (File.Exists(backupFile))
        {
            File.Copy(backupFile, file, true);
            return true;
        }
        return false;
    }
}


One easy way would be to have a "loader" app that all it does is check if the config file for the real app exists, otherwise create it, and then start the real app.

Might be some neater way of doing it that I'm not aware of though.


There's something wrong - something, probably your application, is writing a blank user.config file. This is a bug to investigate and fix. It may be that your application is not exiting cleanly (so it is sometimes silently wiping the app.config, so I'd start by taking a look at the shutdown sequence. Also, sticking a 3rd party file utility on the file may help you catch see exactly when and where it gets corrupted).

If you can't fix the problem, then the best workaround I can think of is to use an independent XML configuration file (ditch the automated app.config approach) - then you have complete control over when and where it is loaded and saved.

But, fundamentally, there's a big code smell and I'd want to know why the standard xml configuration approach isn't working in my app when it works fine in thousands of others.


[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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜