From 9d87c47f1c90c209f9e9e7afdd959c085b61137e Mon Sep 17 00:00:00 2001
From: JFronny <33260128+jfronny@users.noreply.github.com>
Date: Thu, 19 Nov 2020 19:26:36 +0100
Subject: [PATCH] AspNet extensions
---
.gitlab-ci.yml | 5 +
.idea/.idea.CC-Functions/.idea/modules.xml | 2 +-
AspNet/AspNet.csproj | 32 ++++
AspNet/DictionaryGuidConverter.cs | 138 +++++++++++++++++
AspNet/SaveLoadDict.cs | 164 +++++++++++++++++++++
AspNet/SerialDict.cs | 73 +++++++++
CC-Functions.sln | 6 +
Core/Core.csproj | 1 -
8 files changed, 419 insertions(+), 2 deletions(-)
create mode 100644 AspNet/AspNet.csproj
create mode 100644 AspNet/DictionaryGuidConverter.cs
create mode 100644 AspNet/SaveLoadDict.cs
create mode 100644 AspNet/SerialDict.cs
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 12c3e69..712a6d5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -55,6 +55,11 @@ uptool:
$tmp = $(Get-Item $(Resolve-Path *.nupkg).Path).Name
echo $tmp
dotnet nuget push $tmp -s https://api.nuget.org/v3/index.json -k $NUGET
+ cd ..\AspNet
+ dotnet pack --version-suffix "$suffix" -c Release -o .
+ $tmp = $(Get-Item $(Resolve-Path *.nupkg).Path).Name
+ echo $tmp
+ dotnet nuget push $tmp -s https://api.nuget.org/v3/index.json -k $NUGET
cd ..\W32
dotnet pack --version-suffix "$suffix" -c Release -o .
$tmp = $(Get-Item $(Resolve-Path *.nupkg).Path).Name
diff --git a/.idea/.idea.CC-Functions/.idea/modules.xml b/.idea/.idea.CC-Functions/.idea/modules.xml
index 6029ade..3eaf66f 100644
--- a/.idea/.idea.CC-Functions/.idea/modules.xml
+++ b/.idea/.idea.CC-Functions/.idea/modules.xml
@@ -2,7 +2,7 @@
-
+
\ No newline at end of file
diff --git a/AspNet/AspNet.csproj b/AspNet/AspNet.csproj
new file mode 100644
index 0000000..f4a5453
--- /dev/null
+++ b/AspNet/AspNet.csproj
@@ -0,0 +1,32 @@
+
+
+
+ Library
+ CC_Functions.AspNet
+ CC_Functions.AspNet
+ false
+ CC-Functions.AspNet
+ CC-Functions.AspNet
+ JFronny
+ Random pieces of code for Asp.Net, including my SerialDict integrated Database
+ Copyright 2020
+ https://gitlab.com/JFronny/CC-Functions
+ https://gitlab.com/JFronny/CC-Functions.git
+ git
+ 1.1.*
+ 1.0.0.0
+ 0.0
+ 1.1.$(VersionSuffix)
+ net5.0
+
+
+ bin\Debug\Core.xml
+
+
+ bin\Release\Core.xml
+
+
+
+
+
+
diff --git a/AspNet/DictionaryGuidConverter.cs b/AspNet/DictionaryGuidConverter.cs
new file mode 100644
index 0000000..3dd98c3
--- /dev/null
+++ b/AspNet/DictionaryGuidConverter.cs
@@ -0,0 +1,138 @@
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+
+namespace CC_Functions.AspNet
+{
+ ///
+ /// Provides serializing dictionary with Guid keys
+ ///
+ public class DictionaryGuidConverter : JsonConverterFactory
+ {
+ ///
+ public override bool CanConvert(Type typeToConvert)
+ {
+ if (!typeToConvert.IsGenericType)
+ {
+ return false;
+ }
+
+ if (typeToConvert.GetGenericTypeDefinition() != typeof(Dictionary<,>))
+ {
+ return false;
+ }
+
+ return typeToConvert.GetGenericArguments()[0] == typeof(Guid);
+ }
+
+ ///
+ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options)
+ {
+ Type valueType = typeToConvert.GetGenericArguments()[1];
+
+ JsonConverter converter = (JsonConverter)Activator.CreateInstance(
+ typeof(DictionaryGuidConverterInner<>).MakeGenericType(valueType),
+ BindingFlags.Instance | BindingFlags.Public,
+ null,
+ new object[] { options },
+ null);
+
+ return converter;
+ }
+
+ private class DictionaryGuidConverterInner : JsonConverter>
+ {
+ private readonly JsonConverter _valueConverter;
+ private Type _valueType;
+
+ public DictionaryGuidConverterInner(JsonSerializerOptions options)
+ {
+ // For performance, use the existing converter if available.
+ _valueConverter = (JsonConverter)options
+ .GetConverter(typeof(TValue));
+
+ // Cache the key and value types.
+ _valueType = typeof(TValue);
+ }
+
+ public override Dictionary Read(
+ ref Utf8JsonReader reader,
+ Type typeToConvert,
+ JsonSerializerOptions options)
+ {
+ if (reader.TokenType != JsonTokenType.StartObject)
+ {
+ throw new JsonException();
+ }
+
+ Dictionary dictionary = new();
+
+ while (reader.Read())
+ {
+ if (reader.TokenType == JsonTokenType.EndObject)
+ {
+ return dictionary;
+ }
+
+ // Get the key.
+ if (reader.TokenType != JsonTokenType.PropertyName)
+ {
+ throw new JsonException();
+ }
+
+ string propertyName = reader.GetString();
+
+ // For performance, parse with ignoreCase:false first.
+ if (!Guid.TryParse(propertyName, out Guid key))
+ {
+ throw new JsonException(
+ $"Unable to convert \"{propertyName}\" to Guid.");
+ }
+
+ // Get the value.
+ TValue v;
+ if (_valueConverter != null)
+ {
+ reader.Read();
+ v = _valueConverter.Read(ref reader, _valueType, options);
+ }
+ else
+ {
+ v = JsonSerializer.Deserialize(ref reader, options);
+ }
+
+ // Add to dictionary.
+ dictionary.Add(key, v);
+ }
+
+ throw new JsonException();
+ }
+
+ public override void Write(
+ Utf8JsonWriter writer,
+ Dictionary dictionary,
+ JsonSerializerOptions options)
+ {
+ writer.WriteStartObject();
+
+ foreach (KeyValuePair kvp in dictionary)
+ {
+ writer.WritePropertyName(kvp.Key.ToString());
+
+ if (_valueConverter != null)
+ {
+ _valueConverter.Write(writer, kvp.Value, options);
+ }
+ else
+ {
+ JsonSerializer.Serialize(writer, kvp.Value, options);
+ }
+ }
+
+ writer.WriteEndObject();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/AspNet/SaveLoadDict.cs b/AspNet/SaveLoadDict.cs
new file mode 100644
index 0000000..64c7a89
--- /dev/null
+++ b/AspNet/SaveLoadDict.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace CC_Functions.AspNet
+{
+ ///
+ /// Provides synchronizing for dictionaries with saving/loading backends
+ ///
+ /// The key type
+ /// The param type
+ public abstract class SaveLoadDict : IDictionary
+ {
+ ///
+ public IEnumerator> GetEnumerator()
+ {
+ lock (this) return Load().GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ lock (this) return GetEnumerator();
+ }
+
+ ///
+ public void Add(KeyValuePair item)
+ {
+ lock (this) Add(item.Key, item.Value);
+ }
+
+ ///
+ public void Clear()
+ {
+ lock (this) Save(new Dictionary());
+ }
+
+ ///
+ public bool Contains(KeyValuePair item)
+ {
+ lock (this) return Load().Contains(item);
+ }
+
+ ///
+ public void CopyTo(KeyValuePair[] array, int arrayIndex)
+ {
+ lock (this) Load().CopyTo(array, arrayIndex);
+ }
+
+ ///
+ public bool Remove(KeyValuePair item)
+ {
+ lock (this)
+ {
+ IDictionary dictionary = Load();
+ try
+ {
+ return dictionary.Remove(item);
+ }
+ finally
+ {
+ Save(dictionary);
+ }
+ }
+ }
+
+ ///
+ public int Count
+ {
+ get { lock (this) return Load().Count; }
+ }
+
+ ///
+ public bool IsReadOnly => false;
+
+ ///
+ public void Add(T key, U value)
+ {
+ lock (this)
+ {
+ IDictionary dictionary = Load();
+ dictionary.Add(key, value);
+ Save(dictionary);
+ }
+ }
+
+ ///
+ public bool ContainsKey(T key)
+ {
+ lock (this) return Load().ContainsKey(key);
+ }
+
+ ///
+ public bool Remove(T key)
+ {
+ lock (this)
+ {
+ IDictionary dictionary = Load();
+ try
+ {
+ return dictionary.Remove(key);
+ }
+ finally
+ {
+ Save(dictionary);
+ }
+ }
+ }
+
+ ///
+ public bool TryGetValue(T key, out U value)
+ {
+ lock (this) return Load().TryGetValue(key, out value);
+ }
+
+ ///
+ public U this[T key]
+ {
+ get
+ {
+ lock (this) return Load()[key];
+ }
+ set
+ {
+ lock (this)
+ {
+ IDictionary dictionary = Load();
+ dictionary[key] = value;
+ Save(dictionary);
+ }
+ }
+ }
+
+ ///
+ public ICollection Keys
+ {
+ get { lock (this) return Load().Keys; }
+ }
+
+ ///
+ public ICollection Values
+ {
+ get { lock (this) return Load().Values; }
+ }
+
+ ///
+ /// Replace the current content based on the current state
+ ///
+ /// Function to mutate the content
+ public void Mutate(Func, IDictionary> f)
+ {
+ lock (this) Save(f(Load()));
+ }
+ ///
+ /// Save the dictionary content
+ ///
+ /// Dictionary content to save
+ protected abstract void Save(IDictionary v);
+ ///
+ /// Load the content to a dictionary
+ ///
+ /// The loaded content
+ protected abstract IDictionary Load();
+ }
+}
diff --git a/AspNet/SerialDict.cs b/AspNet/SerialDict.cs
new file mode 100644
index 0000000..54fb443
--- /dev/null
+++ b/AspNet/SerialDict.cs
@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using ProtoBuf;
+
+namespace CC_Functions.AspNet
+{
+ ///
+ /// An implementation of SaveLoadDict that uses Protobuf-net for serialization and Guid keys
+ ///
+ /// The data type
+ public abstract class SerialDict : SaveLoadDict
+ {
+ //Interface
+ ///
+ /// Gets the directory containing databases
+ ///
+ protected abstract string DatabasesDir { get; }
+ ///
+ /// Gets the file name for this database. Must not contain the path
+ ///
+ protected abstract string DatabaseFileName { get; }
+ ///
+ /// Called when the database is loaded. Use for preparing initial entries
+ ///
+ public event LoadedD Loaded;
+ ///
+ /// Called when the database is loaded. Use for preparing initial entries
+ ///
+ /// The current dictionary content
+ public delegate void LoadedD(IDictionary v);
+ ///
+ /// Loads the dictionary and replaces Guids with strings. Use for sending
+ ///
+ /// The simplified dictionary
+ public IDictionary GetSendable() => Load().ToDictionary(s => s.Key.ToString(), s => s.Value);
+
+ //Internal
+ private string GetRel() => Path.Combine(DatabasesDir, DatabaseFileName);
+
+ ///
+ protected override IDictionary Load()
+ {
+ if (!Directory.Exists(DatabasesDir))
+ Directory.CreateDirectory(DatabasesDir);
+ IDictionary v;
+ if (File.Exists(GetRel()))
+ {
+ using (FileStream file = File.OpenRead(GetRel()))
+ v = Serializer.Deserialize>(file);
+ Loaded?.Invoke(v);
+ return v;
+ }
+ else
+ {
+ v = new Dictionary();
+ Loaded?.Invoke(v);
+ Save(v);
+ return v;
+ }
+ }
+
+ ///
+ protected override void Save(IDictionary dict)
+ {
+ if (!Directory.Exists(DatabasesDir))
+ Directory.CreateDirectory(DatabasesDir);
+ using FileStream file = File.Create(GetRel());
+ Serializer.Serialize(file, dict);
+ }
+ }
+}
\ No newline at end of file
diff --git a/CC-Functions.sln b/CC-Functions.sln
index 8c6947a..58e66fd 100644
--- a/CC-Functions.sln
+++ b/CC-Functions.sln
@@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLITest", "CLITest\CLITest.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Core", "Core\Core.csproj", "{780EC190-E223-46DE-B6FB-1CF56ABDF34E}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNet", "AspNet\AspNet.csproj", "{1A9F3CD1-559B-4429-B8A6-490AF7188A2E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -45,6 +47,10 @@ Global
{780EC190-E223-46DE-B6FB-1CF56ABDF34E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{780EC190-E223-46DE-B6FB-1CF56ABDF34E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{780EC190-E223-46DE-B6FB-1CF56ABDF34E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1A9F3CD1-559B-4429-B8A6-490AF7188A2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1A9F3CD1-559B-4429-B8A6-490AF7188A2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1A9F3CD1-559B-4429-B8A6-490AF7188A2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1A9F3CD1-559B-4429-B8A6-490AF7188A2E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Core/Core.csproj b/Core/Core.csproj
index 75cf4d4..70ca43c 100644
--- a/Core/Core.csproj
+++ b/Core/Core.csproj
@@ -4,7 +4,6 @@
Library
CC_Functions.Core
CC_Functions.Core
- 8
false
CC-Functions.Core
CC-Functions.Core