简体   繁体   English

将 Akka.net 与 IConfiguration 结合使用

[英]Using Akka.net with IConfiguration

Almost all Akka.net documentation refers to documentation through HOCON in some form.几乎所有 Akka.net 文档都以某种形式引用通过 HOCON 的文档。 From my understanding, HOCON was made to tackle issues related to XML-based configuration in .NET Framework.据我了解,HOCON 是为了解决 .NET Framework 中基于 XML 的配置相关问题而创建的。 Now that everything in JSON-based (starting in .NET Core), I would really want to configure Akka.net through appsettings.json, just like any other service I write in .NET. Some solutions I have found to this approach seem rather hacky by pasting a HOCON string in the appsettings file, or have the HOCON object inline in the source code.现在一切都基于 JSON(从 .NET Core 开始),我真的很想通过 appsettings.json 配置 Akka.net,就像我在 .NET 中编写的任何其他服务一样。我发现这种方法的一些解决方案看起来很老套在 appsettings 文件中粘贴 HOCON 字符串,或者在源代码中内联 HOCON object。 It would be very nice to have it within an appsettings since this fits better in how both my team manages configuration, deployment-wise, and modern .NET applications approach configuration.将它放在应用程序设置中会非常好,因为这更适合我的团队如何管理配置、部署方式和现代 .NET 应用程序方法配置。

Why is Akka.net using HOCON instead of a more abstract interface such as IConfiguration, and how can I best configure it by following best practices in .NET using appsettings.json and IConfiguration?为什么 Akka.net 使用 HOCON 而不是 IConfiguration 等更抽象的接口,我如何才能按照 .NET 中的最佳实践使用 appsettings.json 和 IConfiguration 对其进行最佳配置?

I believe one of the reasons why Akka.net uses HOCON is due to how it is a 1-1 port of Akka (Java), which also heavily relies on HOCON for configuration.我相信 Akka.net 使用 HOCON 的原因之一是它是 Akka (Java) 的 1-1 端口,它也严重依赖 HOCON 进行配置。 For portability it is then the preferred format for configuring the framework.为了可移植性,它是配置框架的首选格式。 While it is just speculation from my side, it could be a priority thing why there is no support for IConfiguration since the current way of configuration "just works" even though it fits poorly together with how newer .NET applications are written today.虽然这只是我的猜测,但为什么不支持IConfiguration可能是一个优先事项,因为当前的配置方式“正常工作”,尽管它与今天编写的更新的 .NET 应用程序的方式不太吻合。

There are a few ways that the Akka.Configuration.Config can be built from an IConfiguration instance.有几种方法可以从IConfiguration实例构建Akka.Configuration.Config One way is to take the IConfiguration object, and construct a JSON string from it, then give it to ConfigurationFactory.ParseString which does support parsing JSON. A HOCON representation can then be obtained from the parsed Config instance.一种方法是采用IConfiguration object,并从中构造一个 JSON 字符串,然后将其提供给支持解析 JSON 的ConfigurationFactory.ParseString 。然后可以从解析的Config实例中获取 HOCON 表示。 In order to correctly parse a JSON object, the generated HOCON string has to parsed again (my guess is because of a bug that makes it interpret JSON and HOCON differently).为了正确解析 JSON object,生成的 HOCON 字符串必须再次解析(我的猜测是因为一个 bug 导致它以不同的方式解释 JSON 和 HOCON)。 Make sure the JSON config does not contain any properties such as {"foo.don": "bar"} , while HOCON supports resolving foo.don - JSON does not.确保 JSON 配置不包含任何属性,例如{"foo.don": "bar"} ,而 HOCON 支持解析foo.don - JSON 不支持。 Below is the extension method I put together for parsing a Config from an IConfiguration instance:下面是我放在一起用于从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;
    }
}

A better solution would be to implement a parser, similar to how Akka.Configuration.Hocon.Parser builds up the Config object. This would be a much better solution than the hacky approach above:更好的解决方案是实现解析器,类似于Akka.Configuration.Hocon.Parser构建Config object 的方式。这将是比上面的 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;
    }
}

In either case, an appsettings.json with element containing the Akka configuration can then be parsed with either of the approaches above.在任何一种情况下,一个 appsettings.json 的元素包含 Akka 配置,然后可以使用上述任何一种方法进行解析。 For example:例如:

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

where the config can be retrieved by:可以通过以下方式检索配置的位置:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM