.NET9中如何将JsonDocument转换为RulesEngine可处理的格式以解决路径查找失败问题
嘿,我刚好碰到过类似的情况,咱们来一步步解决这个问题!
问题根源
你遇到的路径找不到错误,核心原因是:RulesEngine需要的是普通的CLR对象(比如匿名类型、强类型POCO或者ExpandoObject),而你之前的两种尝试都没生成这种对象:
- 直接用
data.RootElement.GetRawText()得到的是JSON字符串,不是可解析的对象; - 直接调用
JsonSerializer.Deserialize不指定类型时,System.Text.Json会把JSON对象反序列化为JsonElement(而不是匿名对象),RulesEngine解析时会识别到它的内部属性(比如ValueKind),导致路径匹配失败。
而你手动创建的匿名对象new { external = new { terminal = "1234" } }能正常工作,正是因为它是标准的CLR对象,RulesEngine可以直接遍历它的属性。
解决方案
根据你的场景,这里有三种可行的方法,你可以按需选择:
1. 反序列化为匿名类型(适合结构固定的场景)
既然手动创建的匿名对象有效,我们可以用匿名类型作为模板,把JsonDocument反序列化成对应的匿名对象:
private static async ValueTask<List<RuleResultTree>> MapAndExecute(JsonDocument data, RulesEngine.RulesEngine rulesEngine, string workflowName) { // 定义和你的JSON结构完全匹配的匿名类型模板 var template = new { External = new { Terminal = "", Previous = 0, Now = 0, StringCollection = new List<string>() } }; // 反序列化RootElement到匿名类型,可选开启大小写不敏感匹配 var parsedData = JsonSerializer.Deserialize( data.RootElement, template.GetType(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true } ); return await rulesEngine.ExecuteAllRulesAsync(workflowName, new RuleParameter("ruleData", parsedData)); }
这样反序列化出来的对象和你手动创建的匿名对象结构完全一致,RulesEngine就能正确解析ruleData.External.Terminal这类路径了。
2. 反序列化为ExpandoObject(适合动态结构的场景)
如果你的JSON结构不固定,用ExpandoObject会更灵活,它是.NET原生的动态类型,RulesEngine可以正常解析它的属性:
private static async ValueTask<List<RuleResultTree>> MapAndExecute(JsonDocument data, RulesEngine.RulesEngine rulesEngine, string workflowName) { var parsedData = JsonSerializer.Deserialize<ExpandoObject>( data.RootElement, new JsonSerializerOptions { PropertyNameCaseInsensitive = true } ); return await rulesEngine.ExecuteAllRulesAsync(workflowName, new RuleParameter("ruleData", parsedData)); }
这种方法不需要提前知道JSON结构,适合处理动态输入的场景。
3. 创建强类型POCO类(推荐用于结构固定的生产环境)
如果你的JSON结构是固定的,最推荐的方式是创建对应的强类型类,这样既有编译时类型检查,性能也更好:
// 先定义匹配JSON结构的POCO类 public class ExternalInfo { public string Terminal { get; set; } public int Previous { get; set; } public int Now { get; set; } public List<string> StringCollection { get; set; } } public class RuleInput { public ExternalInfo External { get; set; } } // 修改你的方法 private static async ValueTask<List<RuleResultTree>> MapAndExecute(JsonDocument data, RulesEngine.RulesEngine rulesEngine, string workflowName) { var parsedData = JsonSerializer.Deserialize<RuleInput>( data.RootElement, new JsonSerializerOptions { PropertyNameCaseInsensitive = true } ); return await rulesEngine.ExecuteAllRulesAsync(workflowName, new RuleParameter("ruleData", parsedData)); }
强类型的好处是能避免拼写错误,而且调试和维护起来更方便。
注意事项
如果你的规则里用的是小写路径(比如ruleData.external.terminal),记得在反序列化时开启PropertyNameCaseInsensitive = true,这样JSON里的External会和规则里的external正确匹配。
内容来源于stack exchange

