// Use like this:
// var hostBuilder = new HostBuilder()
// .ConfigureHostConfiguration(cfg => {
// cfg.Add(new JObjectConfigurationSource(new JObject()));
// })
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
namespace MyNamespace
{
public class JObjectConfigurationSource : ConfigurationProvider, IConfigurationSource
{
private readonly JObject _jObject;
private readonly IDictionary<string, string> _data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
private readonly Stack<string> _context = new Stack<string>();
private string _currentPath;
public JObjectConfigurationSource(JObject jObject) => _jObject = jObject;
public IConfigurationProvider Build(IConfigurationBuilder builder) => this;
public override void Load()
{
Data = ParseStream(_jObject);
}
private IDictionary<string, string> ParseStream(JObject jObject)
{
_data.Clear();
VisitJObject(jObject);
return _data;
}
public void VisitJObject(JObject jObject)
{
foreach (var property in jObject.Properties())
{
EnterContext(property.Name);
VisitProperty(property);
ExitContext();
}
}
private void VisitProperty(JProperty property)
{
VisitToken(property.Value);
}
private void VisitToken(JToken token)
{
switch (token.Type)
{
case JTokenType.Object:
VisitJObject(token.Value<JObject>());
break;
case JTokenType.Array:
VisitArray(token.Value<JArray>());
break;
case JTokenType.Integer:
case JTokenType.Float:
case JTokenType.String:
case JTokenType.Boolean:
case JTokenType.Null:
case JTokenType.Raw:
case JTokenType.Bytes:
VisitPrimitive(token.Value<JValue>());
break;
default:
throw new FormatException();
}
}
private void VisitArray(JArray array)
{
for (int index = 0; index < array.Count; ++index)
{
EnterContext(index.ToString());
VisitToken(array[index]);
ExitContext();
}
}
private void VisitPrimitive(JValue data)
{
string currentPath = _currentPath;
if (_data.ContainsKey(currentPath))
{
throw new FormatException();
}
_data[currentPath] = data.ToString(CultureInfo.InvariantCulture);
}
private void EnterContext(string context)
{
_context.Push(context);
_currentPath = ConfigurationPath.Combine(_context.Reverse());
}
private void ExitContext()
{
_context.Pop();
_currentPath = ConfigurationPath.Combine(_context.Reverse());
}
}
}