如何将嵌套对象转换为带扁平化参数名的查询字符串?
我需要把下面的嵌套请求对象转换成指定格式的查询字符串:
var parameter = new RulesCommandServiceAppendRequest() { Chain = Chain.INPUT, Data = new RuleInputModel() { Protocol = "tcp", SourceIp = "2.2.2.2", DestinationIp = "1.1.1.1", SourcePort = "111", DestinationPort = "222", Jump = "DROP" } };
期望的查询字符串格式:
Chain=INPUT&Data.DestinationIp=1.1.1.1&Data.DestinationPort=222&Data.Jump=DROP&Data.Protocol=tcp&Data.SourceIp=2.2.2.2&Data.SourcePort=111
我尝试用WebSerializer库调用WebSerializer.ToQueryString(parameter),得到的结果不符合预期:
Chain=INPUT&Data=DestinationIp=1.1.1.1&DestinationPort=222&Jump=DROP&Protocol=tcp&SourceIp=2.2.2.2&SourcePort=111
这个结果无法被我的ASP.NET Web API .NET 6服务端识别,请问有没有其他可用的库,或者修正WebSerializer使用方式的技巧?
可行解决方案
1. 手动构建键值对生成查询字符串
直接用System.Net.Http的FormUrlEncodedContent手动拼接带层级前缀的键值对,简单直接:
var keyValuePairs = new List<KeyValuePair<string, string>> { new("Chain", parameter.Chain.ToString()), new("Data.Protocol", parameter.Data.Protocol), new("Data.SourceIp", parameter.Data.SourceIp), new("Data.DestinationIp", parameter.Data.DestinationIp), new("Data.SourcePort", parameter.Data.SourcePort), new("Data.DestinationPort", parameter.Data.DestinationPort), new("Data.Jump", parameter.Data.Jump) }; var content = new FormUrlEncodedContent(keyValuePairs); string queryString = await content.ReadAsStringAsync();
2. 用Newtonsoft.Json递归生成嵌套格式
利用Newtonsoft.Json的序列化能力,递归遍历对象结构生成带层级的键值对:
using Newtonsoft.Json.Linq; public static string ToNestedQueryString(object obj, string prefix = "") { var properties = JObject.FromObject(obj); var keyValuePairs = new List<string>(); foreach (var prop in properties) { var key = string.IsNullOrEmpty(prefix) ? prop.Key : $"{prefix}.{prop.Key}"; if (prop.Value is JObject nestedObj) { keyValuePairs.Add(ToNestedQueryString(nestedObj, key)); } else { var value = Uri.EscapeDataString(prop.Value.ToString()); keyValuePairs.Add($"{key}={value}"); } } return string.Join("&", keyValuePairs); } // 使用示例 string queryString = ToNestedQueryString(parameter);
3. 用ASP.NET Core工具类结合反射展开对象
借助Microsoft.AspNetCore.WebUtilities的QueryHelpers,配合反射递归扁平化嵌套对象:
using System.Reflection; using Microsoft.AspNetCore.WebUtilities; public static Dictionary<string, string> FlattenObject(object obj, string prefix = "") { var result = new Dictionary<string, string>(); foreach (PropertyInfo prop in obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { var value = prop.GetValue(obj); if (value == null) continue; var key = string.IsNullOrEmpty(prefix) ? prop.Name : $"{prefix}.{prop.Name}"; if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string)) { var nestedDict = FlattenObject(value, key); foreach (var nestedKvp in nestedDict) { result[nestedKvp.Key] = nestedKvp.Value; } } else { result[key] = value.ToString(); } } return result; } // 使用示例 var flattened = FlattenObject(parameter); string queryString = QueryHelpers.AddQueryString("", flattened);
4. 调整WebSerializer配置(若支持)
检查WebSerializer是否支持自定义嵌套格式配置:比如给RuleInputModel的属性添加前缀注解,或者修改全局序列化契约,让嵌套对象的属性自动带上父级属性名作为前缀。如果库本身提供这类配置,调整后即可生成符合要求的格式。
内容的提问来源于stack exchange,提问作者sorosh_sabz

