【问题标题】:Using Akka.net with IConfiguration将 Akka.net 与 IConfiguration 一起使用
【发布时间】:2021-10-01 22:14:29
【问题描述】:

几乎所有 Akka.net 文档都以某种形式通过 HOCON 引用文档。据我了解,HOCON 旨在解决与 .NET Framework 中基于 XML 的配置相关的问题。现在一切都基于 JSON(从 .NET Core 开始),我真的想通过 appsettings.json 配置 Akka.net,就像我在 .NET 中编写的任何其他服务一样。通过在 appsettings 文件中粘贴 HOCON 字符串,或者在源代码中内联 HOCON 对象,我发现这种方法的一些解决方案似乎相当麻烦。将它包含在 appsettings 中会非常好,因为这更适合我的团队管理配置、部署方式和现代 .NET 应用程序方法配置的方式。

为什么 Akka.net 使用 HOCON 而不是更抽象的接口(如 IConfiguration),以及如何按照 .NET 中使用 appsettings.json 和 IConfiguration 的最佳实践来最好地配置它?

【问题讨论】:

    标签: c# .net akka.net


    【解决方案1】:

    我相信 Akka.net 使用 HOCON 的原因之一是因为它是 Akka (Java) 的 1-1 端口,它也严重依赖 HOCON 进行配置。对于可移植性,它是配置框架的首选格式。虽然这只是我的猜测,但它可能是为什么不支持 IConfiguration 的优先事项,因为当前的配置方式“正常工作”,即使它与当今较新的 .NET 应用程序的编写方式不匹配。

    有几种方法可以从IConfiguration 实例构建Akka.Configuration.Config。一种方法是获取IConfiguration 对象,并从中构造一个JSON 字符串,然后将其提供给支持解析JSON 的ConfigurationFactory.ParseString。然后可以从解析的Config 实例中获得 HOCON 表示。 为了正确解析 JSON 对象,必须再次解析生成的 HOCON 字符串(我的猜测是因为一个错误导致它以不同方式解释 JSON 和 HOCON)。 确保 JSON 配置不包含任何属性,例如 {"foo.don" : "bar"},而 HOCON 支持解析 foo.don - JSON 不支持。下面是我为从IConfiguration 实例解析Config 而整理的扩展方法:

    public static class ConfigurationExtensions
    {
        public static Config ToAkkaConfiguration(this IConfiguration config)
        {
            var jToken = BuildJToken(config);
            var jsonString = JsonConvert.SerializeObject(jToken);
            var hocon = ConfigurationFactory.ParseString(jsonString);
    
            return hocon;
        }
    
        // Based on https://stackoverflow.com/a/62533775/1924825
        private static JToken BuildJToken(IConfiguration config)
        {
            var obj = new JObject();
    
            foreach (var child in config.GetChildren())
            {
                if (child.Path.EndsWith(":0"))
                {
                    var arr = new JArray();
    
                    foreach (var arrayChild in config.GetChildren())
                    {
                        arr.Add(BuildJToken(arrayChild));
                    }
    
                    return arr;
                }
                else
                {
                    obj.Add(child.Key, BuildJToken(child));
                }
            }
    
            if (!obj.HasValues && config is IConfigurationSection section)
            {
                if (long.TryParse(section.Value, out long integer))
                {
                    return new JValue(integer);
                }
                else if (bool.TryParse(section.Value, out bool boolean))
                {
                    return new JValue(boolean);
                }
                else if (decimal.TryParse(section.Value, out decimal real))
                {
                    return new JValue(real);
                }
    
                return new JValue(section.Value);
            }
    
            return obj;
        }
    }
    

    更好的解决方案是实现一个解析器,类似于Akka.Configuration.Hocon.Parser 构建Config 对象的方式。这将是比上面的 hacky 方法更好的解决方案:

    public static class ConfigurationExtensions
    {
        public static Config ToAkkaConfiguration(this IConfiguration config)
        {
            var root = new HoconValue();
            ParseConfig(root, config);
            var hconRoot = new HoconRoot(root);
            return new Config(hconRoot);
        }
    
        private static void ParseConfig(HoconValue owner, IConfiguration config)
        {
            if (config is IConfigurationSection section && !config.GetChildren().Any())
            {
                var lit = new HoconLiteral { Value = section.Value };
                owner.AppendValue(lit);
            }
            else
            {
                foreach (var child in config.GetChildren())
                {
                    if (child.Path.EndsWith(":0"))
                    {
                        var array = ParseArray(config);
                        owner.AppendValue(array);
                        return;
                    }
                    else
                    {
                        if (owner.GetObject() == null)
                            owner.NewValue(new HoconObject());
    
                        var key = owner.GetObject().GetOrCreateKey(child.Key);
    
                        ParseConfig(key, child);
                    }
                }
            }
        }
    
        private static HoconArray ParseArray(IConfiguration config)
        {
            var arr = new HoconArray();
    
            foreach (var arrayChild in config.GetChildren())
            {
                var value = new HoconValue();
                ParseConfig(value, arrayChild);
                arr.Add(value);
            }
    
            return arr;
        }
    }
    

    在任何一种情况下,都可以使用上述任何一种方法解析具有包含 Akka 配置的元素的 appsettings.json。例如:

    {
      "AkkaConfiguration": {
        "akka": {
          "actor": {
            "provider": "cluster"
          },
          "remote": {
            "dot-netty": {
              "tcp": {
                "port": 8081,
                "hostname": "localhost"
              }
            }
          },
          "cluster": {
            "seed-nodes": [ "akka.tcp://test@localhost:8081" ],
            "roles": [ "myService" ]
          }
        }
      }
    }
    
    

    可以通过以下方式检索配置的位置:

    var config = config.GetSection("AkkaConfiguration").ToAkkaConfiguration();
    

    【讨论】:

      猜你喜欢
      • 2015-06-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多