|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
Many articles on Code Project discuss how to save application settings. My solution is an attempt to make the saving non-destructive, transparent and traceable. It is based on merging XML files that contain the serialized class instances identified by GUIDs.
In the sample application, I will show how to implement an employee database application base. In the first delivered version the application should manage these employee details:
I simulate a customer who is outside of the US. The searcher doesn't need the citizenship information, but wants to know if the employee is male. So, they want to edit these fields:
The third configuration is an evolution of the application in which the application developer introduces a new field: married.
If the customer deploys the new version of application, it should see these fields:
In this very simple scenario, it is clear that there are two parties which concurrently change the behavior of the application through configuration.
In the data model I have to describe the UI. I can have several delivered fields, which the end user can change and eventually also add to. I decided to describe the fields with the following properties: Name: string, Visible: bool and DataType: string. I will need a persistent container for such descriptions.
public class FieldCollection: ElementList<Field> //Container of Fields
{
}
public class Field : OwnedElement<FieldCollection>
//Field belongs to FieldCollection
{
public const string XMLDataType = "type";
public const string XMLVisible = "visible";
private string _dataType;
// DataType property will be serialized as type attribute
[Serialization(XMLDataType,
SerializationSettings.SerializeAsAttribute)]
public string DataType
{
get
{
return _dataType;
}
set
{
if (_dataType != value)
{
// here we track the changes into local change list
LogChange(XMLDataType, _dataType, value);
_dataType = value;
}
}
}
private bool _visible = true;
[Serialization(XMLVisible)]
//if the engine saves the complete state of class it
// doesn't write the default values
[DefaultValue(true)]
public bool Visible ...
}
The missing declaration of the Name property is already in the ancestor of OwnedElement. The persistent form of the first configuration looks like this:
<e:FieldCollection xmlns:e="elements">
<e:Field type="System.String" ID="36a63bf3-1654-4818-a173-7845048d8e66"
Name="Name" />
<e:Field type="System.Double" ID="06f9d30b-3d34-4769-aaa7-f4abbf8f1df1"
Name="Salary" />
<e:Field type="System.DateTime" ID="93a16832-5f25-43d4-9a0b-e6a6d16866c7"
Name="Birthday" />
<e:Field type="System.Boolean" ID="1d46058c-c17b-41b5-b0b0-ec7ae55021fc"
Name="US_Citizen" />
</e:FieldCollection>
In this small XML, I serialized a collection of 4 Fields of specified name and type. All Fields have visible = true which is the default value and therefore not serialized. In the second configuration, the user adds the new Male field and hides the field US_Citizen. These changes on configuration are serialized into XML. In namespace o are the old saved values.
<e:FieldCollection xmlns:e="elements" xmlns:o="versioning">
<e:Field visible="0" o:visible="1"
ID="1d46058c-c17b-41b5-b0b0-ec7ae55021fc" />
<e:Field type="System.Boolean" ID="f3ab16b0-f33f-4919-9c5c-29419d7ada7e"
Name="Male" />
</e:FieldCollection>
If the application now reads the first XML file and then the second file, the engine finds in the second file the same ID (GUID). It identifies the Field and then updates its properties. The engine also adds a new Field to the collection.
Generating the first configuration:
FieldCollection fieldCollection = new FieldCollection();
Field nameField = fieldCollection.Add("Name");
nameField.DataType = typeof(string).FullName;
Field salaryField = fieldCollection.Add("Salary");
salaryField.DataType = typeof(double).FullName;
Field birthdayField = fieldCollection.Add("Birthday");
birthdayField.DataType = typeof(DateTime).FullName;
Field usField= fieldCollection.Add("US_Citizen");
usField.DataType = typeof(Boolean).FullName;
// write the fieldCollection into ver1.xml
// last parameter means write the not the changes on
// fieldCollection but the whole state
Writer.Write(fieldCollection, "ver1.xml", false);
The generation is pretty simple. I need to instantiate a new FieldCollection and insert Fields into it. Then I can write with Writer the erialized form of the configuration into an XML file. Installation changes are:
FieldCollection fieldCollection = new FieldCollection();
Reader.Read("ver1.xml", fieldCollection, null);
fieldCollection.AcceptChanges();
Field usField = fieldCollection.Find("US_Citizen");
if (usField != null)
usField.Visible = false;
Field maleField = fieldCollection.Add("Male");
maleField.DataType = typeof(Boolean).FullName;
// last parameter = true means save changes
Writer.Write(fieldCollection, "installation.xml", true);
It's again very simple. First, I read the fieldCollection with its Fields. Then I make one field invisible and add a new field. Finally, I save the changes. Configuration merging:
public static FieldCollection Merge(params string[] fileNames)
{
FieldCollection result = new FieldCollection();
foreach (string fileName in fileNames)
{
Reader.Read(fileName, result, null);
}
return result;
}
use it as:
FieldCollection result = Merge("ver1.xml", "instalation.xml");
Merging of configurations is pretty simple. First, I need to read the base configuration and then apply the change log to it.
In the next article, I will describe the library in detail.
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 22 May 2007 Editor: Genevieve Sovereign |
Copyright 2007 by Burkovsky Everything else Copyright © CodeProject, 1999-2009 Web15 | Advertise on the Code Project |