From fa767e5f3754b8c939b1f5a088d1c8e080f043ac Mon Sep 17 00:00:00 2001
From: bytewizer <58912473+bytewizer@users.noreply.github.com>
Date: Sun, 28 Aug 2022 20:07:16 -0700
Subject: [PATCH] Added hosting configuration json and ini file support
---
.github/workflows/actions.yml | 4 +-
src/Bytewizer.TinyCLR.Runtime.sln | 12 ++
...r.TinyCLR.Hosting.Configuration.Ini.csproj | 71 ++++++++++++
.../IniConfigurationExtensions.cs | 33 ++++++
.../IniStreamConfigurationProvider.cs | 97 ++++++++++++++++
.../IniStreamConfigurationSource.cs | 31 +++++
.../Properties/AssemblyInfo.cs | 4 +
....TinyCLR.Hosting.Configuration.Json.csproj | 79 +++++++++++++
.../FileConfigurationProvider.cs | 78 +++++++++++++
.../Configuration/FileConfigurationSource.cs | 44 +++++++
.../JsonConfigurationExtensions.cs | 62 ++++++++++
.../Configuration/JsonConfigurationParser.cs | 108 ++++++++++++++++++
.../JsonFileConfigurationProvider.cs | 30 +++++
.../JsonFileConfigurationSource.cs | 22 ++++
.../JsonStreamConfigurationProvider.cs | 30 +++++
.../JsonStreamConfigurationSource.cs | 22 ++++
.../Properties/AssemblyInfo.cs | 4 +
...wizer.TinyCLR.Hosting.Configuration.csproj | 8 --
.../Hosting/ConfigurationExtensions.cs | 25 +++-
.../Bytewizer.TinyCLR.Logging.csproj | 4 -
20 files changed, 752 insertions(+), 16 deletions(-)
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Bytewizer.TinyCLR.Hosting.Configuration.Ini.csproj
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniConfigurationExtensions.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniStreamConfigurationProvider.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniStreamConfigurationSource.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Properties/AssemblyInfo.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Bytewizer.TinyCLR.Hosting.Configuration.Json.csproj
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/FileConfigurationProvider.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/FileConfigurationSource.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonConfigurationExtensions.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonConfigurationParser.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonFileConfigurationProvider.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonFileConfigurationSource.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonStreamConfigurationProvider.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonStreamConfigurationSource.cs
create mode 100644 src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Properties/AssemblyInfo.cs
diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml
index 3efe69a..507ec1c 100644
--- a/.github/workflows/actions.yml
+++ b/.github/workflows/actions.yml
@@ -66,7 +66,7 @@ jobs:
-p:PackageOutputPath=\builds\artifacts
-p:BuildNumber="${{ steps.info.outputs.build }}"
-p:Copyright="${{ steps.info.outputs.copyright }}"
- -p:VersionPrefix="2.1.12"
+ -p:VersionPrefix="2.1.13"
-p:VersionSuffix=preview.${{ steps.info.outputs.build }}
-p:Configuration=${env:CONFIGURATION}
-p:ContinuousIntegrationBuild=true
@@ -78,7 +78,7 @@ jobs:
-p:PackageOutputPath=\builds\artifacts
-p:BuildNumber="${{ steps.info.outputs.build }}"
-p:Copyright="${{ steps.info.outputs.copyright }}"
- -p:VersionPrefix="2.1.12"
+ -p:VersionPrefix="2.1.13"
-p:VersionSuffix=preview.${{ steps.info.outputs.build }}
-p:Configuration=${env:CONFIGURATION}
-p:ContinuousIntegrationBuild=true
diff --git a/src/Bytewizer.TinyCLR.Runtime.sln b/src/Bytewizer.TinyCLR.Runtime.sln
index a2a6069..97d7811 100644
--- a/src/Bytewizer.TinyCLR.Runtime.sln
+++ b/src/Bytewizer.TinyCLR.Runtime.sln
@@ -47,6 +47,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bytewizer.TinyCLR.Hosting",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bytewizer.TinyCLR.Hosting.Configuration", "hosting\Bytewizer.TinyCLR.Hosting.Configuration\Bytewizer.TinyCLR.Hosting.Configuration.csproj", "{71492D2D-6B78-46C8-9531-C02915742A46}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bytewizer.TinyCLR.Hosting.Configuration.Ini", "hosting\Bytewizer.TinyCLR.Hosting.Configuration.Ini\Bytewizer.TinyCLR.Hosting.Configuration.Ini.csproj", "{72592D2D-6B78-46C8-9531-C02915742A46}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bytewizer.TinyCLR.Hosting.Configuration.Json", "hosting\Bytewizer.TinyCLR.Hosting.Configuration.Json\Bytewizer.TinyCLR.Hosting.Configuration.Json.csproj", "{72492D2D-6B78-46C8-9531-C02915742A46}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -141,6 +145,14 @@ Global
{71492D2D-6B78-46C8-9531-C02915742A46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{71492D2D-6B78-46C8-9531-C02915742A46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{71492D2D-6B78-46C8-9531-C02915742A46}.Release|Any CPU.Build.0 = Release|Any CPU
+ {72592D2D-6B78-46C8-9531-C02915742A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {72592D2D-6B78-46C8-9531-C02915742A46}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {72592D2D-6B78-46C8-9531-C02915742A46}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {72592D2D-6B78-46C8-9531-C02915742A46}.Release|Any CPU.Build.0 = Release|Any CPU
+ {72492D2D-6B78-46C8-9531-C02915742A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {72492D2D-6B78-46C8-9531-C02915742A46}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {72492D2D-6B78-46C8-9531-C02915742A46}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {72492D2D-6B78-46C8-9531-C02915742A46}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Bytewizer.TinyCLR.Hosting.Configuration.Ini.csproj b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Bytewizer.TinyCLR.Hosting.Configuration.Ini.csproj
new file mode 100644
index 0000000..d6429db
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Bytewizer.TinyCLR.Hosting.Configuration.Ini.csproj
@@ -0,0 +1,71 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {72592D2D-6B78-46C8-9531-C02915742A46}
+ Library
+ Properties
+ Bytewizer.TinyCLR.Hosting.Configuration.Ini
+ Bytewizer.TinyCLR.Hosting.Configuration.Ini
+ v4.8
+ 512
+ {A1948822-69DD-4150-919B-F3F42EFB71CC};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+ 9
+
+
+
+
+
+ Generic Host extention library supporting ini files built for TinyCLR IoT devices.
+ ghi tinyclr tinyclros sitcore iot generic host hosting
+ TinyCLR
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ bin\Debug\Bytewizer.TinyCLR.Hosting.Configuration.Ini.xml
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ bin\Release\Bytewizer.TinyCLR.Hosting.Configuration.Ini.xml
+
+
+
+
+
+
+
+
+
+ 2.2.0.4200
+
+
+ 2.2.0.4200
+
+
+ 6.3.0
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+ {71492D2D-6B78-46C8-9531-C02915742A46}
+ Bytewizer.TinyCLR.Hosting.Configuration
+
+
+
+
\ No newline at end of file
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniConfigurationExtensions.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniConfigurationExtensions.cs
new file mode 100644
index 0000000..2d72c3a
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniConfigurationExtensions.cs
@@ -0,0 +1,33 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.IO;
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Ini
+{
+ ///
+ /// Extension methods for adding .
+ ///
+ public static class IniConfigurationExtensions
+ {
+ ///
+ /// Adds a INI configuration source to .
+ ///
+ /// The to add to.
+ /// The to read the ini configuration data from.
+ /// The .
+ public static IConfigurationBuilder AddIniStream(this IConfigurationBuilder builder, Stream stream)
+ {
+ if (stream == null)
+ {
+ throw new ArgumentNullException();
+ }
+
+ return builder.Add(new IniStreamConfigurationSource() { Stream = stream });
+ }
+ }
+}
+
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniStreamConfigurationProvider.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniStreamConfigurationProvider.cs
new file mode 100644
index 0000000..c9d1378
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniStreamConfigurationProvider.cs
@@ -0,0 +1,97 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.IO;
+using System.Collections;
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Ini
+{
+ ///
+ /// An INI file based .
+ ///
+ public class IniStreamConfigurationProvider : StreamConfigurationProvider
+ {
+ ///
+ /// Constructor.
+ ///
+ /// The .
+ public IniStreamConfigurationProvider(IniStreamConfigurationSource source) : base(source) { }
+
+ ///
+ /// Read a stream of INI values into a key/value dictionary.
+ ///
+ /// The stream of INI data.
+ /// The which was read from the stream.
+ public static Hashtable Read(Stream stream)
+ {
+ var data = new Hashtable();
+
+ using (var reader = new StreamReader(stream))
+ {
+ string sectionPrefix = string.Empty;
+
+ while (reader.Peek() != -1)
+ {
+ string rawLine = reader.ReadLine()!; // Since Peak didn't return -1, stream hasn't ended.
+ string line = rawLine.Trim();
+
+ // Ignore blank lines
+ //if (string.IsNullOrWhiteSpace(line))
+ if (string.IsNullOrEmpty(line))
+ {
+ continue;
+ }
+ // Ignore comments
+ if (line[0] is ';' or '#' or '/')
+ {
+ continue;
+ }
+ // [Section:header]
+ if (line[0] == '[' && line[line.Length - 1] == ']')
+ {
+ // remove the brackets
+ sectionPrefix = line.Substring(1, line.Length - 2).Trim() + ":";
+
+ continue;
+ }
+
+ // key = value OR "value"
+ int separator = line.IndexOf('=');
+ if (separator < 0)
+ {
+ throw new FormatException(rawLine);
+ }
+
+ string key = sectionPrefix + line.Substring(0, separator).Trim();
+ string value = line.Substring(separator + 1).Trim();
+
+ // Remove quotes
+ if (value.Length > 1 && value[0] == '"' && value[value.Length - 1] == '"')
+ {
+ value = value.Substring(1, value.Length - 2);
+ }
+
+ if (data.Contains(key))
+ {
+ throw new FormatException(key);
+ }
+
+ data[key.ToLower()] = value;
+ }
+ }
+ return data;
+ }
+
+ ///
+ /// Loads INI configuration key/values from a stream into a provider.
+ ///
+ /// The to load ini configuration data from.
+ public override void Load(Stream stream)
+ {
+ Data = Read(stream);
+ }
+ }
+}
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniStreamConfigurationSource.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniStreamConfigurationSource.cs
new file mode 100644
index 0000000..e3cfcf3
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Configuration/IniStreamConfigurationSource.cs
@@ -0,0 +1,31 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Ini
+{
+ ///
+ /// Represents an INI file as an .
+ /// Files are simple line structures (INI Files on Wikipedia)
+ ///
+ ///
+ /// [Section:Header]
+ /// key1=value1
+ /// key2 = " value2 "
+ /// ; comment
+ /// # comment
+ /// / comment
+ ///
+ public class IniStreamConfigurationSource : StreamConfigurationSource
+ {
+ ///
+ /// Builds the for this source.
+ ///
+ /// The .
+ /// An
+ public override IConfigurationProvider Build(IConfigurationBuilder builder)
+ => new IniStreamConfigurationProvider(this);
+ }
+}
+
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Properties/AssemblyInfo.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..391013c
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Ini/Properties/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+using System.Runtime.InteropServices;
+
+[assembly: ComVisible(false)]
+[assembly: Guid("9e368003-1168-49f2-863e-8799a9436bea")]
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Bytewizer.TinyCLR.Hosting.Configuration.Json.csproj b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Bytewizer.TinyCLR.Hosting.Configuration.Json.csproj
new file mode 100644
index 0000000..c21942e
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Bytewizer.TinyCLR.Hosting.Configuration.Json.csproj
@@ -0,0 +1,79 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {72492D2D-6B78-46C8-9531-C02915742A46}
+ Library
+ Properties
+ Bytewizer.TinyCLR.Hosting.Configuration.Json
+ Bytewizer.TinyCLR.Hosting.Configuration.Json
+ v4.8
+ 512
+ {A1948822-69DD-4150-919B-F3F42EFB71CC};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+ 9
+
+
+
+
+
+ Generic Host extention library supporting json files built for TinyCLR IoT devices.
+ ghi tinyclr tinyclros sitcore iot generic host hosting
+ TinyCLR
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ bin\Debug\Bytewizer.TinyCLR.Hosting.Configuration.Json.xml
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+ bin\Release\Bytewizer.TinyCLR.Hosting.Configuration.Json.xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 2.2.0.4200
+
+
+ 2.2.0.4200
+
+
+ 2.2.0.4200
+
+
+ 6.3.0
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+ {71492D2D-6B78-46C8-9531-C02915742A46}
+ Bytewizer.TinyCLR.Hosting.Configuration
+
+
+
+
\ No newline at end of file
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/FileConfigurationProvider.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/FileConfigurationProvider.cs
new file mode 100644
index 0000000..7442087
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/FileConfigurationProvider.cs
@@ -0,0 +1,78 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.IO;
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Json
+{
+ ///
+ /// File Stream based configuration provider.
+ ///
+ public abstract class FileConfigurationProvider : ConfigurationProvider
+ {
+ ///
+ /// The source settings for this provider.
+ ///
+ public FileConfigurationSource Source { get; }
+
+ private bool _loaded;
+
+ ///
+ /// Constructor.
+ ///
+ /// The source.
+ public FileConfigurationProvider(FileConfigurationSource source)
+ {
+ if (source == null)
+ {
+ throw new ArgumentNullException();
+ }
+
+ Source = source;
+ }
+
+ ///
+ /// Generates a string representing this provider name and relevant details.
+ ///
+ /// The configuration name.
+ public override string ToString()
+ => $"{GetType().Name} for '{Source.Path}' ({(Source.Optional ? "optional" : "required")})";
+
+ ///
+ /// Load the configuration data from the stream.
+ ///
+ /// The data stream.
+ public abstract void Load(Stream stream);
+
+ ///
+ /// Load the configuration data from the stream. Will throw after the first call.
+ ///
+ public override void Load()
+ {
+ if (_loaded)
+ {
+ throw new InvalidOperationException();
+ }
+
+ try
+ {
+ var filePath = $"{Source.DriveProvider.Name}{Source.Path}";
+ Source.Stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
+
+ Load(Source.Stream);
+ }
+ catch (Exception ex)
+ {
+ if (!Source.Optional)
+ {
+ throw ex;
+ }
+ }
+
+ _loaded = true;
+ }
+ }
+}
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/FileConfigurationSource.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/FileConfigurationSource.cs
new file mode 100644
index 0000000..1433f32
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/FileConfigurationSource.cs
@@ -0,0 +1,44 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System.IO;
+using GHIElectronics.TinyCLR.IO;
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Json
+{
+ ///
+ /// File based .
+ ///
+ public abstract class FileConfigurationSource : IConfigurationSource
+ {
+ ///
+ /// The stream containing the configuration data.
+ ///
+ public Stream Stream { get; set; }
+
+ ///
+ /// The path to the file.
+ ///
+ public string Path { get; set; }
+
+ ///
+ /// Determines if loading the file is optional.
+ ///
+ public bool Optional { get; set; }
+
+ ///
+ /// The drive provider to the file.
+ ///
+ public IDriveProvider DriveProvider { get; set; }
+
+ ///
+ /// Builds the for this source.
+ ///
+ /// The .
+ /// An
+ public abstract IConfigurationProvider Build(IConfigurationBuilder builder);
+ }
+}
+
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonConfigurationExtensions.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonConfigurationExtensions.cs
new file mode 100644
index 0000000..56f0946
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonConfigurationExtensions.cs
@@ -0,0 +1,62 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.IO;
+
+using GHIElectronics.TinyCLR.IO;
+using GHIElectronics.TinyCLR.Devices.Storage;
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Json
+{
+ ///
+ /// Extension methods for adding .
+ ///
+ public static class JsonConfigurationExtensions
+ {
+ ///
+ /// Adds the JSON configuration provider at to .
+ ///
+ /// The to add to.
+ /// Path relative to the base path stored in
+ /// of .
+ /// Whether the file is optional.
+ /// The .
+ public static IConfigurationBuilder AddJsonFile(this IConfigurationBuilder builder, string path, bool optional)
+ {
+ if (builder == null)
+ {
+ throw new ArgumentNullException();
+ }
+
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentNullException();
+ }
+
+ var controller = StorageController.GetDefault();
+ var driveProvider = FileSystem.Mount(controller.Hdc);
+
+ return builder.Add(new JsonFileConfigurationSource()
+ { Path = path, Optional = optional, DriveProvider = driveProvider });
+ }
+
+ ///
+ /// Adds a JSON configuration source to .
+ ///
+ /// The to add to.
+ /// The to read the json configuration data from.
+ /// The .
+ public static IConfigurationBuilder AddJsonStream(this IConfigurationBuilder builder, Stream stream)
+ {
+ if (stream == null)
+ {
+ throw new ArgumentNullException();
+ }
+
+ return builder.Add(new JsonStreamConfigurationSource() { Stream = stream });
+ }
+ }
+}
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonConfigurationParser.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonConfigurationParser.cs
new file mode 100644
index 0000000..61e34ea
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonConfigurationParser.cs
@@ -0,0 +1,108 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System;
+using System.IO;
+using System.Collections;
+using System.Diagnostics;
+
+using GHIElectronics.TinyCLR.Data.Json;
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Json
+{
+ internal sealed class JsonConfigurationParser
+ {
+ private readonly Hashtable _data = new Hashtable();
+
+ public static Hashtable Parse(Stream input)
+ => new JsonConfigurationParser().ParseStream(input);
+
+ private Hashtable ParseStream(Stream input)
+ {
+ try
+ {
+ JToken token = JsonConverter.Deserialize(input);
+
+ if (token is JObject jobj)
+ {
+ foreach (JProperty member in jobj.Members)
+ {
+ foreach (DictionaryEntry pair in GetNode(member))
+ {
+ _data.Add(
+ pair.Key.ToString().ToLower(),
+ pair.Value.ToString().Trim('"').TrimEnd('"')
+ );
+ }
+ }
+ }
+
+ if (token is JArray jarray)
+ {
+ for (int i = 0; i < jarray.Length; i++)
+ {
+ var property = new JProperty($"root{i}", jarray[i]);
+
+ foreach (DictionaryEntry pair in GetNode(property))
+ {
+ _data.Add(
+ pair.Key.ToString().ToLower(),
+ pair.Value.ToString().Trim('"').TrimEnd('"')
+ );
+ }
+ }
+ }
+ }
+ catch
+ {
+ throw new FormatException("Could not parse the JSON file.");
+ }
+
+ return _data;
+ }
+
+ private static ArrayList GetNode(JProperty node)
+ {
+ var items = new ArrayList();
+
+ if (node.Value is JObject jobj)
+ {
+ foreach (JProperty member in jobj.Members)
+ {
+ var key = string.Concat(node.Name, ":", member.Name);
+ var values = GetNode(new JProperty(key, member.Value));
+
+ foreach (DictionaryEntry pair in values)
+ {
+ items.Add(pair);
+ }
+ }
+
+ return items;
+ }
+
+ if (node.Value is JArray jarray)
+ {
+ for (int i = 0; i < jarray.Length; i++)
+ {
+ var key = string.Concat(node.Name, ":", i);
+ var values = GetNode(new JProperty(key, jarray[i]));
+
+ foreach (DictionaryEntry pair in values)
+ {
+ items.Add(pair);
+ }
+ }
+
+ return items;
+ }
+
+ items.Add(new DictionaryEntry (node.Name, node.Value));
+
+ return items;
+ }
+ }
+}
+
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonFileConfigurationProvider.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonFileConfigurationProvider.cs
new file mode 100644
index 0000000..9c0d8eb
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonFileConfigurationProvider.cs
@@ -0,0 +1,30 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System.IO;
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Json
+{
+ ///
+ /// Loads configuration key/values from a json file stream into a provider.
+ ///
+ public class JsonFileConfigurationProvider : FileConfigurationProvider
+ {
+ ///
+ /// Constructor.
+ ///
+ /// The .
+ public JsonFileConfigurationProvider(JsonFileConfigurationSource source) : base(source) { }
+
+ ///
+ /// Loads json configuration key/values from a stream into a provider.
+ ///
+ /// The json to load configuration data from.
+ public override void Load(Stream stream)
+ {
+ Data = JsonConfigurationParser.Parse(stream);
+ }
+ }
+}
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonFileConfigurationSource.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonFileConfigurationSource.cs
new file mode 100644
index 0000000..e8b90f3
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonFileConfigurationSource.cs
@@ -0,0 +1,22 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Json
+{
+ ///
+ /// Represents a JSON file as an .
+ ///
+ public class JsonFileConfigurationSource : FileConfigurationSource
+ {
+ ///
+ /// Builds the for this source.
+ ///
+ /// The .
+ /// An
+ public override IConfigurationProvider Build(IConfigurationBuilder builder)
+ => new JsonFileConfigurationProvider(this);
+ }
+}
+
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonStreamConfigurationProvider.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonStreamConfigurationProvider.cs
new file mode 100644
index 0000000..3c43405
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonStreamConfigurationProvider.cs
@@ -0,0 +1,30 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+using System.IO;
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Json
+{
+ ///
+ /// Loads configuration key/values from a json stream into a provider.
+ ///
+ public class JsonStreamConfigurationProvider : StreamConfigurationProvider
+ {
+ ///
+ /// Constructor.
+ ///
+ /// The .
+ public JsonStreamConfigurationProvider(JsonStreamConfigurationSource source) : base(source) { }
+
+ ///
+ /// Loads json configuration key/values from a stream into a provider.
+ ///
+ /// The json to load configuration data from.
+ public override void Load(Stream stream)
+ {
+ Data = JsonConfigurationParser.Parse(stream);
+ }
+ }
+}
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonStreamConfigurationSource.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonStreamConfigurationSource.cs
new file mode 100644
index 0000000..f957240
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Configuration/JsonStreamConfigurationSource.cs
@@ -0,0 +1,22 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// See LICENSE file in the project root for full license information.
+//
+
+namespace Bytewizer.TinyCLR.Hosting.Configuration.Json
+{
+ ///
+ /// Represents a JSON file as an .
+ ///
+ public class JsonStreamConfigurationSource : StreamConfigurationSource
+ {
+ ///
+ /// Builds the for this source.
+ ///
+ /// The .
+ /// An
+ public override IConfigurationProvider Build(IConfigurationBuilder builder)
+ => new JsonStreamConfigurationProvider(this);
+ }
+}
+
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Properties/AssemblyInfo.cs b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..391013c
--- /dev/null
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration.Json/Properties/AssemblyInfo.cs
@@ -0,0 +1,4 @@
+using System.Runtime.InteropServices;
+
+[assembly: ComVisible(false)]
+[assembly: Guid("9e368003-1168-49f2-863e-8799a9436bea")]
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration/Bytewizer.TinyCLR.Hosting.Configuration.csproj b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration/Bytewizer.TinyCLR.Hosting.Configuration.csproj
index 2ea24c7..a5cfeec 100644
--- a/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration/Bytewizer.TinyCLR.Hosting.Configuration.csproj
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting.Configuration/Bytewizer.TinyCLR.Hosting.Configuration.csproj
@@ -70,18 +70,10 @@
-
- {70392D1D-6B78-46C8-9531-C02915742A46}
- Bytewizer.TinyCLR.Core
-
{F5997E37-7348-4FA6-9103-990D9906DA4F}
Bytewizer.TinyCLR.DependencyInjection.Abstractions
-
- {AEB62F01-BA5F-45E3-A82C-4D2E058046A3}
- Bytewizer.TinyCLR.DependencyInjection
-
{70492D2D-6B78-46C8-9531-C02915742A46}
Bytewizer.TinyCLR.Hosting
diff --git a/src/hosting/Bytewizer.TinyCLR.Hosting/Hosting/ConfigurationExtensions.cs b/src/hosting/Bytewizer.TinyCLR.Hosting/Hosting/ConfigurationExtensions.cs
index 476ff64..46525b3 100644
--- a/src/hosting/Bytewizer.TinyCLR.Hosting/Hosting/ConfigurationExtensions.cs
+++ b/src/hosting/Bytewizer.TinyCLR.Hosting/Hosting/ConfigurationExtensions.cs
@@ -57,8 +57,9 @@ public static object GetOrDefault(this IConfiguration configuration, string key,
}
var type = defaultValue.GetType();
+
if (type == typeof(string)) return (string)value;
- //if (type == typeof(bool)) return ((string)value).ToLower() == "true";
+ if (type == typeof(bool)) return ((string)value).ToBoolean();
if (type == typeof(int)) return int.Parse((string)value);
if (type == typeof(uint)) return uint.Parse((string)value);
if (type == typeof(byte)) return byte.Parse((string)value);
@@ -68,8 +69,28 @@ public static object GetOrDefault(this IConfiguration configuration, string key,
if (type == typeof(long)) return long.Parse((string)value);
if (type == typeof(ulong)) return ulong.Parse((string)value);
if (type == typeof(double)) return double.Parse((string)value);
-
+
return value;
}
}
+
+ internal static class StringExtensions
+ {
+ public static bool ToBoolean(this string value)
+ {
+ switch (value.ToLower().Trim())
+ {
+ case "true":
+ return true;
+ case "1":
+ return true;
+ case "false":
+ return false;
+ case "0":
+ return false;
+ default:
+ return false;
+ }
+ }
+ }
}
diff --git a/src/logging/Bytewizer.TinyCLR.Logging/Bytewizer.TinyCLR.Logging.csproj b/src/logging/Bytewizer.TinyCLR.Logging/Bytewizer.TinyCLR.Logging.csproj
index 26271d9..87e90d0 100644
--- a/src/logging/Bytewizer.TinyCLR.Logging/Bytewizer.TinyCLR.Logging.csproj
+++ b/src/logging/Bytewizer.TinyCLR.Logging/Bytewizer.TinyCLR.Logging.csproj
@@ -75,10 +75,6 @@
{F5997E37-7348-4FA6-9103-990D9906DA4F}
Bytewizer.TinyCLR.DependencyInjection.Abstractions
-
- {AEB62F01-BA5F-45E3-A82C-4D2E058046A3}
- Bytewizer.TinyCLR.DependencyInjection
-
{598D7917-49D1-4E76-BFF4-23221BAD7072}
Bytewizer.TinyCLR.Logging.Abstractions