从位于内存中的JSON加载启动配置

时间:2017-06-28 16:19:20

标签: .net json build configuration core

我正在研究如何在 .Net Core 中加载启动配置。我注意到有不同的方法可以做到这一点,我已经看到了XML,JSON,init文件,以及位于内存中的Dictionary(稍后我会回到这里)。我使用的代码如下:

new ConfigurationBuilder().AddJsonFile("file.json").Build();

所有这些都没关系,但是,是否有任何方法可以从JSON字符串加载该配置?我的意思是,我不想将json存储在临时文件中,因为它是一个实时构建的文件而且毫无意义。

关于位于内存中的字典。它很容易手动构建,但是,复杂和过于分层的JSON结构呢?据我所知,字典是

  

字典<字符串,字符串>

其关键字是"连接的树的父母:"同时管理重复的节点,枚举它们等。痛苦地从头开始构建这个算法。

4 个答案:

答案 0 :(得分:9)

  • 使用nuget软件包.status> = 3.0.0
Microsoft.Extensions.Configuration.Json

答案 1 :(得分:6)

我非常喜欢Adam的答案,但是他链接到的接口实现有点单片。这是一个较小的:

public class InMemoryFileProvider : IFileProvider
{
    private class InMemoryFile : IFileInfo
    {
        private readonly byte[] _data;
        public InMemoryFile(string json) => _data = Encoding.UTF8.GetBytes(json);
        public Stream CreateReadStream() => new MemoryStream(_data);
        public bool Exists { get; } = true;
        public long Length => _data.Length;
        public string PhysicalPath { get; } = string.Empty;
        public string Name { get; } = string.Empty;
        public DateTimeOffset LastModified { get; } = DateTimeOffset.UtcNow;
        public bool IsDirectory { get; } = false;
    }

    private readonly IFileInfo _fileInfo;
    public InMemoryFileProvider(string json) => _fileInfo = new InMemoryFile(json);
    public IFileInfo GetFileInfo(string _) => _fileInfo;
    public IDirectoryContents GetDirectoryContents(string _) => null;
    public IChangeToken Watch(string _) => NullChangeToken.Singleton;
}

然后,根据亚当的回答,您可以使用:

var memoryFileProvider = new InMemoryFileProvider(jsonString);
var configuration = new ConfigurationBuilder()
    .AddJsonFile(memoryFileProvider, "appsettings.json", false, false)
    .Build();

答案 2 :(得分:3)

通过实现内存中的文件提供程序,您可以相对容易地重用现有的API(Microsoft.Extensions.Configuration.Json)。

您需要

  • 一个虚假的IFileProvider实现-类似于使用过here的实现。
  • 虚拟的IFileInfo实现-您可以借用一个from here

下面的代码演示了如何组装所有这些代码:

var json = "{ \"option1\": 1, \"option2\": \"abc\", }";
var memoryJsonFile = new MemoryFileInfo("config.json", Encoding.UTF8.GetBytes(json), DateTimeOffset.Now);
var memoryFileProvider = new MockFileProvider(memoryJsonFile);

var configuration = new ConfigurationBuilder()
    .AddJsonFile(memoryFileProvider, "config.json", false, false)
    .Build();

Console.WriteLine(configuration["option2"]);

然后你就去了;)

答案 3 :(得分:2)

在ASPNETCORE 2.0中(不确定其他版本),您可以使用var host = new WebHostBuilder() .ConfigureAppConfiguration((hostingContext, config) => { config.AddInMemoryCollection(new Dictionary<string, string>() { { "MyParentKey:MySubKey", "MyValue" } }); });

using Microsoft.Extensions.Configuration;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;

namespace Config
{
    public class JsonConfigurationParser
    {
        private JsonConfigurationParser() { }

        private readonly IDictionary<string, string> _data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        private readonly Stack<string> _context = new Stack<string>();
        private string _currentPath;

        public static IDictionary<string, string> Parse(string json) => new JsonConfigurationParser().ParseJson(json);

        private IDictionary<string, string> ParseJson(string json)
        {
            _data.Clear();

            var jsonConfig = JObject.Parse(json);

            VisitJObject(jsonConfig);

            return _data;
        }

        private 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.Bytes:
                case JTokenType.Raw:
                case JTokenType.Null:
                    VisitPrimitive(token.Value<JValue>());
                    break;

                default:
                    throw new FormatException("Unsupported JSON token");
            }
        }

        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)
        {
            var key = _currentPath;

            if (_data.ContainsKey(key))
            {
                throw new FormatException("Duplicate Key");
            }
            _data[key] = 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());
        }
    }
}

更新: 我已经从下面的链接调整了一些代码来解析JSON字符串并返回一个字典:

https://github.com/aspnet/Configuration/blob/d469707ab18eef7ed0002f00175a9ad5b0f36250/src/Config.Json/JsonConfigurationFileParser.cs

var dictionary = JsonConfigurationParser.Parse(MyJsonString);

用法:

SELECT