Library for reading and saving settings and data.
- XmlRepository is a baseclass for managing xml files.
- BinaryRepository is a baseclass for managing binary files.
- JsonRepository is a baseclass for managing json files.
- Transactional atomic saves. Avoids corrupted data on application crash etc.
- Repository bootstraps itself with settings file in directory.
- SingletonRepository manages a singleton reference for each file.
- Creates backups on save. Backup rules configurable via setting.
- Extension
- Directory
- Number of backups
- Max age backups.
- Use git for backups.
- T Clone(T item); deep clone by serializing and then deserializing an instance.
- bool IsDirty(T item, IEqualityComparer comparer); check if an instance is dirty after last save.
- EqualityComparers that checks structural equality by serializing and comparing bytes. If performance is an issue overloads with IEqualityComparer are exposed.
Helper class for reading and saving files. It is meant to be cached as it is expensive to instantiate.
There are a number of interfaces with subsets of the functionality. Exposing the raw repository class is probably a bad idea as it has so many overload of everything.
When not passing in an explicit RepositorySetting in the constructor the constructor looks on disk if there is a settings file to read and use. If there is no file it creates an instance and saves it for use next time.
This makes it configurable without recompiling.
If a setting is passed in the constructor does not look on disk.
The different libraries contains repository implementations for
NewtonSoft.JsonSystem.XmlSerializerSystem.Runtime.Serialization.Formatters.Binary.BinaryFormatterSystem.Runtime.Serialization.DataContractSerializer
Manages singleton instances of things read or written to disk. This is useful for settings etc.
Simple repository for reading & saving data.
- GetFileInfo, for getting the file the repository uses for reading & saving.
- Delete for deleting files & backups.
- Exists for checking if files exists.
- Read for reading and deserializing the contents of files.
- ReadAsync for reading and deserializing the contents of files.
- ReadOrCreate, read the file if it exists, create and instance and save it to disk before returning it if not.
- Save for saving files.
- SaveAsync for saving files.
- CanRename, check for collisions before renaming.
- Rename, rename files and backups.
- ClearTrackerCache, clear the
IDirtyTracker - RemoveFromDirtyTracker, remove an item from
IDirtyTracker - DeleteBackups, delete backups for a file.
For managing versions of files on disk. The migrations can also be used for switching from xml to json for example. Sample for json:
var read = repository.Read<DummySerializable>(new JsonMigration(Version1To2, Version2To3));
JObject Version1To2(JObject jObject)
{
if (jObject["Version"].Value<int>() == 1)
{
jObject["Version"] = 2;
jObject.RenameProperty("Typo", "Name");
return jObject;
}
return jObject;
}
JObject Version2To3(JObject jObject)
{
if (jObject["Version"].Value<int>() == 2)
{
jObject["Version"] = 3;
jObject.Add("NewProperty", "default value");
return jObject;
}
return jObject;
}Locks all files that will be part of the transaction. Uses atomic writes.
- Lock
fileif exists. - Lock
file.deleteif it exists. - Create and lock
file.tmpif it exists. - Save to
file.tmp - Rename
filetofile.backup ifcreating backups. - Rename
file.tmp->file
On error everything is reset back to initial state.
public class Settings
{
private static readonly DirectoryInfo Directory = new DirectoryInfo("./Settings");
// Initializes with ./Settings/RepositorySettings.json is present
// Creates a git repository for history.
private readonly SingletonRepository repository = new SingletonRepository(
CreateDefaultSettings,
new GitBackuper(Directory.FullName));
public MySetting ReadFoo()
{
// Reads the contents of ./Settings/MySetting.json
// As we are using a SingletonRepository Read will always return the same instance.
return this.repository.Read<MySetting>();
}
public void Save(MySetting setting)
{
// Saves to of ./Settings/MySetting.json
// Commits changes to git repository.
this.repository.Save(setting);
}
private static RepositorySettings CreateDefaultSettings()
{
return new RepositorySettings(
directory: Directory.FullName,
jsonSerializerSettings: new JsonSerializerSettings { Formatting = Formatting.Indented },
isTrackingDirty: true,
backupSettings: null,
extension: ".json",
tempExtension: ".saving");
}
}public class Data
{
// Uses %AppData%/ApplicationName.
// Initializes with %AppData%/ApplicationName/RepositorySettings.cfg
private readonly DataRepository repository = new DataRepository();
public MyData ReadFoo()
{
// Reads the contents of %AppData%/ApplicationName/MyData.cfg
// As we wrap a DataRepository Read will always return a new instance.
return this.repository.Read<MyData>();
}
public void Save(MyData data)
{
// Saves to of %AppData%/ApplicationName/MyData.cfg
// Creates a backup %AppData%/ApplicationName/MyData.bak
this.repository.Save(data);
}
}A number of interfaces exposing subsets of the functionality are provided.
IAsyncFileNameRepositoryIAsyncFileInfoRepositoryIClonerIDirtyIStreamRepositoryIGenericRepositoryIGenericAsyncRepository- A bunch of StreamRepositories for reading raw streams.