将 Akka.net 与 IConfiguration 一起使用
Using Akka.net with IConfiguration
几乎所有 Akka.net 文档都以某种形式引用通过 HOCON 的文档。根据我的理解,HOCON 是为了解决与 .NET Framework 中基于 XML 的配置相关的问题。现在一切都基于 JSON(从 .NET Core 开始),我真的很想配置 Akka.net 到 appsettings.json,就像我在 .NET 中编写的任何其他服务一样。我发现通过在 appsettings 文件中粘贴一个 HOCON 字符串,或者在源代码中内联 HOCON 对象,我发现这种方法的一些解决方案看起来很老套。将它放在应用程序设置中会非常好,因为这更适合我的团队如何管理配置、部署方式和现代 .NET 应用程序方法配置。
为什么 Akka.net 使用 HOCON 而不是更抽象的接口,例如 IConfiguration,我如何才能按照 .NET 中使用 appsettings.json 和 IConfiguration 的最佳实践最好地配置它?
我认为 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
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;
}
}
在任何一种情况下,一个 appsettings.json with element 包含 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();
几乎所有 Akka.net 文档都以某种形式引用通过 HOCON 的文档。根据我的理解,HOCON 是为了解决与 .NET Framework 中基于 XML 的配置相关的问题。现在一切都基于 JSON(从 .NET Core 开始),我真的很想配置 Akka.net 到 appsettings.json,就像我在 .NET 中编写的任何其他服务一样。我发现通过在 appsettings 文件中粘贴一个 HOCON 字符串,或者在源代码中内联 HOCON 对象,我发现这种方法的一些解决方案看起来很老套。将它放在应用程序设置中会非常好,因为这更适合我的团队如何管理配置、部署方式和现代 .NET 应用程序方法配置。
为什么 Akka.net 使用 HOCON 而不是更抽象的接口,例如 IConfiguration,我如何才能按照 .NET 中使用 appsettings.json 和 IConfiguration 的最佳实践最好地配置它?
我认为 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
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;
}
}
在任何一种情况下,一个 appsettings.json with element 包含 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();