views:

62

answers:

3

Currently, we use a giant configuration object that is serialized to/from XML. This has worked fine for the most part, but we are finding that in the case of power loss and application crashes, that the file could be left in a state that renders it unable to deserialize properly, effectively corrupting the configuration information.

I would like to use the built-in app.config, but it doesn't seem to easily support custom classes. For example, with XML serialization, I can easily serialize a generic list<ComplexClass> with no extra code. It just works. It seems that when using app.config, you have to provide a ton of information and custom classes for this to work. Plus, most of the "custom configuration" tutorials are from circa-2007 and may be outdated for all I know. Does anyone have information to the latest way to do this in .NET 4.0?

In addition, when a problem occurs in the application, 9/10 times it is because of an improper configuration. App.config likes to store user-changeable settings in a very inaccessible location for users who aren't familiar with hidden directories and such. Is there any way to have a single location to store the config file, which the user can easily email us when a problem occurs?

Or, is all this easier than I remember it being in early 2.0 days? Any links or quick examples of how to easily do custom app.config information would be great.

As a further example, this is a pared-down version of one of the types of objects I want to serialize as List<Alarm>, as the amount of Alarms can vary or be empty. Is there an analogous way to store something like this in app.config?

[Serializable]
public class Alarm
{
    [Serializable]
    public class AlarmSetting
    {
        public enum AlarmVariables { Concentration, RSquared }
        public enum AlarmComparisons { LessThan, GreaterThan }

        [Description("Which entity is being alarmed on.")]
        public AlarmVariables Variable { get; set; }
        [Description("Method of comparing the entity to the setpoint.")]
        public AlarmComparisons Comparator { get; set; }
        [Description("Value at which to alarm.")]
        public Double Setpoint { get; set; }
    }

    public String Name { get; set; }
    public Boolean Enabled { get; set; }
    public String Parameter { get; set; }
    public List<AlarmSetting> AlarmSettings { get; set; }
    public System.Drawing.Color RowColor { get; set; }
}
+5  A: 

I would suggest moving away from any sort of config file and instead use some type of local database such as sqlite or sql server express which is much more resilient to app crashes.

IMHO, config settings shouldn't be a default container for user settings. To me a config file is there to make sure the app runs in the given environment. For example, defining connection strings or polling rates or things of that nature.

User settings, especially ones that change often, need a better storage mechanism such as a local database. Unless, of course, it's a client/server application. In which case those settings should be up at the server itself and only persisted locally if the app has to work in a disconnected state.

The example you gave, one of configuring what appears to be one or more alarms is a perfect example of something that belongs in a database table.

Chris Lively
I agree. I use System.Data.Sqlite to store config data as XML in a Sqlite database. The advantages are that you can keep multiple versions of config data and you can wrap your database access in transactions so that you're protected from crash corruption.
ebpower
I could see this working extremely well, but I also don't want to run a database server, or preferably even deal with db-specific drivers (i.e. sqlite) or external DLLs. Is there any time of file-based database built into .NET that would be usable for this situation?
drharris
you really out to check out this page:http://www.sqlite.org/whentouse.html sqlite's entire purpose is to solve the problem you are experiencing.
Chris Lively
+1  A: 

I have been using XML serialization, similar to what you are describing, for many years on a number of different projects. Unless you want to bite off SQL for configuration, this seems to be the best solution.

IMHO, the app.config mechanism is not any better than straight XML serialization. It is actually more difficult to access this configuration from a number of different projects. If you are only saving transient state (user options etc) from a WinForms application, then application settings can be convenient for simple data types.

It seems to me like you have another issue that is causing the corruption. I rarely get file corruption with these XML files. Whenever I do, it is related to an exception that is thrown during serialization, not due to application crash etc. If you want to double check this, you might want to serialize to memory stream and then dump the memory stream to disk. You can actually serialize, deserialize the stream to make sure it's valid prior to dumping the file to disk.

Unless you are writing this file a lot I would be skeptical that the file corruption is due to power outages.

Scott P
Given what drharris has said already I'd bet big money they are writing to the xml file pretty much constantly. It appears to be the only storage mechanism of the app.
Chris Lively
That's the strange thing. I cannot ever replicate the corruption on my development machine, and it seems to be completely random, and I do catch any exceptions and log them (and display it to the user). The only place corruption seems to be able to occur is outside the application itself, which we can't seem to track down. The real kicker is that when a corrupted file is opened in notepad or similar, nothing looks incorrect, yet it always fails (with no useful information). I may try implementing this serialization to memory stream first; perhaps this may catch something.
drharris
And yes, there is constant read/write to this file as things change in software. The key here is that we are constantly updating the configuration of external hardware, and thus the values are always changing. Additional data is logged to flat files, but this configuration is the whole of the entire application's state, including all external hardware.
drharris
@drharris, If you have frequent changes, I'd definitely second the other recommendations to use a light database, as it's designed with the transactional safeguards you're after in mind.
Dan Bryant
A: 

Unless you can track down the source of the error, you're only just guessing that it has anything to do with Xml files. It's entirely possible the built-in XmlSerializer is failing .. e.g. you may have a circular reference somewhere, but it's hard to comment unless you know what your error is.

Sometimes using the built-in Xml Serializer isn't the best choice, and when objects get complex, it can be better to perform the serialization and deserialization yourself. You'll have more control and be able to more accurately determine / recover from bad file data.

XDocument doc = new XDocument(
    new XElement("attachments",
        new XElement("directory", attachmentDirectory),
        new XElement("attachment-list",
            from attached in attachedFiles
            select new XElement("file", 
                new XAttribute("name", attached.FileName), 
                new XAttribute("size", attached.FileSize))
            )
        )
    );

Other than that, configuration files are for configuration, not program data. The difference is configuration data shouldn't change often, and normally isn't too directly editable from users. In a winforms app, you don't share data between users in a configuration file. If you do, then you should consider if your app is really a database application.

Robert Paulson