簡體   English   中英

將 Akka.net 與 IConfiguration 結合使用

[英]Using Akka.net with IConfiguration

幾乎所有 Akka.net 文檔都以某種形式引用通過 HOCON 的文檔。 據我了解,HOCON 是為了解決 .NET Framework 中基於 XML 的配置相關問題而創建的。 現在一切都基於 JSON(從 .NET Core 開始),我真的很想通過 appsettings.json 配置 Akka.net,就像我在 .NET 中編寫的任何其他服務一樣。我發現這種方法的一些解決方案看起來很老套在 appsettings 文件中粘貼 HOCON 字符串,或者在源代碼中內聯 HOCON object。 將它放在應用程序設置中會非常好,因為這更適合我的團隊如何管理配置、部署方式和現代 .NET 應用程序方法配置。

為什么 Akka.net 使用 HOCON 而不是 IConfiguration 等更抽象的接口,我如何才能按照 .NET 中的最佳實踐使用 appsettings.json 和 IConfiguration 對其進行最佳配置?

我相信 Akka.net 使用 HOCON 的原因之一是它是 Akka (Java) 的 1-1 端口,它也嚴重依賴 HOCON 進行配置。 為了可移植性,它是配置框架的首選格式。 雖然這只是我的猜測,但為什么不支持IConfiguration可能是一個優先事項,因為當前的配置方式“正常工作”,盡管它與今天編寫的更新的 .NET 應用程序的方式不太吻合。

有幾種方法可以從IConfiguration實例構建Akka.Configuration.Config 一種方法是采用IConfiguration object,並從中構造一個 JSON 字符串,然后將其提供給支持解析 JSON 的ConfigurationFactory.ParseString 。然后可以從解析的Config實例中獲取 HOCON 表示。 為了正確解析 JSON object,生成的 HOCON 字符串必須再次解析(我的猜測是因為一個 bug 導致它以不同的方式解釋 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 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;
    }
}

在任何一種情況下,一個 appsettings.json 的元素包含 Akka 配置,然后可以使用上述任何一種方法進行解析。 例如:

{
  "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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM