184 lines
5.6 KiB
C#
184 lines
5.6 KiB
C#
using Unosquare.Swan.Formatters;
|
|
using Unosquare.Swan.Reflection;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
|
|
namespace Unosquare.Swan.Abstractions {
|
|
/// <summary>
|
|
/// Represents a provider to save and load settings using a plain JSON file.
|
|
/// </summary>
|
|
/// <example>
|
|
/// The following example shows how to save and load settings.
|
|
/// <code>
|
|
/// using Unosquare.Swan.Abstractions;
|
|
///
|
|
/// public class Example
|
|
/// {
|
|
/// public static void Main()
|
|
/// {
|
|
/// // get user from settings
|
|
/// var user = SettingsProvider<Settings>.Instance.Global.User;
|
|
///
|
|
/// // modify the port
|
|
/// SettingsProvider<Settings>.Instance.Global.Port = 20;
|
|
///
|
|
/// // if we want these settings to persist
|
|
/// SettingsProvider<Settings>.Instance.PersistGlobalSettings();
|
|
/// }
|
|
///
|
|
/// public class Settings
|
|
/// {
|
|
/// public int Port { get; set; } = 9696;
|
|
///
|
|
/// public string User { get; set; } = "User";
|
|
/// }
|
|
/// }
|
|
/// </code>
|
|
/// </example>
|
|
/// <typeparam name="T">The type of settings model.</typeparam>
|
|
public sealed class SettingsProvider<T>
|
|
: SingletonBase<SettingsProvider<T>> {
|
|
private readonly Object _syncRoot = new Object();
|
|
|
|
private T _global;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the configuration file path. By default the entry assembly directory is used
|
|
/// and the filename is 'appsettings.json'.
|
|
/// </summary>
|
|
/// <value>
|
|
/// The configuration file path.
|
|
/// </value>
|
|
public String ConfigurationFilePath {
|
|
get; set;
|
|
} =
|
|
#if NETSTANDARD1_3
|
|
Path.Combine(Runtime.LocalStoragePath, "appsettings.json");
|
|
#else
|
|
Path.Combine(Runtime.EntryAssemblyDirectory, "appsettings.json");
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Gets the global settings object.
|
|
/// </summary>
|
|
/// <value>
|
|
/// The global settings object.
|
|
/// </value>
|
|
public T Global {
|
|
get {
|
|
lock(this._syncRoot) {
|
|
if(Equals(this._global, default(T))) {
|
|
this.ReloadGlobalSettings();
|
|
}
|
|
|
|
return this._global;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Reloads the global settings.
|
|
/// </summary>
|
|
public void ReloadGlobalSettings() {
|
|
if(File.Exists(this.ConfigurationFilePath) == false || File.ReadAllText(this.ConfigurationFilePath).Length == 0) {
|
|
this.ResetGlobalSettings();
|
|
return;
|
|
}
|
|
|
|
lock(this._syncRoot) {
|
|
this._global = Json.Deserialize<T>(File.ReadAllText(this.ConfigurationFilePath));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Persists the global settings.
|
|
/// </summary>
|
|
public void PersistGlobalSettings() => File.WriteAllText(this.ConfigurationFilePath, Json.Serialize(this.Global, true));
|
|
|
|
/// <summary>
|
|
/// Updates settings from list.
|
|
/// </summary>
|
|
/// <param name="propertyList">The list.</param>
|
|
/// <returns>
|
|
/// A list of settings of type ref="ExtendedPropertyInfo".
|
|
/// </returns>
|
|
/// <exception cref="ArgumentNullException">propertyList.</exception>
|
|
public List<String> RefreshFromList(List<ExtendedPropertyInfo<T>> propertyList) {
|
|
if(propertyList == null) {
|
|
throw new ArgumentNullException(nameof(propertyList));
|
|
}
|
|
|
|
List<String> changedSettings = new List<String>();
|
|
IEnumerable<PropertyInfo> globalProps = Runtime.PropertyTypeCache.RetrieveAllProperties<T>();
|
|
|
|
foreach(ExtendedPropertyInfo<T> property in propertyList) {
|
|
PropertyInfo propertyInfo = globalProps.FirstOrDefault(x => x.Name == property.Property);
|
|
|
|
if(propertyInfo == null) {
|
|
continue;
|
|
}
|
|
|
|
Object originalValue = propertyInfo.GetValue(this.Global);
|
|
Boolean isChanged = propertyInfo.PropertyType.IsArray
|
|
? property.Value is IEnumerable enumerable && propertyInfo.TrySetArray(enumerable.Cast<Object>(), this.Global)
|
|
: this.SetValue(property.Value, originalValue, propertyInfo);
|
|
|
|
if(!isChanged) {
|
|
continue;
|
|
}
|
|
|
|
changedSettings.Add(property.Property);
|
|
this.PersistGlobalSettings();
|
|
}
|
|
|
|
return changedSettings;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets the list.
|
|
/// </summary>
|
|
/// <returns>A List of ExtendedPropertyInfo of the type T.</returns>
|
|
public List<ExtendedPropertyInfo<T>> GetList() {
|
|
Dictionary<String, Object> jsonData = Json.Deserialize(Json.Serialize(this.Global)) as Dictionary<String, Object>;
|
|
|
|
return jsonData?.Keys
|
|
.Select(p => new ExtendedPropertyInfo<T>(p) { Value = jsonData[p] })
|
|
.ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Resets the global settings.
|
|
/// </summary>
|
|
public void ResetGlobalSettings() {
|
|
lock(this._syncRoot) {
|
|
this._global = Activator.CreateInstance<T>();
|
|
}
|
|
|
|
this.PersistGlobalSettings();
|
|
}
|
|
|
|
private Boolean SetValue(Object property, Object originalValue, PropertyInfo propertyInfo) {
|
|
switch(property) {
|
|
case null when originalValue == null:
|
|
break;
|
|
case null:
|
|
propertyInfo.SetValue(this.Global, null);
|
|
return true;
|
|
default:
|
|
if(propertyInfo.PropertyType.TryParseBasicType(property, out Object propertyValue) &&
|
|
!propertyValue.Equals(originalValue)) {
|
|
propertyInfo.SetValue(this.Global, propertyValue);
|
|
return true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
} |