From 9d97d437a6127f43a7f03fa50c6adc0941bd7d11 Mon Sep 17 00:00:00 2001 From: Daniel Clark Date: Fri, 9 Dec 2022 22:54:51 +0000 Subject: [PATCH] Refactor --- .../Configurations/ConfigurationChanged.cs | 7 +- .../ConfigurationInitializer.cs | 31 ++- .../Configurations/ConfigurationWriter.cs | 30 +-- .../Configurations/IConfigurationWriter.cs | 10 +- .../IWritableConfigurationProvider.cs | 10 +- .../IWritableJsonConfigurationBuilder.cs | 16 +- .../IWritableJsonConfigurationDescriptor.cs | 12 +- .../WritableJsonConfigurationBuilder.cs | 140 +++++----- .../WritableJsonConfigurationDescriptor.cs | 6 +- .../WritableJsonConfigurationExtensions.cs | 134 +++++----- .../WritableJsonConfigurationFile.cs | 248 +++++++++--------- .../WritableJsonConfigurationProvider.cs | 72 +++-- .../WritableJsonConfigurationSource.cs | 33 ++- Toolkit.Foundation/Configurations/Write.cs | 7 +- .../Configurations/WriteHandler.cs | 41 ++- .../Extensions/IHostBuilderExtensions.cs | 21 +- .../IServiceCollectionExtensions.cs | 35 ++- .../Extensions/IServiceFactoryExtensions.cs | 25 +- Toolkit.Foundation/Lifecycles/AppService.cs | 33 ++- Toolkit.Foundation/Lifecycles/ICache.cs | 9 +- .../Lifecycles/IInitializable.cs | 6 + .../Lifecycles/IInitialization.cs | 6 + Toolkit.Foundation/Lifecycles/IInitializer.cs | 7 - .../Lifecycles/Initialization.cs | 22 +- .../Lifecycles/InitializationHandler.cs | 27 -- Toolkit.Foundation/Lifecycles/Initialize.cs | 5 + .../Lifecycles/InitializeHandler.cs | 29 ++ Toolkit.Foundation/Lifecycles/Initialized.cs | 7 +- 28 files changed, 517 insertions(+), 512 deletions(-) create mode 100644 Toolkit.Foundation/Lifecycles/IInitializable.cs create mode 100644 Toolkit.Foundation/Lifecycles/IInitialization.cs delete mode 100644 Toolkit.Foundation/Lifecycles/IInitializer.cs delete mode 100644 Toolkit.Foundation/Lifecycles/InitializationHandler.cs create mode 100644 Toolkit.Foundation/Lifecycles/Initialize.cs create mode 100644 Toolkit.Foundation/Lifecycles/InitializeHandler.cs diff --git a/Toolkit.Foundation/Configurations/ConfigurationChanged.cs b/Toolkit.Foundation/Configurations/ConfigurationChanged.cs index d14c42c..6248860 100644 --- a/Toolkit.Foundation/Configurations/ConfigurationChanged.cs +++ b/Toolkit.Foundation/Configurations/ConfigurationChanged.cs @@ -1,4 +1,3 @@ -namespace Toolkit.Foundation -{ - public record ConfigurationChanged(TConfiguration Configuration) where TConfiguration : class; -} +namespace Toolkit.Foundation; + +public record ConfigurationChanged(TConfiguration Configuration) where TConfiguration : class; diff --git a/Toolkit.Foundation/Configurations/ConfigurationInitializer.cs b/Toolkit.Foundation/Configurations/ConfigurationInitializer.cs index a30d36e..f5fe0cf 100644 --- a/Toolkit.Foundation/Configurations/ConfigurationInitializer.cs +++ b/Toolkit.Foundation/Configurations/ConfigurationInitializer.cs @@ -1,23 +1,22 @@ using Mediator; -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public class ConfigurationInitializer : IInitializable where TConfiguration : class, new() { - public class ConfigurationInitializer : IInitializer where TConfiguration : class, new() + private readonly TConfiguration configuration; + private readonly IMediator mediator; + + public ConfigurationInitializer(TConfiguration configuration, + IMediator mediator) { - private readonly TConfiguration configuration; - private readonly IMediator mediator; + this.configuration = configuration; + this.mediator = mediator; + } - public ConfigurationInitializer(TConfiguration configuration, - IMediator mediator) - { - this.configuration = configuration; - this.mediator = mediator; - } - - public async Task InitializeAsync() - { - await mediator.Send(configuration); - await Task.CompletedTask; - } + public async Task InitializeAsync() + { + await mediator.Send(configuration); + await Task.CompletedTask; } } diff --git a/Toolkit.Foundation/Configurations/ConfigurationWriter.cs b/Toolkit.Foundation/Configurations/ConfigurationWriter.cs index 81b14d5..4ebffb9 100644 --- a/Toolkit.Foundation/Configurations/ConfigurationWriter.cs +++ b/Toolkit.Foundation/Configurations/ConfigurationWriter.cs @@ -2,30 +2,28 @@ using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public class ConfigurationWriter : IConfigurationWriter where TConfiguration : class, new() { - public class ConfigurationWriter : IConfigurationWriter where TConfiguration : class, new() + private readonly IConfiguration rootConfiguration; + + public ConfigurationWriter(IConfiguration rootConfiguration) { - private readonly IConfiguration rootConfiguration; + this.rootConfiguration = rootConfiguration; + } - public ConfigurationWriter(IConfiguration rootConfiguration) + public void Write(string section, TConfiguration configuration) + { + if (rootConfiguration is IConfigurationRoot root) { - this.rootConfiguration = rootConfiguration; - } - - public void Write(string section, TConfiguration configuration) - { - if (rootConfiguration is IConfigurationRoot root) + foreach (IConfigurationProvider? provider in root.Providers) { - foreach (IConfigurationProvider? provider in root.Providers) + if (provider is IWritableConfigurationProvider writableConfigurationProvider) { - if (provider is IWritableConfigurationProvider writableConfigurationProvider) - { - writableConfigurationProvider.Write(section, configuration); - } + writableConfigurationProvider.Write(section, configuration); } } } } - } diff --git a/Toolkit.Foundation/Configurations/IConfigurationWriter.cs b/Toolkit.Foundation/Configurations/IConfigurationWriter.cs index ca158cf..4114619 100644 --- a/Toolkit.Foundation/Configurations/IConfigurationWriter.cs +++ b/Toolkit.Foundation/Configurations/IConfigurationWriter.cs @@ -1,8 +1,6 @@ -namespace Toolkit.Foundation -{ - public interface IConfigurationWriter where TConfiguration : class - { - void Write(string section, TConfiguration args); - } +namespace Toolkit.Foundation; +public interface IConfigurationWriter where TConfiguration : class +{ + void Write(string section, TConfiguration args); } diff --git a/Toolkit.Foundation/Configurations/IWritableConfigurationProvider.cs b/Toolkit.Foundation/Configurations/IWritableConfigurationProvider.cs index 13eaaf0..a538d4f 100644 --- a/Toolkit.Foundation/Configurations/IWritableConfigurationProvider.cs +++ b/Toolkit.Foundation/Configurations/IWritableConfigurationProvider.cs @@ -1,8 +1,6 @@ -namespace Toolkit.Foundation -{ - public interface IWritableConfigurationProvider - { - void Write(string section, TValue value) where TValue : class, new(); - } +namespace Toolkit.Foundation; +public interface IWritableConfigurationProvider +{ + void Write(string section, TValue value) where TValue : class, new(); } diff --git a/Toolkit.Foundation/Configurations/IWritableJsonConfigurationBuilder.cs b/Toolkit.Foundation/Configurations/IWritableJsonConfigurationBuilder.cs index 97c1f2a..3c0eeef 100644 --- a/Toolkit.Foundation/Configurations/IWritableJsonConfigurationBuilder.cs +++ b/Toolkit.Foundation/Configurations/IWritableJsonConfigurationBuilder.cs @@ -1,14 +1,12 @@ -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public interface IWritableJsonConfigurationBuilder { - public interface IWritableJsonConfigurationBuilder - { - Stream? DefaultFileStream { get; } + Stream? DefaultFileStream { get; } - IWritableJsonConfigurationBuilder AddDefaultConfiguration(string Key) where TConfiguration : class; + IWritableJsonConfigurationBuilder AddDefaultConfiguration(string Key) where TConfiguration : class; - IWritableJsonConfigurationBuilder AddDefaultFileStream(Stream stream); - - void Build(string path); - } + IWritableJsonConfigurationBuilder AddDefaultFileStream(Stream stream); + void Build(string path); } diff --git a/Toolkit.Foundation/Configurations/IWritableJsonConfigurationDescriptor.cs b/Toolkit.Foundation/Configurations/IWritableJsonConfigurationDescriptor.cs index 8f14804..20e1d2b 100644 --- a/Toolkit.Foundation/Configurations/IWritableJsonConfigurationDescriptor.cs +++ b/Toolkit.Foundation/Configurations/IWritableJsonConfigurationDescriptor.cs @@ -1,10 +1,8 @@ -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public interface IWritableJsonConfigurationDescriptor { - public interface IWritableJsonConfigurationDescriptor - { - Type ConfigurationType { get; } - - string Key { get; } - } + Type ConfigurationType { get; } + string Key { get; } } diff --git a/Toolkit.Foundation/Configurations/WritableJsonConfigurationBuilder.cs b/Toolkit.Foundation/Configurations/WritableJsonConfigurationBuilder.cs index 6e8975d..6506e52 100644 --- a/Toolkit.Foundation/Configurations/WritableJsonConfigurationBuilder.cs +++ b/Toolkit.Foundation/Configurations/WritableJsonConfigurationBuilder.cs @@ -10,101 +10,99 @@ using System.Text.Json; using System.Text.Json.Serialization; using JsonSerializer = System.Text.Json.JsonSerializer; -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public class WritableJsonConfigurationBuilder : IWritableJsonConfigurationBuilder { - public class WritableJsonConfigurationBuilder : IWritableJsonConfigurationBuilder + private readonly List descriptors = new(); + + public Stream? DefaultFileStream { get; private set; } + + public IReadOnlyCollection Descriptors => new ReadOnlyCollection(descriptors); + + public IWritableJsonConfigurationBuilder AddDefaultConfiguration(string Key) where TConfiguration : class { - private readonly List descriptors = new(); + descriptors.Add(new WritableJsonConfigurationDescriptor(typeof(TConfiguration), Key)); + return this; + } - public Stream? DefaultFileStream { get; private set; } + public IWritableJsonConfigurationBuilder AddDefaultFileStream(Stream stream) + { + DefaultFileStream = stream; + return this; + } - public IReadOnlyCollection Descriptors => new ReadOnlyCollection(descriptors); - - public IWritableJsonConfigurationBuilder AddDefaultConfiguration(string Key) where TConfiguration : class + public void Build(string path) + { + JObject? sourceDocument = new(); + if (TryLoadSource(out string? defaultContent)) { - descriptors.Add(new WritableJsonConfigurationDescriptor(typeof(TConfiguration), Key)); - return this; + sourceDocument = JObject.Parse(defaultContent!); } - public IWritableJsonConfigurationBuilder AddDefaultFileStream(Stream stream) + JObject? targetDocument = new(); + if (TryLoadTarget(path, out string? targetContent)) { - DefaultFileStream = stream; - return this; + targetDocument = JObject.Parse(targetContent!); } - public void Build(string path) + foreach (IWritableJsonConfigurationDescriptor? descriptor in descriptors) { - JObject? sourceDocument = new(); - if (TryLoadSource(out string? defaultContent)) + if (sourceDocument.SelectToken($"$.{descriptor.Key}") is JToken sourceSection) { - sourceDocument = JObject.Parse(defaultContent!); - } - - JObject? targetDocument = new(); - if (TryLoadTarget(path, out string? targetContent)) - { - targetDocument = JObject.Parse(targetContent!); - } - - foreach (IWritableJsonConfigurationDescriptor? descriptor in descriptors) - { - if (sourceDocument.SelectToken($"$.{descriptor.Key}") is JToken sourceSection) + if (targetDocument.SelectToken($"$.{descriptor.Key}") is JToken targetSection) { - if (targetDocument.SelectToken($"$.{descriptor.Key}") is JToken targetSection) - { - object? source = JsonSerializer.Deserialize(JsonConvert.SerializeObject(sourceSection), descriptor.ConfigurationType); - object? target = JsonSerializer.Deserialize(JsonConvert.SerializeObject(targetSection), descriptor.ConfigurationType); + object? source = JsonSerializer.Deserialize(JsonConvert.SerializeObject(sourceSection), descriptor.ConfigurationType); + object? target = JsonSerializer.Deserialize(JsonConvert.SerializeObject(targetSection), descriptor.ConfigurationType); - JsonPatch? patch = source.CreatePatch(target); + JsonPatch? patch = source.CreatePatch(target); - object? sourcePatched = patch.Apply(source); - targetSection.Replace(JToken.Parse(JsonSerializer.Serialize(sourcePatched, new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }))); - } - else - { - object? source = JsonSerializer.Deserialize(JsonConvert.SerializeObject(sourceSection), descriptor.ConfigurationType); - targetDocument.Add(descriptor.Key, JToken.Parse(JsonSerializer.Serialize(source, new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }))); - } + object? sourcePatched = patch.Apply(source); + targetSection.Replace(JToken.Parse(JsonSerializer.Serialize(sourcePatched, new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }))); } else { - object? configuration = Activator.CreateInstance(descriptor.ConfigurationType); - targetDocument.Add(descriptor.Key, JToken.Parse(JsonSerializer.Serialize(configuration, new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }))); + object? source = JsonSerializer.Deserialize(JsonConvert.SerializeObject(sourceSection), descriptor.ConfigurationType); + targetDocument.Add(descriptor.Key, JToken.Parse(JsonSerializer.Serialize(source, new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }))); } } - - using FileStream? fileStream = new(path, FileMode.Create, FileAccess.Write); - using StreamWriter streamWriter = new(fileStream); - using JsonTextWriter writer = new(streamWriter) { Formatting = Formatting.Indented }; - targetDocument.WriteTo(writer); - } - - private bool TryLoadTarget(string path, [MaybeNull] out string? content) - { - if (File.Exists(path)) + else { - using FileStream? fileStream = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - using StreamReader? streamReader = new(fileStream); - content = streamReader.ReadToEnd(); - return true; + object? configuration = Activator.CreateInstance(descriptor.ConfigurationType); + targetDocument.Add(descriptor.Key, JToken.Parse(JsonSerializer.Serialize(configuration, new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }))); } - - content = null; - return false; } - private bool TryLoadSource([MaybeNull] out string? content) - { - if (DefaultFileStream is Stream fileStream) - { - using StreamReader? streamReader = new(fileStream); - content = streamReader.ReadToEnd(); - return true; - } - - content = null; - return false; - } + using FileStream? fileStream = new(path, FileMode.Create, FileAccess.Write); + using StreamWriter streamWriter = new(fileStream); + using JsonTextWriter writer = new(streamWriter) { Formatting = Formatting.Indented }; + targetDocument.WriteTo(writer); } + private bool TryLoadTarget(string path, [MaybeNull] out string? content) + { + if (File.Exists(path)) + { + using FileStream? fileStream = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + using StreamReader? streamReader = new(fileStream); + content = streamReader.ReadToEnd(); + return true; + } + + content = null; + return false; + } + + private bool TryLoadSource([MaybeNull] out string? content) + { + if (DefaultFileStream is Stream fileStream) + { + using StreamReader? streamReader = new(fileStream); + content = streamReader.ReadToEnd(); + return true; + } + + content = null; + return false; + } } diff --git a/Toolkit.Foundation/Configurations/WritableJsonConfigurationDescriptor.cs b/Toolkit.Foundation/Configurations/WritableJsonConfigurationDescriptor.cs index fa44c4f..4da65d9 100644 --- a/Toolkit.Foundation/Configurations/WritableJsonConfigurationDescriptor.cs +++ b/Toolkit.Foundation/Configurations/WritableJsonConfigurationDescriptor.cs @@ -1,5 +1,3 @@ -namespace Toolkit.Foundation -{ - public record WritableJsonConfigurationDescriptor(Type ConfigurationType, string Key) : IWritableJsonConfigurationDescriptor; +namespace Toolkit.Foundation; -} +public record WritableJsonConfigurationDescriptor(Type ConfigurationType, string Key) : IWritableJsonConfigurationDescriptor; diff --git a/Toolkit.Foundation/Configurations/WritableJsonConfigurationExtensions.cs b/Toolkit.Foundation/Configurations/WritableJsonConfigurationExtensions.cs index 804231a..9804e41 100644 --- a/Toolkit.Foundation/Configurations/WritableJsonConfigurationExtensions.cs +++ b/Toolkit.Foundation/Configurations/WritableJsonConfigurationExtensions.cs @@ -1,76 +1,74 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.FileProviders; -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public static class WritableJsonConfigurationExtensions { - public static class WritableJsonConfigurationExtensions + public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, + string path) { - public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, - string path) - { - return builder.AddWritableJsonFile(null, path, false, false, null); - } - - public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, - string path, - Action? factoryDelegate) - { - return builder.AddWritableJsonFile(null, path, false, false, factoryDelegate); - } - - public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, - string path, - bool optional) - { - return builder.AddWritableJsonFile(null, path, optional, false, null); - } - - public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, - string path, - bool optional, - Action? factoryDelegate) - { - return builder.AddWritableJsonFile(null, path, optional, false, factoryDelegate); - } - - public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, - string path, - bool optional, - bool reloadOnChange) - { - return builder.AddWritableJsonFile(null, path, optional, reloadOnChange, null); - } - - public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, - string path, - bool optional, - bool reloadOnChange, - Action? factoryDelegate) - { - return builder.AddWritableJsonFile(null, path, optional, reloadOnChange, factoryDelegate); - } - - public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, - IFileProvider? provider, - string path, - bool optional, - bool reloadOnChange, Action? writableJsonConfigurationDelegate) - { - IWritableJsonConfigurationBuilder writableJsonConfigurationBuilder = new WritableJsonConfigurationBuilder(); - writableJsonConfigurationDelegate?.Invoke(writableJsonConfigurationBuilder); - - return builder.AddWritableJsonFile(configuration => - { - configuration.FileProvider = provider; - configuration.Path = path; - configuration.Optional = optional; - configuration.ReloadOnChange = reloadOnChange; - configuration.Factory = writableJsonConfigurationBuilder; - configuration.ResolveFileProvider(); - }); - } - - public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, Action configureSource) => builder.Add(configureSource); + return builder.AddWritableJsonFile(null, path, false, false, null); } + public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, + string path, + Action? factoryDelegate) + { + return builder.AddWritableJsonFile(null, path, false, false, factoryDelegate); + } + + public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, + string path, + bool optional) + { + return builder.AddWritableJsonFile(null, path, optional, false, null); + } + + public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, + string path, + bool optional, + Action? factoryDelegate) + { + return builder.AddWritableJsonFile(null, path, optional, false, factoryDelegate); + } + + public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, + string path, + bool optional, + bool reloadOnChange) + { + return builder.AddWritableJsonFile(null, path, optional, reloadOnChange, null); + } + + public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, + string path, + bool optional, + bool reloadOnChange, + Action? factoryDelegate) + { + return builder.AddWritableJsonFile(null, path, optional, reloadOnChange, factoryDelegate); + } + + public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, + IFileProvider? provider, + string path, + bool optional, + bool reloadOnChange, Action? writableJsonConfigurationDelegate) + { + IWritableJsonConfigurationBuilder writableJsonConfigurationBuilder = new WritableJsonConfigurationBuilder(); + writableJsonConfigurationDelegate?.Invoke(writableJsonConfigurationBuilder); + + return builder.AddWritableJsonFile(configuration => + { + configuration.FileProvider = provider; + configuration.Path = path; + configuration.Optional = optional; + configuration.ReloadOnChange = reloadOnChange; + configuration.Factory = writableJsonConfigurationBuilder; + configuration.ResolveFileProvider(); + }); + } + + public static IConfigurationBuilder AddWritableJsonFile(this IConfigurationBuilder builder, Action configureSource) => builder.Add(configureSource); } diff --git a/Toolkit.Foundation/Configurations/WritableJsonConfigurationFile.cs b/Toolkit.Foundation/Configurations/WritableJsonConfigurationFile.cs index f6421c8..9bf2d58 100644 --- a/Toolkit.Foundation/Configurations/WritableJsonConfigurationFile.cs +++ b/Toolkit.Foundation/Configurations/WritableJsonConfigurationFile.cs @@ -3,148 +3,146 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System.Text.Json; -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +internal class WritableJsonConfigurationFile { - internal class WritableJsonConfigurationFile + private readonly Dictionary data = new(StringComparer.OrdinalIgnoreCase); + private readonly Stack paths = new(); + private JObject tokenCache = new(); + private bool isParsing; + + public IDictionary Parse(Stream input) { - private readonly Dictionary data = new(StringComparer.OrdinalIgnoreCase); - private readonly Stack paths = new(); - private JObject tokenCache = new(); - private bool isParsing; + return ParseStream(input); + } - public IDictionary Parse(Stream input) + public void Write(string key, string value, Stream output) + { + if (isParsing) { - return ParseStream(input); + return; } - public void Write(string key, string value, Stream output) + if (key[^1] == ':') { - if (isParsing) - { - return; - } - - if (key[^1] == ':') - { - key = key[0..^1]; - } - - string? tokenPath = $"$.{key.Replace(":", ".")}"; - key = key.Replace("[", "").Replace("]", ""); - - if (tokenCache.SelectToken(tokenPath) is JToken token && data.ContainsKey(key)) - { - (JsonValueKind? kind, string _) = data[key]; - object? newValue = ConvertValue(kind, value); - - data[key] = new(kind, value); - token.Replace(JToken.FromObject(newValue)); - } - - using StreamWriter streamWriter = new(output); - using JsonTextWriter writer = new(streamWriter) { Formatting = Formatting.Indented }; - tokenCache.WriteTo(writer); - - output.SetLength(output.Position); + key = key[0..^1]; } - private static object ConvertValue(JsonValueKind? kind, string value) + string? tokenPath = $"$.{key.Replace(":", ".")}"; + key = key.Replace("[", "").Replace("]", ""); + + if (tokenCache.SelectToken(tokenPath) is JToken token && data.ContainsKey(key)) { - return kind is JsonValueKind.True or JsonValueKind.False ? bool.Parse(value) : value; + (JsonValueKind? kind, string _) = data[key]; + object? newValue = ConvertValue(kind, value); + + data[key] = new(kind, value); + token.Replace(JToken.FromObject(newValue)); } - private void EnterContext(string context) + using StreamWriter streamWriter = new(output); + using JsonTextWriter writer = new(streamWriter) { Formatting = Formatting.Indented }; + tokenCache.WriteTo(writer); + + output.SetLength(output.Position); + } + + private static object ConvertValue(JsonValueKind? kind, string value) + { + return kind is JsonValueKind.True or JsonValueKind.False ? bool.Parse(value) : value; + } + + private void EnterContext(string context) + { + paths.Push(paths.Count > 0 ? paths.Peek() + ConfigurationPath.KeyDelimiter + context : context); + } + + private void ExitContext() + { + paths.Pop(); + } + + private IDictionary ParseStream(Stream input) + { + data.Clear(); + + JsonDocumentOptions jsonDocumentOptions = new() { - paths.Push(paths.Count > 0 ? paths.Peek() + ConfigurationPath.KeyDelimiter + context : context); + CommentHandling = JsonCommentHandling.Skip, + AllowTrailingCommas = true, + }; + + isParsing = true; + using (StreamReader? reader = new(input)) + { + string? content = reader.ReadToEnd(); + tokenCache = JObject.Parse(content); + + using JsonDocument? doc = JsonDocument.Parse(content, jsonDocumentOptions); + VisitElement(doc.RootElement); + } + isParsing = false; + + return data.ToDictionary(k => k.Key, v => v.Value.Item2?.ToString() ?? null); + } + + private void VisitElement(JsonElement element) + { + bool isEmpty = true; + + foreach (JsonProperty property in element.EnumerateObject()) + { + isEmpty = false; + + EnterContext(property.Name); + VisitValue(property.Value); + ExitContext(); } - private void ExitContext() + if (isEmpty && paths.Count > 0) { - paths.Pop(); - } - - private IDictionary ParseStream(Stream input) - { - data.Clear(); - - JsonDocumentOptions jsonDocumentOptions = new() - { - CommentHandling = JsonCommentHandling.Skip, - AllowTrailingCommas = true, - }; - - isParsing = true; - using (StreamReader? reader = new(input)) - { - string? content = reader.ReadToEnd(); - tokenCache = JObject.Parse(content); - - using JsonDocument? doc = JsonDocument.Parse(content, jsonDocumentOptions); - VisitElement(doc.RootElement); - } - isParsing = false; - - return data.ToDictionary(k => k.Key, v => v.Value.Item2?.ToString() ?? null); - } - - private void VisitElement(JsonElement element) - { - bool isEmpty = true; - - foreach (JsonProperty property in element.EnumerateObject()) - { - isEmpty = false; - - EnterContext(property.Name); - VisitValue(property.Value); - ExitContext(); - } - - if (isEmpty && paths.Count > 0) - { - data[paths.Peek()] = (JsonValueKind.Null, null); - } - } - - private void VisitValue(JsonElement value) - { - switch (value.ValueKind) - { - case JsonValueKind.Object: - VisitElement(value); - break; - - case JsonValueKind.Array: - int index = 0; - foreach (JsonElement arrayElement in value.EnumerateArray()) - { - EnterContext(index.ToString()); - VisitValue(arrayElement); - ExitContext(); - index++; - } - break; - - case JsonValueKind.Number: - case JsonValueKind.String: - case JsonValueKind.True: - case JsonValueKind.False: - case JsonValueKind.Null: - string key = paths.Peek(); - if (data.ContainsKey(key)) - { - throw new FormatException(); - } - data[key] = new(value.ValueKind, value.ToString()); - break; - - case JsonValueKind.Undefined: - break; - - default: - throw new FormatException(); - } + data[paths.Peek()] = (JsonValueKind.Null, null); } } + private void VisitValue(JsonElement value) + { + switch (value.ValueKind) + { + case JsonValueKind.Object: + VisitElement(value); + break; + + case JsonValueKind.Array: + int index = 0; + foreach (JsonElement arrayElement in value.EnumerateArray()) + { + EnterContext(index.ToString()); + VisitValue(arrayElement); + ExitContext(); + index++; + } + break; + + case JsonValueKind.Number: + case JsonValueKind.String: + case JsonValueKind.True: + case JsonValueKind.False: + case JsonValueKind.Null: + string key = paths.Peek(); + if (data.ContainsKey(key)) + { + throw new FormatException(); + } + data[key] = new(value.ValueKind, value.ToString()); + break; + + case JsonValueKind.Undefined: + break; + + default: + throw new FormatException(); + } + } } diff --git a/Toolkit.Foundation/Configurations/WritableJsonConfigurationProvider.cs b/Toolkit.Foundation/Configurations/WritableJsonConfigurationProvider.cs index 1b6124f..c58c6ce 100644 --- a/Toolkit.Foundation/Configurations/WritableJsonConfigurationProvider.cs +++ b/Toolkit.Foundation/Configurations/WritableJsonConfigurationProvider.cs @@ -3,46 +3,44 @@ using Microsoft.Extensions.FileProviders; using Newtonsoft.Json; using Newtonsoft.Json.Linq; -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public class WritableJsonConfigurationProvider : JsonConfigurationProvider, IWritableConfigurationProvider { - public class WritableJsonConfigurationProvider : JsonConfigurationProvider, IWritableConfigurationProvider + public WritableJsonConfigurationProvider(JsonConfigurationSource source) : base(source) { - public WritableJsonConfigurationProvider(JsonConfigurationSource source) : base(source) - { - } - - public void Write(string section, TValue value) where TValue : class, new() - { - IFileInfo? file = Source.FileProvider?.GetFileInfo(Source.Path ?? string.Empty); - static Stream OpenRead(IFileInfo fileInfo) - { - return fileInfo.PhysicalPath is not null - ? new FileStream(fileInfo.PhysicalPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite) - : fileInfo.CreateReadStream(); - } - - if (file is null) - { - throw new FileNotFoundException(); - } - - using Stream stream = OpenRead(file); - using StreamReader? reader = new(stream); - - string? content = reader.ReadToEnd(); - JObject? document = JObject.Parse(content); - - if (document.SelectToken($"$.{section}") is JToken sectionToken) - { - sectionToken.Replace(JToken.Parse(JsonConvert.SerializeObject(value))); - stream.SetLength(0); - - using StreamWriter streamWriter = new(stream); - using JsonTextWriter writer = new(streamWriter) { Formatting = Formatting.Indented }; - document.WriteTo(writer); - } - } } + public void Write(string section, TValue value) where TValue : class, new() + { + IFileInfo? file = Source.FileProvider?.GetFileInfo(Source.Path ?? string.Empty); + static Stream OpenRead(IFileInfo fileInfo) + { + return fileInfo.PhysicalPath is not null + ? new FileStream(fileInfo.PhysicalPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite) + : fileInfo.CreateReadStream(); + } + + if (file is null) + { + throw new FileNotFoundException(); + } + + using Stream stream = OpenRead(file); + using StreamReader? reader = new(stream); + + string? content = reader.ReadToEnd(); + JObject? document = JObject.Parse(content); + + if (document.SelectToken($"$.{section}") is JToken sectionToken) + { + sectionToken.Replace(JToken.Parse(JsonConvert.SerializeObject(value))); + stream.SetLength(0); + + using StreamWriter streamWriter = new(stream); + using JsonTextWriter writer = new(streamWriter) { Formatting = Formatting.Indented }; + document.WriteTo(writer); + } + } } diff --git a/Toolkit.Foundation/Configurations/WritableJsonConfigurationSource.cs b/Toolkit.Foundation/Configurations/WritableJsonConfigurationSource.cs index 0e6c618..25bd255 100644 --- a/Toolkit.Foundation/Configurations/WritableJsonConfigurationSource.cs +++ b/Toolkit.Foundation/Configurations/WritableJsonConfigurationSource.cs @@ -2,27 +2,26 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.FileProviders; -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public class WritableJsonConfigurationSource : JsonConfigurationSource { - public class WritableJsonConfigurationSource : JsonConfigurationSource + public IWritableJsonConfigurationBuilder? Factory { get; set; } + + public override IConfigurationProvider Build(IConfigurationBuilder builder) { - public IWritableJsonConfigurationBuilder? Factory { get; set; } + EnsureDefaultsWithSteam(builder); + return new WritableJsonConfigurationProvider(this); + } - public override IConfigurationProvider Build(IConfigurationBuilder builder) + private void EnsureDefaultsWithSteam(IConfigurationBuilder builder) + { + EnsureDefaults(builder); + + if (FileProvider is PhysicalFileProvider physicalFileProvider) { - EnsureDefaultsWithSteam(builder); - return new WritableJsonConfigurationProvider(this); - } - - private void EnsureDefaultsWithSteam(IConfigurationBuilder builder) - { - EnsureDefaults(builder); - - if (FileProvider is PhysicalFileProvider physicalFileProvider) - { - string? outputFile = System.IO.Path.Combine(physicalFileProvider.Root, Path); - Factory?.Build(outputFile); - } + string? outputFile = System.IO.Path.Combine(physicalFileProvider.Root, Path); + Factory?.Build(outputFile); } } } diff --git a/Toolkit.Foundation/Configurations/Write.cs b/Toolkit.Foundation/Configurations/Write.cs index f4cab41..e8fe169 100644 --- a/Toolkit.Foundation/Configurations/Write.cs +++ b/Toolkit.Foundation/Configurations/Write.cs @@ -1,6 +1,5 @@ using Mediator; -namespace Toolkit.Foundation -{ - public abstract record Write(string Section, Action UpdateDelegate) : IRequest where TConfiguration : class; -} +namespace Toolkit.Foundation; + +public abstract record Write(string Section, Action UpdateDelegate) : IRequest where TConfiguration : class; diff --git a/Toolkit.Foundation/Configurations/WriteHandler.cs b/Toolkit.Foundation/Configurations/WriteHandler.cs index fd1a64e..00973d7 100644 --- a/Toolkit.Foundation/Configurations/WriteHandler.cs +++ b/Toolkit.Foundation/Configurations/WriteHandler.cs @@ -1,30 +1,29 @@ using Mediator; -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public class WriteHandler : IRequestHandler> where TConfiguration : class { - public class WriteHandler : IRequestHandler> where TConfiguration : class + private readonly IMediator mediator; + private readonly TConfiguration configuration; + private readonly IConfigurationWriter writer; + + public WriteHandler(TConfiguration configuration, + IConfigurationWriter writer, + IMediator mediator) { - private readonly IMediator mediator; - private readonly TConfiguration configuration; - private readonly IConfigurationWriter writer; + this.mediator = mediator; + this.configuration = configuration; + this.writer = writer; + } - public WriteHandler(TConfiguration configuration, - IConfigurationWriter writer, - IMediator mediator) - { - this.mediator = mediator; - this.configuration = configuration; - this.writer = writer; - } + public async ValueTask Handle(Write request, CancellationToken cancellationToken) + { + request.UpdateDelegate.Invoke(configuration); + writer.Write(request.Section, configuration); - public async ValueTask Handle(Write request, CancellationToken cancellationToken) - { - request.UpdateDelegate.Invoke(configuration); - writer.Write(request.Section, configuration); + await mediator.Send(new ConfigurationChanged(configuration), cancellationToken); - await mediator.Send(new ConfigurationChanged(configuration), cancellationToken); - - return default; - } + return default; } } diff --git a/Toolkit.Foundation/Extensions/IHostBuilderExtensions.cs b/Toolkit.Foundation/Extensions/IHostBuilderExtensions.cs index f749f54..d948867 100644 --- a/Toolkit.Foundation/Extensions/IHostBuilderExtensions.cs +++ b/Toolkit.Foundation/Extensions/IHostBuilderExtensions.cs @@ -1,17 +1,16 @@ using Microsoft.Extensions.Hosting; -namespace Toolkit.Foundation -{ - public static class IHostBuilderExtensions - { - public static IHostBuilder UseContentRoot(this IHostBuilder hostBuilder, string contentRoot, bool createDirectory) - { - if (!Directory.Exists(contentRoot) && createDirectory) - { - Directory.CreateDirectory(contentRoot); - } +namespace Toolkit.Foundation; - return hostBuilder.UseContentRoot(contentRoot); +public static class IHostBuilderExtensions +{ + public static IHostBuilder UseContentRoot(this IHostBuilder hostBuilder, string contentRoot, bool createDirectory) + { + if (!Directory.Exists(contentRoot) && createDirectory) + { + Directory.CreateDirectory(contentRoot); } + + return hostBuilder.UseContentRoot(contentRoot); } } diff --git a/Toolkit.Foundation/Extensions/IServiceCollectionExtensions.cs b/Toolkit.Foundation/Extensions/IServiceCollectionExtensions.cs index 9b717e4..e6c737a 100644 --- a/Toolkit.Foundation/Extensions/IServiceCollectionExtensions.cs +++ b/Toolkit.Foundation/Extensions/IServiceCollectionExtensions.cs @@ -1,22 +1,29 @@ -using Mediator; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public static class IServiceCollectionExtensions { - public static class IServiceCollectionExtensions + public static IServiceCollection AddHandler(this IServiceCollection serviceCollection) { - public static IServiceCollection AddHandler(this IServiceCollection serviceCollection) - { - serviceCollection.TryAdd(new ServiceDescriptor(typeof(TRequestHandler), typeof(TRequestHandler), ServiceLifetime.Transient)); - return serviceCollection; - } + serviceCollection.TryAdd(new ServiceDescriptor(typeof(TRequestHandler), typeof(TRequestHandler), ServiceLifetime.Transient)); + return serviceCollection; + } - public static IServiceCollection AddFoundation(this IServiceCollection serviceCollection) - { - serviceCollection.AddSingleton(provider => new ServiceFactory(provider.GetService, (instanceType, parameters) => ActivatorUtilities.CreateInstance(provider, instanceType, parameters!))); + public static IServiceCollection AddFoundation(this IServiceCollection serviceCollection) + { + serviceCollection.AddSingleton(provider => new ServiceFactory(provider.GetService, (instanceType, parameters) => ActivatorUtilities.CreateInstance(provider, instanceType, parameters!))) + .AddSingleton(provider => new Initialization(() => + { + return serviceCollection.Where(x => x.ServiceType.GetInterfaces() + .Contains(typeof(IInitializable)) || x.ServiceType == typeof(IInitializable)) + .GroupBy(x => x.ServiceType) + .Select(x => x.First()) + .SelectMany(x => provider.GetServices(x.ServiceType) + .Select(x => (IInitializable?)x)).ToList(); + })); - return serviceCollection; - } + return serviceCollection; } } diff --git a/Toolkit.Foundation/Extensions/IServiceFactoryExtensions.cs b/Toolkit.Foundation/Extensions/IServiceFactoryExtensions.cs index ddb0538..f84d760 100644 --- a/Toolkit.Foundation/Extensions/IServiceFactoryExtensions.cs +++ b/Toolkit.Foundation/Extensions/IServiceFactoryExtensions.cs @@ -1,16 +1,15 @@ -namespace Toolkit.Foundation -{ - public static class IServiceFactoryExtensions - { - public static T? Create(this IServiceFactory serviceFactory, params object?[] parameters) - { - return serviceFactory.Create(typeof(T), parameters); - } +namespace Toolkit.Foundation; - public static object? Create(this IServiceFactory serviceFactory, Type type) - { - ServiceFactoryDescriptor? descriptor = new(serviceFactory); - return descriptor.Create(type); - } +public static class IServiceFactoryExtensions +{ + public static T? Create(this IServiceFactory serviceFactory, params object?[] parameters) + { + return serviceFactory.Create(typeof(T), parameters); + } + + public static object? Create(this IServiceFactory serviceFactory, Type type) + { + ServiceFactoryDescriptor? descriptor = new(serviceFactory); + return descriptor.Create(type); } } diff --git a/Toolkit.Foundation/Lifecycles/AppService.cs b/Toolkit.Foundation/Lifecycles/AppService.cs index b551a1d..946a87a 100644 --- a/Toolkit.Foundation/Lifecycles/AppService.cs +++ b/Toolkit.Foundation/Lifecycles/AppService.cs @@ -1,26 +1,25 @@ using Mediator; using Microsoft.Extensions.Hosting; -namespace Toolkit.Foundation +namespace Toolkit.Foundation; + +public class AppService : IHostedService { - public class AppService : IHostedService + private readonly IMediator mediator; + + public AppService(IMediator mediator) { - private readonly IMediator mediator; + this.mediator = mediator; + } - public AppService(IMediator mediator) - { - this.mediator = mediator; - } + public async Task StartAsync(CancellationToken cancellationToken) + { + await mediator.Send(new Initialize()); + await mediator.Send(new Initialized()); + } - public async Task StartAsync(CancellationToken cancellationToken) - { - await mediator.Send(new Initialization()); - await mediator.Send(new Initialized()); - } - - public Task StopAsync(CancellationToken cancellationToken) - { - return Task.CompletedTask; - } + public Task StopAsync(CancellationToken cancellationToken) + { + return Task.CompletedTask; } } diff --git a/Toolkit.Foundation/Lifecycles/ICache.cs b/Toolkit.Foundation/Lifecycles/ICache.cs index 6173d14..1521b2a 100644 --- a/Toolkit.Foundation/Lifecycles/ICache.cs +++ b/Toolkit.Foundation/Lifecycles/ICache.cs @@ -1,7 +1,6 @@ -namespace Toolkit.Foundation -{ - public interface ICache - { +namespace Toolkit.Foundation; + +public interface ICache +{ - } } diff --git a/Toolkit.Foundation/Lifecycles/IInitializable.cs b/Toolkit.Foundation/Lifecycles/IInitializable.cs new file mode 100644 index 0000000..a6f053b --- /dev/null +++ b/Toolkit.Foundation/Lifecycles/IInitializable.cs @@ -0,0 +1,6 @@ +namespace Toolkit.Foundation; + +public interface IInitializable +{ + Task InitializeAsync(); +} diff --git a/Toolkit.Foundation/Lifecycles/IInitialization.cs b/Toolkit.Foundation/Lifecycles/IInitialization.cs new file mode 100644 index 0000000..ee2e2ef --- /dev/null +++ b/Toolkit.Foundation/Lifecycles/IInitialization.cs @@ -0,0 +1,6 @@ +namespace Toolkit.Foundation; + +public interface IInitialization +{ + Task InitializeAsync(); +} diff --git a/Toolkit.Foundation/Lifecycles/IInitializer.cs b/Toolkit.Foundation/Lifecycles/IInitializer.cs deleted file mode 100644 index 234ecc4..0000000 --- a/Toolkit.Foundation/Lifecycles/IInitializer.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Toolkit.Foundation -{ - public interface IInitializer - { - Task InitializeAsync(); - } -} diff --git a/Toolkit.Foundation/Lifecycles/Initialization.cs b/Toolkit.Foundation/Lifecycles/Initialization.cs index 9549b4a..0869d04 100644 --- a/Toolkit.Foundation/Lifecycles/Initialization.cs +++ b/Toolkit.Foundation/Lifecycles/Initialization.cs @@ -1,6 +1,22 @@ -using Mediator; +namespace Toolkit.Foundation; -namespace Toolkit.Foundation +public class Initialization : IInitialization { - public record Initialization : IRequest; + private readonly Func> factory; + + public Initialization(Func> factory) + { + this.factory = factory; + } + + public async Task InitializeAsync() + { + foreach (IInitializable? initializer in factory()) + { + if (initializer is not null) + { + await initializer.InitializeAsync(); + } + } + } } diff --git a/Toolkit.Foundation/Lifecycles/InitializationHandler.cs b/Toolkit.Foundation/Lifecycles/InitializationHandler.cs deleted file mode 100644 index 0bb08e7..0000000 --- a/Toolkit.Foundation/Lifecycles/InitializationHandler.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Mediator; - -namespace Toolkit.Foundation -{ - public class InitializationHandler : IRequestHandler - { - private readonly IEnumerable initializers; - - public InitializationHandler(IEnumerable initializers) - { - this.initializers = initializers; - } - - public async ValueTask Handle(Initialization request, CancellationToken cancellationToken) - { - foreach (IInitializer? initializer in initializers) - { - if (initializer is not null) - { - await initializer.InitializeAsync(); - } - } - - return default; - } - } -} diff --git a/Toolkit.Foundation/Lifecycles/Initialize.cs b/Toolkit.Foundation/Lifecycles/Initialize.cs new file mode 100644 index 0000000..d93328e --- /dev/null +++ b/Toolkit.Foundation/Lifecycles/Initialize.cs @@ -0,0 +1,5 @@ +using Mediator; + +namespace Toolkit.Foundation; + +public record Initialize : IRequest; diff --git a/Toolkit.Foundation/Lifecycles/InitializeHandler.cs b/Toolkit.Foundation/Lifecycles/InitializeHandler.cs new file mode 100644 index 0000000..3f4348d --- /dev/null +++ b/Toolkit.Foundation/Lifecycles/InitializeHandler.cs @@ -0,0 +1,29 @@ +using Mediator; +using System.Diagnostics; + +namespace Toolkit.Foundation; + +public class InitializeHandler : IRequestHandler +{ + private readonly IEnumerable initializers; + + public InitializeHandler(IEnumerable initializers) + { + this.initializers = initializers; + } + + public async ValueTask Handle(Initialize request, CancellationToken cancellationToken) + { + foreach (IInitializable? initializer in initializers) + { + if (initializer is not null) + { + Trace.WriteLine(initializer.GetType()); + await initializer.InitializeAsync(); + Trace.WriteLine("Done"); + } + } + + return default; + } +} diff --git a/Toolkit.Foundation/Lifecycles/Initialized.cs b/Toolkit.Foundation/Lifecycles/Initialized.cs index b4e85b6..a13bbce 100644 --- a/Toolkit.Foundation/Lifecycles/Initialized.cs +++ b/Toolkit.Foundation/Lifecycles/Initialized.cs @@ -1,6 +1,5 @@ using Mediator; -namespace Toolkit.Foundation -{ - public record class Initialized : IRequest; -} +namespace Toolkit.Foundation; + +public record class Initialized : IRequest;