.NET Core中使用DotLiquid结合ExpandoObject无法绑定数组内对象属性
问题根因
属性绑定失效的核心原因是仅对最外层模型做了ExpandoObject到DotLiquid Hash的转换,嵌套结构内的对象没有做适配转换:
- Newtonsoft.Json反序列化带嵌套对象的JSON时,数组内的每个JSON对象会被解析为独立的
ExpandoObject,外层的数组字段会被解析为List<object>类型,列表元素就是这些独立的嵌套ExpandoObject - DotLiquid默认的属性访问逻辑,只能识别手动传入的
Hash类型对象的键,无法直接读取原生ExpandoObject的属性,因此数组索引定位到的嵌套对象,没法继续访问其内部的属性值 - 测试中能正常运行的用例,是因为数组里是字符串这类基础类型,不需要额外的类型转换,DotLiquid可以直接读取渲染
解决方案
编写递归转换方法,把模型结构里所有嵌套的ExpandoObject、集合元素都适配为DotLiquid可识别的结构,替换原来仅转换根节点的逻辑:
- 对识别到的
ExpandoObject,通过Hash.FromDictionary转为DotLiquid标准的Hash结构 - 对识别到的可枚举集合(排除字符串类型),遍历每个元素递归做适配转换
- 基础值类型(字符串、数字、布尔值等)直接返回即可
转换方法实现:
private static object ConvertToLiquidCompatible(object input) { // 将ExpandoObject转换为DotLiquid可识别的Hash结构 if (input is ExpandoObject expandoObj) { return Hash.FromDictionary(expandoObj); } // 递归处理集合元素,排除字符串避免被错误拆分为字符集合 if (input is IEnumerable enumerable && input is not string) { var convertedList = new List<object>(); foreach (var item in enumerable) { convertedList.Add(ConvertToLiquidCompatible(item)); } return convertedList; } // 基础值类型直接返回 return input; }
修改原有的Render逻辑,替换模型适配部分:
private static void Render(string modelString, string template) { var model = JsonConvert.DeserializeObject<ExpandoObject>(modelString); // 通过递归方法完成全结构的适配转换 var templateModel = (Hash)ConvertToLiquidCompatible(model); var html = Template.Parse(template).Render(templateModel); Console.WriteLine(html); }
优化注意事项
- 如果需要模板和属性名不区分大小写匹配,可以在应用初始化时配置DotLiquid的命名约定:
Template.NamingConvention = new DotLiquid.NamingConventions.CSharpNamingConvention();配置后模板里写小写的属性名,也能正常匹配JSON里PascalCase格式的键 - 递归转换时必须排除字符串类型,否则字符串会被拆分为单字符的集合,导致渲染逻辑异常
内容的提问来源于stack exchange,提问作者LP13
相关产品推荐
相关产品推荐

