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.Json
System.XmlSerializer
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
System.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
file
if exists. - Lock
file.delete
if it exists. - Create and lock
file.tmp
if it exists. - Save to
file.tmp
- Rename
file
tofile.backup if
creating 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.
IAsyncFileNameRepository
IAsyncFileInfoRepository
ICloner
IDirty
IStreamRepository
IGenericRepository
IGenericAsyncRepository
- A bunch of StreamRepositories for reading raw streams.