Update: Configuration Optimisation and Caching
Loads entire configuration at start-up (rather than scope-based loading). Deserialization occurs once, with the resulting value cached and replayed if the requested type matches.
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Data.Configuration
|
||||
{
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.Data.Configuration
|
||||
{
|
||||
@@ -15,29 +11,37 @@ namespace Disco.Data.Configuration
|
||||
|
||||
public abstract string Scope { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a read-write configuration instance
|
||||
/// </summary>
|
||||
public ConfigurationBase(DiscoDataContext Database)
|
||||
{
|
||||
this.Database = Database;
|
||||
}
|
||||
|
||||
protected List<ConfigurationItem> Items
|
||||
/// <summary>
|
||||
/// Creates a read-only configuration instance
|
||||
/// </summary>
|
||||
public ConfigurationBase() : this(null) { }
|
||||
|
||||
protected IEnumerable<string> ItemKeys
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConfigurationCache.GetConfigurationItems(Database, this.Scope);
|
||||
return ConfigurationCache.GetScopeKeys(Database, this.Scope);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetValue<ValueType>(string Key, ValueType Value)
|
||||
private void SetValue<T>(string Key, T Value)
|
||||
{
|
||||
ConfigurationCache.SetConfigurationValue(Database, this.Scope, Key, Value);
|
||||
ConfigurationCache.SetValue(Database, this.Scope, Key, Value);
|
||||
}
|
||||
private ValueType GetValue<ValueType>(string Key, ValueType Default)
|
||||
private T GetValue<T>(string Key, T Default)
|
||||
{
|
||||
return ConfigurationCache.GetConfigurationValue(Database, this.Scope, Key, Default);
|
||||
return ConfigurationCache.GetValue(Database, this.Scope, Key, Default);
|
||||
}
|
||||
|
||||
protected void Set<ValueType>(ValueType Value, [CallerMemberName] string Key = null)
|
||||
protected void Set<T>(T Value, [CallerMemberName] string Key = null)
|
||||
{
|
||||
if (Key == null)
|
||||
throw new ArgumentNullException("Key");
|
||||
@@ -45,7 +49,7 @@ namespace Disco.Data.Configuration
|
||||
this.SetValue(Key, Value);
|
||||
}
|
||||
|
||||
protected ValueType Get<ValueType>(ValueType Default, [CallerMemberName] string Key = null)
|
||||
protected T Get<T>(T Default, [CallerMemberName] string Key = null)
|
||||
{
|
||||
if (Key == null)
|
||||
throw new ArgumentNullException("Key");
|
||||
@@ -55,7 +59,7 @@ namespace Disco.Data.Configuration
|
||||
|
||||
protected void SetObsfucated(string Value, [CallerMemberName] string Key = null)
|
||||
{
|
||||
this.Set(ConfigurationCache.ObsfucateValue(Value), Key);
|
||||
this.Set(Value.Obsfucate(), Key);
|
||||
}
|
||||
|
||||
protected string GetDeobsfucated(string Default, [CallerMemberName] string Key = null)
|
||||
@@ -65,43 +69,40 @@ namespace Disco.Data.Configuration
|
||||
if (obsfucatedValue == null)
|
||||
return Default;
|
||||
else
|
||||
return ConfigurationCache.DeobsfucateValue(obsfucatedValue);
|
||||
return obsfucatedValue.Deobsfucate();
|
||||
}
|
||||
|
||||
protected void SetAsJson<ValueType>(ValueType Value, [CallerMemberName] string Key = null)
|
||||
protected void RemoveScope()
|
||||
{
|
||||
if (Value == null)
|
||||
this.Set<string>(null, Key);
|
||||
else
|
||||
this.Set(JsonConvert.SerializeObject(Value), Key);
|
||||
ConfigurationCache.RemoveScope(Database, this.Scope);
|
||||
}
|
||||
|
||||
protected ValueType GetFromJson<ValueType>(ValueType Default, [CallerMemberName] string Key = null)
|
||||
protected void RemoveItem(string Key)
|
||||
{
|
||||
var jsonValue = this.Get<string>(null, Key);
|
||||
|
||||
if (jsonValue == null)
|
||||
return Default;
|
||||
else
|
||||
return JsonConvert.DeserializeObject<ValueType>(jsonValue);
|
||||
ConfigurationCache.RemoveScopeKey(Database, this.Scope, Key);
|
||||
}
|
||||
|
||||
protected void SetAsEnum<EnumType>(EnumType Value, [CallerMemberName] string Key = null)
|
||||
[Obsolete("Types are automatically serialized/deserialized if required, use Set<T>(T Value) instead.")]
|
||||
protected void SetAsJson<T>(T Value, [CallerMemberName] string Key = null)
|
||||
{
|
||||
if (Value == null)
|
||||
this.Set<string>(null, Key);
|
||||
else
|
||||
this.Set(Value.ToString(), Key);
|
||||
this.Set(Value, Key);
|
||||
}
|
||||
protected EnumType GetFromEnum<EnumType>(EnumType Default, [CallerMemberName] string Key = null)
|
||||
|
||||
[Obsolete("Types are automatically serialized/deserialized if required, use Get<T>(T Default) instead.")]
|
||||
protected T GetFromJson<T>(T Default, [CallerMemberName] string Key = null)
|
||||
{
|
||||
var stringValue = this.Get<string>(null, Key);
|
||||
|
||||
if (stringValue == null)
|
||||
return Default;
|
||||
else
|
||||
return (EnumType)Enum.Parse(typeof(EnumType), stringValue);
|
||||
return this.Get(Default, Key);
|
||||
}
|
||||
|
||||
[Obsolete("Types are automatically serialized/deserialized if required, use Set<T>(T Value) instead.")]
|
||||
protected void SetAsEnum<T>(T Value, [CallerMemberName] string Key = null)
|
||||
{
|
||||
this.Set(Value, Key);
|
||||
}
|
||||
[Obsolete("Types are automatically serialized/deserialized if required, use Set<T>(T Value) instead.")]
|
||||
protected T GetFromEnum<T>(T Default, [CallerMemberName] string Key = null)
|
||||
{
|
||||
return this.Get(Default, Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,143 +1,384 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Data.Configuration
|
||||
{
|
||||
using ConfigurationCacheItemType = Tuple<ConfigurationItem, object>;
|
||||
using ConfigurationCacheScopeType = ConcurrentDictionary<string, Tuple<ConfigurationItem, object>>;
|
||||
using ConfigurationCacheType = ConcurrentDictionary<string, ConcurrentDictionary<string, Tuple<ConfigurationItem, object>>>;
|
||||
|
||||
internal static class ConfigurationCache
|
||||
{
|
||||
#region Cache
|
||||
|
||||
private static Dictionary<String, Dictionary<String, ConfigurationItem>> configDictionary = new Dictionary<string, Dictionary<string, ConfigurationItem>>();
|
||||
private static List<ConfigurationItem> configurationItems = new List<ConfigurationItem>();
|
||||
private static object configurationItemsLock = new object();
|
||||
private static ConfigurationCacheType cacheStore = null;
|
||||
private static object configChangeLock = new object();
|
||||
|
||||
private static void LoadConfigurationItems(DiscoDataContext Database, string Scope, bool Reload)
|
||||
private static ConfigurationCacheType Cache(DiscoDataContext Database)
|
||||
{
|
||||
if (Reload || !configDictionary.ContainsKey(Scope))
|
||||
if (ConfigurationCache.cacheStore == null)
|
||||
{
|
||||
lock (configurationItemsLock)
|
||||
lock (configChangeLock)
|
||||
{
|
||||
if (Reload || !configDictionary.ContainsKey(Scope))
|
||||
if (ConfigurationCache.cacheStore == null)
|
||||
{
|
||||
if (Database == null)
|
||||
throw new InvalidOperationException("Cache-miss where Configuration Item requested from Cache-Only Configuration Context");
|
||||
throw new InvalidOperationException("The Configuration must be loaded at least once before a Cache-Only Configuration Context is used");
|
||||
|
||||
var newItems = Database.ConfigurationItems.Where(ci => ci.Scope == Scope).ToArray();
|
||||
var configurationItems = Database.ConfigurationItems.ToArray();
|
||||
|
||||
if (configDictionary.ContainsKey(Scope))
|
||||
{
|
||||
var existingItems = configDictionary[Scope];
|
||||
foreach (var existingItem in existingItems.Values)
|
||||
{
|
||||
configurationItems.Remove(existingItem);
|
||||
}
|
||||
}
|
||||
configurationItems.AddRange(newItems);
|
||||
configDictionary[Scope] = newItems.ToDictionary(ci => ci.Key);
|
||||
var indexedItems = configurationItems
|
||||
.GroupBy(ci => ci.Scope)
|
||||
.Select(g =>
|
||||
new KeyValuePair<string, ConfigurationCacheScopeType>(
|
||||
g.Key,
|
||||
new ConfigurationCacheScopeType(
|
||||
g.Select(i => new KeyValuePair<string, ConfigurationCacheItemType>(i.Key, Tuple.Create(i, (object)null))))));
|
||||
|
||||
cacheStore = new ConfigurationCacheType(indexedItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ConfigurationCache.cacheStore;
|
||||
}
|
||||
private static Dictionary<string, Dictionary<string, ConfigurationItem>> ConfigurationDictionary(DiscoDataContext Database, string IncludingScope)
|
||||
|
||||
private static ConfigurationCacheItemType CacheGetItem(DiscoDataContext Database, string Scope, string Key)
|
||||
{
|
||||
LoadConfigurationItems(Database, IncludingScope, false);
|
||||
return configDictionary;
|
||||
}
|
||||
private static ConfigurationItem ConfigurationItem(DiscoDataContext Database, string Scope, string Key)
|
||||
{
|
||||
Dictionary<string, ConfigurationItem> scopeDict = default(Dictionary<string, ConfigurationItem>);
|
||||
if (ConfigurationDictionary(Database, Scope).TryGetValue(Scope, out scopeDict))
|
||||
var cache = Cache(Database);
|
||||
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cache.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
ConfigurationItem item = default(ConfigurationItem);
|
||||
if (scopeDict.TryGetValue(Key, out item))
|
||||
ConfigurationCacheItemType item = default(ConfigurationCacheItemType);
|
||||
if (scopeCache.TryGetValue(Key, out item))
|
||||
return item;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private static List<ConfigurationItem> ConfigurationItems(DiscoDataContext Database, string IncludingScope)
|
||||
|
||||
private static ConfigurationCacheItemType CacheSetItem(DiscoDataContext Database, string Scope, string Key, string Value, object ObjectValue)
|
||||
{
|
||||
LoadConfigurationItems(Database, IncludingScope, false);
|
||||
return configurationItems;
|
||||
if (Database == null)
|
||||
throw new InvalidOperationException("Cannot save changes with a Cache-Only Configuration Context");
|
||||
|
||||
var item = CacheGetItem(Database, Scope, Key);
|
||||
|
||||
if (item == null && Value == null)
|
||||
{
|
||||
// No Change - already null
|
||||
return null;
|
||||
}
|
||||
else if (item == null)
|
||||
{
|
||||
// New Configuration Item
|
||||
lock (configChangeLock)
|
||||
{
|
||||
// Check again for thread safety
|
||||
item = CacheGetItem(Database, Scope, Key);
|
||||
if (item == null)
|
||||
{
|
||||
// Create Configuration Item
|
||||
var configItem = new ConfigurationItem() { Scope = Scope, Key = Key, Value = Value };
|
||||
item = new ConfigurationCacheItemType(configItem, ObjectValue);
|
||||
|
||||
// Add Item to DB
|
||||
Database.ConfigurationItems.Add(configItem);
|
||||
|
||||
// Add Item to Cache
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (!cacheStore.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
scopeCache = new ConfigurationCacheScopeType();
|
||||
cacheStore.TryAdd(Scope, scopeCache);
|
||||
}
|
||||
scopeCache.TryAdd(Key, item);
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (item != null)
|
||||
{
|
||||
// Existing Configuration Item
|
||||
lock (configChangeLock)
|
||||
{
|
||||
var configItem = item.Item1;
|
||||
|
||||
// Compare Values
|
||||
if (item.Item1.Value == Value)
|
||||
{
|
||||
// No Change - Update Cache Reference Only
|
||||
return SetItemTypeValue(item, ObjectValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var entityInfo = Database.Entry(configItem);
|
||||
if (entityInfo.State == System.Data.EntityState.Detached)
|
||||
{
|
||||
// Reload Item from DB
|
||||
configItem = Database.ConfigurationItems.Where(i => i.Scope == Scope && i.Key == Key).First();
|
||||
}
|
||||
|
||||
if (Value == null)
|
||||
{
|
||||
// Remove item from Database
|
||||
Database.ConfigurationItems.Remove(configItem);
|
||||
|
||||
// Remove item from Cache
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cacheStore.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
scopeCache.TryRemove(Key, out item);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Update Database
|
||||
configItem.Value = Value;
|
||||
|
||||
// Update Cache
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cacheStore.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
scopeCache.TryRemove(Key, out item);
|
||||
item = new ConfigurationCacheItemType(configItem, ObjectValue);
|
||||
scopeCache.TryAdd(Key, item);
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
private static ConfigurationCacheItemType SetItemTypeValue(ConfigurationCacheItemType ExistingItem, object Value)
|
||||
{
|
||||
var cache = ConfigurationCache.cacheStore;
|
||||
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cache.TryGetValue(ExistingItem.Item1.Scope, out scopeCache))
|
||||
{
|
||||
ConfigurationCacheItemType newItem = new ConfigurationCacheItemType(ExistingItem.Item1, Value);
|
||||
scopeCache.TryUpdate(ExistingItem.Item1.Key, newItem, ExistingItem);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Helpers
|
||||
internal static ValueType GetConfigurationValue<ValueType>(DiscoDataContext Database, string Scope, string Key, ValueType Default)
|
||||
#region Helpers
|
||||
private static bool IsConvertableFromString(Type t)
|
||||
{
|
||||
var ci = ConfigurationItem(Database, Scope, Key);
|
||||
if (ci == null)
|
||||
if (t == typeof(Boolean) ||
|
||||
t == typeof(Char) ||
|
||||
t == typeof(SByte) ||
|
||||
t == typeof(Byte) ||
|
||||
t == typeof(Int16) || t == typeof(UInt16) ||
|
||||
t == typeof(Int32) || t == typeof(UInt32) ||
|
||||
t == typeof(Int64) || t == typeof(UInt64) ||
|
||||
t == typeof(Single) ||
|
||||
t == typeof(Double) ||
|
||||
t == typeof(Decimal) ||
|
||||
t == typeof(DateTime) ||
|
||||
t == typeof(String))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Cache Getters/Setters
|
||||
internal static T GetValue<T>(DiscoDataContext Database, string Scope, string Key, T Default)
|
||||
{
|
||||
var item = CacheGetItem(Database, Scope, Key);
|
||||
|
||||
if (item == null)
|
||||
return Default;
|
||||
else
|
||||
return (ValueType)Convert.ChangeType(ci.Value, typeof(ValueType));
|
||||
}
|
||||
internal static void SetConfigurationValue<ValueType>(DiscoDataContext Database, string Scope, string Key, ValueType Value)
|
||||
{
|
||||
if (Database == null)
|
||||
throw new InvalidOperationException("Cannot save changes with a CacheOnly Context");
|
||||
|
||||
var ci = ConfigurationItem(Database, Scope, Key);
|
||||
if (ci == null && Value != null)
|
||||
{
|
||||
lock (configurationItemsLock)
|
||||
if (item.Item2 != null && item.Item2.GetType() == typeof(T))
|
||||
{
|
||||
ci = ConfigurationItem(Database, Scope, Key);
|
||||
if (ci == null)
|
||||
{
|
||||
// Create Configuration Item
|
||||
ci = new ConfigurationItem() { Scope = Scope, Key = Key, Value = Value.ToString() };
|
||||
// Add Item to DB & Internal Collections
|
||||
Database.ConfigurationItems.Add(ci);
|
||||
ConfigurationItems(Database, Scope).Add(ci);
|
||||
ConfigurationDictionary(Database, Scope)[Scope].Add(Key, ci);
|
||||
ci = null;
|
||||
}
|
||||
// Return Cached Item
|
||||
return (T)item.Item2;
|
||||
}
|
||||
}
|
||||
if (ci != null)
|
||||
{
|
||||
lock (configurationItemsLock)
|
||||
else
|
||||
{
|
||||
var entityInfo = Database.Entry(ci);
|
||||
if (entityInfo.State == System.Data.EntityState.Detached)
|
||||
{
|
||||
// Reload Scope from DB
|
||||
LoadConfigurationItems(Database, Scope, true);
|
||||
ci = ConfigurationItem(Database, Scope, Key);
|
||||
}
|
||||
// Convert Serialized Item
|
||||
Type itemType = typeof(T);
|
||||
object itemValue;
|
||||
|
||||
if (Value == null)
|
||||
if (itemType == typeof(string))
|
||||
{
|
||||
Database.ConfigurationItems.Remove(ci);
|
||||
configurationItems.Remove(ci);
|
||||
configDictionary[Scope].Remove(Key);
|
||||
// string
|
||||
itemValue = item.Item1.Value;
|
||||
}
|
||||
else if (itemType == typeof(object))
|
||||
{
|
||||
// object
|
||||
itemValue = item.Item1.Value;
|
||||
}
|
||||
else if (IsConvertableFromString(itemType))
|
||||
{
|
||||
// IConvertable
|
||||
itemValue = Convert.ChangeType(item.Item1.Value, itemType);
|
||||
}
|
||||
else if (itemType.BaseType != null && itemType.BaseType == typeof(Enum))
|
||||
{
|
||||
// Enum
|
||||
itemValue = Enum.Parse(typeof(T), item.Item1.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ci.Value = Value.ToString();
|
||||
// JSON Deserialize
|
||||
itemValue = JsonConvert.DeserializeObject<T>(item.Item1.Value);
|
||||
}
|
||||
|
||||
// Set Item in Cache
|
||||
SetItemTypeValue(item, itemValue);
|
||||
|
||||
return (T)itemValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
internal static void SetValue<T>(DiscoDataContext Database, string Scope, string Key, T Value)
|
||||
{
|
||||
Type valueType = typeof(T);
|
||||
string stringValue;
|
||||
|
||||
if (Value == null)
|
||||
{
|
||||
stringValue = null;
|
||||
}
|
||||
else if (valueType == typeof(object))
|
||||
{
|
||||
throw new ArgumentException(string.Format("Cannot serialize the configuration item [{0}].[{1}] which defines a type of [System.Object]", Scope, Key), "Value");
|
||||
}
|
||||
else if (IsConvertableFromString(valueType))
|
||||
{
|
||||
// string or supports IConvertable
|
||||
stringValue = Value.ToString();
|
||||
}
|
||||
else if (valueType.BaseType != null && valueType.BaseType == typeof(Enum))
|
||||
{
|
||||
// Enum
|
||||
stringValue = Value.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
// JSON Serialize
|
||||
stringValue = JsonConvert.SerializeObject(Value);
|
||||
}
|
||||
|
||||
CacheSetItem(Database, Scope, Key, stringValue, Value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Cache Helpers
|
||||
|
||||
internal static IEnumerable<string> GetScopeKeys(DiscoDataContext Database, string Scope)
|
||||
{
|
||||
var cache = Cache(Database);
|
||||
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cache.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
return scopeCache.Keys.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
return Enumerable.Empty<string>();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void RemoveScope(DiscoDataContext Database, string Scope)
|
||||
{
|
||||
if (Database == null)
|
||||
throw new InvalidOperationException("Cannot save changes with a Cache-Only Configuration Context");
|
||||
|
||||
lock (configChangeLock)
|
||||
{
|
||||
// Remove item from Database
|
||||
var items = Database.ConfigurationItems.Where(i => i.Scope == Scope).ToList();
|
||||
items.ForEach(i => Database.ConfigurationItems.Remove(i));
|
||||
|
||||
// Remove item from Cache
|
||||
if (cacheStore != null)
|
||||
{
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
cacheStore.TryRemove(Scope, out scopeCache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void RemoveScopeKey(DiscoDataContext Database, string Scope, string Key)
|
||||
{
|
||||
if (Database == null)
|
||||
throw new InvalidOperationException("Cannot save changes with a Cache-Only Configuration Context");
|
||||
|
||||
lock (configChangeLock)
|
||||
{
|
||||
var cacheItem = CacheGetItem(Database, Scope, Key);
|
||||
ConfigurationItem configItem = null;
|
||||
|
||||
// Remove item from Database
|
||||
if (cacheItem != null)
|
||||
{
|
||||
configItem = cacheItem.Item1;
|
||||
|
||||
var entityInfo = Database.Entry(configItem);
|
||||
if (entityInfo.State == System.Data.EntityState.Detached)
|
||||
{
|
||||
// Reload Item from DB
|
||||
configItem = Database.ConfigurationItems.Where(i => i.Scope == Scope && i.Key == Key).FirstOrDefault();
|
||||
}
|
||||
}
|
||||
if (configItem == null)
|
||||
{
|
||||
// Load Item from DB
|
||||
configItem = Database.ConfigurationItems.Where(i => i.Scope == Scope && i.Key == Key).FirstOrDefault();
|
||||
}
|
||||
if (configItem != null)
|
||||
{
|
||||
Database.ConfigurationItems.Remove(configItem);
|
||||
}
|
||||
|
||||
// Remove item from Cache
|
||||
if (cacheItem != null)
|
||||
{
|
||||
ConfigurationCacheScopeType scopeCache;
|
||||
if (cacheStore.TryGetValue(Scope, out scopeCache))
|
||||
{
|
||||
scopeCache.TryRemove(Key, out cacheItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static List<ConfigurationItem> GetConfigurationItems(DiscoDataContext Database, string Scope)
|
||||
{
|
||||
return ConfigurationDictionary(Database, Scope)[Scope].Values.ToList();
|
||||
}
|
||||
#endregion
|
||||
|
||||
internal static string ObsfucateValue(string Value)
|
||||
#region Obsfucation Helpers
|
||||
internal static string Obsfucate(this string Value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Value))
|
||||
return Value;
|
||||
else
|
||||
return Convert.ToBase64String(Encoding.Unicode.GetBytes(Value));
|
||||
}
|
||||
internal static string DeobsfucateValue(string ObsfucatedValue)
|
||||
internal static string Deobsfucate(this string ObsfucatedValue)
|
||||
{
|
||||
if (string.IsNullOrEmpty(ObsfucatedValue))
|
||||
return ObsfucatedValue;
|
||||
@@ -145,6 +386,5 @@ namespace Disco.Data.Configuration
|
||||
return Encoding.Unicode.GetString(Convert.FromBase64String(ObsfucatedValue));
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
using Disco.Data.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
@@ -20,18 +16,18 @@ namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetFromJson<Dictionary<string, List<string>>>(null);
|
||||
return Get<Dictionary<string, List<string>>>(null);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetAsJson(value);
|
||||
Set(value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool? SearchAllForestServers
|
||||
{
|
||||
get { return GetFromJson<bool?>(null); }
|
||||
set { SetAsJson(value); }
|
||||
get { return Get<bool?>(null); }
|
||||
set { Set(value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using Disco.Data.Repository;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
// Removed 2012-06-14 G# - Properties moved to DeviceProfile model & DB Migrated in DBv3.
|
||||
//
|
||||
//
|
||||
//using System;
|
||||
//using System.Collections.Generic;
|
||||
//using System.Linq;
|
||||
//using System.Text;
|
||||
//using Disco.Models.Repository;
|
||||
|
||||
//namespace Disco.Data.Configuration.Modules
|
||||
//{
|
||||
// public class DeviceProfileConfiguration : ConfigurationBase
|
||||
// {
|
||||
// private DeviceProfilesConfiguration deviceProfilesConfig;
|
||||
// private DeviceProfile deviceProfile;
|
||||
|
||||
// public DeviceProfileConfiguration(ConfigurationContext Context, DeviceProfile DeviceProfile)
|
||||
// : base(Context)
|
||||
// {
|
||||
// this.deviceProfilesConfig = Context.DeviceProfiles;
|
||||
// this.deviceProfile = DeviceProfile;
|
||||
// }
|
||||
|
||||
// public override string Scope
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return string.Format("DeviceProfile:{0}", this.deviceProfile.Id);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public string ComputerNameTemplate
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return this.GetValue("ComputerNameTemplate", "DeviceProfile.ShortName + '-' + SerialNumber");
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// this.SetValue("ComputerNameTemplate", value);
|
||||
// }
|
||||
// }
|
||||
|
||||
// public enum DeviceProfileDistributionTypes : int
|
||||
// {
|
||||
// OneToMany = 0,
|
||||
// OneToOne = 1
|
||||
// }
|
||||
// public DeviceProfileDistributionTypes DistributionType
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return (DeviceProfileDistributionTypes)this.GetValue("DistributionType", (int)DeviceProfileDistributionTypes.OneToMany);
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// this.SetValue("DistributionType", (int)value);
|
||||
// }
|
||||
// }
|
||||
// public string OrganisationalUnit
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return this.GetValue<string>("OrganisationalUnit", null);
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// this.SetValue("OrganisationalUnit", value);
|
||||
// }
|
||||
// }
|
||||
// public bool AllocateWirelessCertificate
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// return this.GetValue("AllocateWirelessCertificate", false);
|
||||
// }
|
||||
// set
|
||||
// {
|
||||
// this.SetValue("AllocateWirelessCertificate", value);
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// }
|
||||
//}
|
||||
@@ -1,9 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Data.Repository;
|
||||
using System;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.Job;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Disco.Models.BI.Job;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
@@ -46,14 +43,14 @@ namespace Disco.Data.Configuration.Modules
|
||||
|
||||
public LocationModes LocationMode
|
||||
{
|
||||
get { return GetFromEnum<LocationModes>(LocationModes.Unrestricted); }
|
||||
set { SetAsEnum(value); }
|
||||
get { return Get<LocationModes>(LocationModes.Unrestricted); }
|
||||
set { Set(value); }
|
||||
}
|
||||
|
||||
public List<string> LocationList
|
||||
{
|
||||
get { return GetFromJson<List<string>>(new List<string>()); }
|
||||
set { SetAsJson(value); }
|
||||
get { return Get<List<string>>(new List<string>()); }
|
||||
set { Set(value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +1,22 @@
|
||||
using System;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.Config;
|
||||
using Newtonsoft.Json;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Models.BI.Config;
|
||||
using Disco.Models.Repository;
|
||||
using Newtonsoft.Json;
|
||||
using Disco.Data.Repository;
|
||||
|
||||
namespace Disco.Data.Configuration.Modules
|
||||
{
|
||||
public class OrganisationAddressesConfiguration : ConfigurationBase
|
||||
{
|
||||
private const string scope = "OrganisationAddresses";
|
||||
|
||||
public OrganisationAddressesConfiguration(DiscoDataContext Database) : base(Database) { }
|
||||
|
||||
public override string Scope { get { return "OrganisationAddresses"; } }
|
||||
public override string Scope { get { return scope; } }
|
||||
|
||||
public OrganisationAddress GetAddress(int Id)
|
||||
{
|
||||
var address = default(OrganisationAddress);
|
||||
var addressString = this.Get<string>(null, Id.ToString());
|
||||
if (addressString != null)
|
||||
{
|
||||
if (addressString.StartsWith("{"))
|
||||
{
|
||||
// Assume Json
|
||||
address = JsonConvert.DeserializeObject<OrganisationAddress>(addressString);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Assume Old Storage Method
|
||||
address = OrganisationAddress.FromConfigurationEntry(Id, addressString);
|
||||
}
|
||||
}
|
||||
return address;
|
||||
return this.Get<OrganisationAddress>(null, Id.ToString());
|
||||
}
|
||||
public OrganisationAddress SetAddress(OrganisationAddress Address)
|
||||
{
|
||||
@@ -41,25 +25,21 @@ namespace Disco.Data.Configuration.Modules
|
||||
Address.Id = NextOrganisationAddressId;
|
||||
}
|
||||
|
||||
string addressString = JsonConvert.SerializeObject(Address);
|
||||
this.Set(Address, Address.Id.ToString());
|
||||
|
||||
this.Set(addressString, Address.Id.ToString()); //Address.ToConfigurationEntry());
|
||||
return Address;
|
||||
}
|
||||
public void RemoveAddress(int Id)
|
||||
{
|
||||
// Set Config Item to null = Remove Configuration Item
|
||||
this.Set<string>(null, Id.ToString());
|
||||
// Remove Configuration Item
|
||||
this.RemoveItem(Id.ToString());
|
||||
}
|
||||
|
||||
public List<OrganisationAddress> Addresses
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Items.Select(ca => ca.Value.StartsWith("{") ?
|
||||
JsonConvert.DeserializeObject<OrganisationAddress>(ca.Value) :
|
||||
OrganisationAddress.FromConfigurationEntry(int.Parse(ca.Key), ca.Value)
|
||||
).ToList();
|
||||
return this.ItemKeys.Select(key => this.Get<OrganisationAddress>(null, key)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,5 +58,19 @@ namespace Disco.Data.Configuration.Modules
|
||||
}
|
||||
}
|
||||
|
||||
internal static void MigrateDatabase(DiscoDataContext Database)
|
||||
{
|
||||
// Migrate all organisation addresses to JSON
|
||||
if (Database.ConfigurationItems.Count(i => i.Scope == scope && !i.Value.StartsWith("{")) > 0)
|
||||
{
|
||||
var items = Database.ConfigurationItems.Where(i => i.Scope == scope && !i.Value.StartsWith("{")).ToList();
|
||||
items.ForEach(i =>
|
||||
{
|
||||
i.Value = JsonConvert.SerializeObject(OrganisationAddress.FromConfigurationEntry(int.Parse(i.Key), i.Value));
|
||||
});
|
||||
Database.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.Repository;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using Disco.Data.Repository;
|
||||
using Disco.Models.BI.Interop.Community;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Disco.Data.Configuration
|
||||
{
|
||||
@@ -270,11 +264,11 @@ namespace Disco.Data.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.GetFromJson<UpdateResponse>(null);
|
||||
return this.Get<UpdateResponse>(null);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.SetAsJson(value);
|
||||
this.Set(value);
|
||||
}
|
||||
}
|
||||
public bool UpdateBetaDeployment
|
||||
|
||||
@@ -77,7 +77,6 @@
|
||||
<Compile Include="Configuration\Modules\JobPreferencesConfiguration.cs" />
|
||||
<Compile Include="Configuration\SystemConfiguration.cs" />
|
||||
<Compile Include="Configuration\Modules\BootstrapperConfiguration.cs" />
|
||||
<Compile Include="Configuration\Modules\DeviceProfileConfiguration.cs" />
|
||||
<Compile Include="Configuration\Modules\DeviceProfilesConfiguration.cs" />
|
||||
<Compile Include="Configuration\Modules\OrganisationAddressesConfiguration.cs" />
|
||||
<Compile Include="Migrations\201204250418485_DBv0.cs" />
|
||||
@@ -203,7 +202,7 @@
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties BuildVersion_BuildAction="Both" BuildVersion_UseGlobalSettings="False" BuildVersion_DetectChanges="False" BuildVersion_StartDate="2011/7/1" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_UpdateFileVersion="True" />
|
||||
<UserProperties BuildVersion_UpdateFileVersion="True" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.DeltaBaseYear.MonthAndDayStamp.TimeStamp" BuildVersion_StartDate="2011/7/1" BuildVersion_DetectChanges="False" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildAction="Both" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
|
||||
|
||||
@@ -19,7 +19,11 @@ namespace Disco.Data.Repository
|
||||
Database.SeedJobTypes();
|
||||
Database.SeedJobSubTypes();
|
||||
|
||||
Database.SaveChanges();
|
||||
|
||||
// Migration Maintenance
|
||||
Database.MigrateConfiguration();
|
||||
|
||||
Database.MigratePreDomainObjects();
|
||||
}
|
||||
|
||||
@@ -311,6 +315,14 @@ namespace Disco.Data.Repository
|
||||
}
|
||||
// End Added: 2013-02-07 G#
|
||||
|
||||
public static void MigrateConfiguration(this DiscoDataContext Database)
|
||||
{
|
||||
// Organisation Addresses - Force all to JSON serializing
|
||||
Configuration.Modules.OrganisationAddressesConfiguration.MigrateDatabase(Database);
|
||||
|
||||
Database.SaveChanges();
|
||||
}
|
||||
|
||||
#region Migrate Users SQL
|
||||
private const string MigratePreDomainUsers_Sql = @"INSERT INTO [Users] SELECT @IdNew, u.DisplayName, u.Surname, u.GivenName, u.PhoneNumber, u.EmailAddress FROM [Users] u WHERE [Id]=@IdExisting;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user