AspNet extensions
This commit is contained in:
parent
bb5ea72041
commit
9d87c47f1c
@ -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
|
||||
|
@ -2,7 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.CC-Functions/.idea/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.CC-Functions/.idea/riderModule.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/.idea.CC-Functions/riderModule.iml" filepath="$PROJECT_DIR$/.idea/.idea.CC-Functions/riderModule.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
32
AspNet/AspNet.csproj
Normal file
32
AspNet/AspNet.csproj
Normal file
@ -0,0 +1,32 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>CC_Functions.AspNet</RootNamespace>
|
||||
<AssemblyName>CC_Functions.AspNet</AssemblyName>
|
||||
<Deterministic>false</Deterministic>
|
||||
<PackageId>CC-Functions.AspNet</PackageId>
|
||||
<Title>CC-Functions.AspNet</Title>
|
||||
<Authors>JFronny</Authors>
|
||||
<Description>Random pieces of code for Asp.Net, including my SerialDict integrated Database</Description>
|
||||
<Copyright>Copyright 2020</Copyright>
|
||||
<PackageProjectUrl>https://gitlab.com/JFronny/CC-Functions</PackageProjectUrl>
|
||||
<RepositoryUrl>https://gitlab.com/JFronny/CC-Functions.git</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<AssemblyVersion>1.1.*</AssemblyVersion>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<VersionSuffix>0.0</VersionSuffix>
|
||||
<PackageVersion>1.1.$(VersionSuffix)</PackageVersion>
|
||||
<TargetFramework>net5.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DocumentationFile>bin\Debug\Core.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DocumentationFile>bin\Release\Core.xml</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="protobuf-net" Version="3.0.62" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
138
AspNet/DictionaryGuidConverter.cs
Normal file
138
AspNet/DictionaryGuidConverter.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides serializing dictionary with Guid keys
|
||||
/// </summary>
|
||||
public class DictionaryGuidConverter : JsonConverterFactory
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvert(Type typeToConvert)
|
||||
{
|
||||
if (!typeToConvert.IsGenericType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeToConvert.GetGenericTypeDefinition() != typeof(Dictionary<,>))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return typeToConvert.GetGenericArguments()[0] == typeof(Guid);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
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<TValue> : JsonConverter<Dictionary<Guid, TValue>>
|
||||
{
|
||||
private readonly JsonConverter<TValue> _valueConverter;
|
||||
private Type _valueType;
|
||||
|
||||
public DictionaryGuidConverterInner(JsonSerializerOptions options)
|
||||
{
|
||||
// For performance, use the existing converter if available.
|
||||
_valueConverter = (JsonConverter<TValue>)options
|
||||
.GetConverter(typeof(TValue));
|
||||
|
||||
// Cache the key and value types.
|
||||
_valueType = typeof(TValue);
|
||||
}
|
||||
|
||||
public override Dictionary<Guid, TValue> Read(
|
||||
ref Utf8JsonReader reader,
|
||||
Type typeToConvert,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType != JsonTokenType.StartObject)
|
||||
{
|
||||
throw new JsonException();
|
||||
}
|
||||
|
||||
Dictionary<Guid, TValue> 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<TValue>(ref reader, options);
|
||||
}
|
||||
|
||||
// Add to dictionary.
|
||||
dictionary.Add(key, v);
|
||||
}
|
||||
|
||||
throw new JsonException();
|
||||
}
|
||||
|
||||
public override void Write(
|
||||
Utf8JsonWriter writer,
|
||||
Dictionary<Guid, TValue> dictionary,
|
||||
JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
|
||||
foreach (KeyValuePair<Guid, TValue> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
164
AspNet/SaveLoadDict.cs
Normal file
164
AspNet/SaveLoadDict.cs
Normal file
@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CC_Functions.AspNet
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides synchronizing for dictionaries with saving/loading backends
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The key type</typeparam>
|
||||
/// <typeparam name="U">The param type</typeparam>
|
||||
public abstract class SaveLoadDict<T, U> : IDictionary<T, U>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public IEnumerator<KeyValuePair<T, U>> GetEnumerator()
|
||||
{
|
||||
lock (this) return Load().GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
lock (this) return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(KeyValuePair<T, U> item)
|
||||
{
|
||||
lock (this) Add(item.Key, item.Value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
lock (this) Save(new Dictionary<T, U>());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Contains(KeyValuePair<T, U> item)
|
||||
{
|
||||
lock (this) return Load().Contains(item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void CopyTo(KeyValuePair<T, U>[] array, int arrayIndex)
|
||||
{
|
||||
lock (this) Load().CopyTo(array, arrayIndex);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(KeyValuePair<T, U> item)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
IDictionary<T, U> dictionary = Load();
|
||||
try
|
||||
{
|
||||
return dictionary.Remove(item);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Save(dictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public int Count
|
||||
{
|
||||
get { lock (this) return Load().Count; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReadOnly => false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Add(T key, U value)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
IDictionary<T, U> dictionary = Load();
|
||||
dictionary.Add(key, value);
|
||||
Save(dictionary);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool ContainsKey(T key)
|
||||
{
|
||||
lock (this) return Load().ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool Remove(T key)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
IDictionary<T, U> dictionary = Load();
|
||||
try
|
||||
{
|
||||
return dictionary.Remove(key);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Save(dictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryGetValue(T key, out U value)
|
||||
{
|
||||
lock (this) return Load().TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public U this[T key]
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (this) return Load()[key];
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
IDictionary<T, U> dictionary = Load();
|
||||
dictionary[key] = value;
|
||||
Save(dictionary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<T> Keys
|
||||
{
|
||||
get { lock (this) return Load().Keys; }
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ICollection<U> Values
|
||||
{
|
||||
get { lock (this) return Load().Values; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Replace the current content based on the current state
|
||||
/// </summary>
|
||||
/// <param name="f">Function to mutate the content</param>
|
||||
public void Mutate(Func<IDictionary<T, U>, IDictionary<T, U>> f)
|
||||
{
|
||||
lock (this) Save(f(Load()));
|
||||
}
|
||||
/// <summary>
|
||||
/// Save the dictionary content
|
||||
/// </summary>
|
||||
/// <param name="v">Dictionary content to save</param>
|
||||
protected abstract void Save(IDictionary<T, U> v);
|
||||
/// <summary>
|
||||
/// Load the content to a dictionary
|
||||
/// </summary>
|
||||
/// <returns>The loaded content</returns>
|
||||
protected abstract IDictionary<T, U> Load();
|
||||
}
|
||||
}
|
73
AspNet/SerialDict.cs
Normal file
73
AspNet/SerialDict.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using ProtoBuf;
|
||||
|
||||
namespace CC_Functions.AspNet
|
||||
{
|
||||
/// <summary>
|
||||
/// An implementation of SaveLoadDict that uses Protobuf-net for serialization and Guid keys
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The data type</typeparam>
|
||||
public abstract class SerialDict<T> : SaveLoadDict<Guid, T>
|
||||
{
|
||||
//Interface
|
||||
/// <summary>
|
||||
/// Gets the directory containing databases
|
||||
/// </summary>
|
||||
protected abstract string DatabasesDir { get; }
|
||||
/// <summary>
|
||||
/// Gets the file name for this database. Must not contain the path
|
||||
/// </summary>
|
||||
protected abstract string DatabaseFileName { get; }
|
||||
/// <summary>
|
||||
/// Called when the database is loaded. Use for preparing initial entries
|
||||
/// </summary>
|
||||
public event LoadedD Loaded;
|
||||
/// <summary>
|
||||
/// Called when the database is loaded. Use for preparing initial entries
|
||||
/// </summary>
|
||||
/// <param name="v">The current dictionary content</param>
|
||||
public delegate void LoadedD(IDictionary<Guid, T> v);
|
||||
/// <summary>
|
||||
/// Loads the dictionary and replaces Guids with strings. Use for sending
|
||||
/// </summary>
|
||||
/// <returns>The simplified dictionary</returns>
|
||||
public IDictionary<string, T> GetSendable() => Load().ToDictionary(s => s.Key.ToString(), s => s.Value);
|
||||
|
||||
//Internal
|
||||
private string GetRel() => Path.Combine(DatabasesDir, DatabaseFileName);
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override IDictionary<Guid, T> Load()
|
||||
{
|
||||
if (!Directory.Exists(DatabasesDir))
|
||||
Directory.CreateDirectory(DatabasesDir);
|
||||
IDictionary<Guid, T> v;
|
||||
if (File.Exists(GetRel()))
|
||||
{
|
||||
using (FileStream file = File.OpenRead(GetRel()))
|
||||
v = Serializer.Deserialize<Dictionary<Guid, T>>(file);
|
||||
Loaded?.Invoke(v);
|
||||
return v;
|
||||
}
|
||||
else
|
||||
{
|
||||
v = new Dictionary<Guid, T>();
|
||||
Loaded?.Invoke(v);
|
||||
Save(v);
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Save(IDictionary<Guid, T> dict)
|
||||
{
|
||||
if (!Directory.Exists(DatabasesDir))
|
||||
Directory.CreateDirectory(DatabasesDir);
|
||||
using FileStream file = File.Create(GetRel());
|
||||
Serializer.Serialize(file, dict);
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -4,7 +4,6 @@
|
||||
<OutputType>Library</OutputType>
|
||||
<RootNamespace>CC_Functions.Core</RootNamespace>
|
||||
<AssemblyName>CC_Functions.Core</AssemblyName>
|
||||
<LangVersion>8</LangVersion>
|
||||
<Deterministic>false</Deterministic>
|
||||
<PackageId>CC-Functions.Core</PackageId>
|
||||
<Title>CC-Functions.Core</Title>
|
||||
|
Reference in New Issue
Block a user