.NET中捕获表单数组值的正则表达式问题求助
解决自定义模型绑定器中表单数组值的解析问题
问题核心
你当前的实现把表单键值对直接拼接成扁平JSON,像"filterList[0].filterType"这种带索引的键无法被JSON反序列化器识别为数组结构,导致模型绑定失败。你尝试的正则表达式因未匹配开头的{和空格,漏过了第一个键值对。
不推荐正则的原因
正则处理结构化数据容易出现边界错误(比如值包含引号、特殊字符时匹配失效),且维护成本高。更可靠的方式是直接解析表单键的层级结构,构建正确的嵌套对象/数组。
结构化解析的解决方案
直接遍历表单键,拆分键的层级路径(比如filterList[0].filterType拆分为数组filterList的第0个元素的filterType属性),逐步构建对应的嵌套对象,最后直接映射到目标模型。
实现代码示例
private static async Task HandleFormAsync(HttpContext httpContext, ModelBindingContext bindingContext) { var form = await httpContext.Request.ReadFormAsync(); var modelObj = new JObject(); foreach (var kvp in form) { var current = modelObj; var keyParts = SplitFormKey(kvp.Key); for (int i = 0; i < keyParts.Length; i++) { var part = keyParts[i]; // 处理带索引的数组键,如filterList[0] if (part.Contains("[")) { var arrayName = part.Split('[')[0]; if (!int.TryParse(part.Split('[', ']')[1], out var index)) { bindingContext.Result = ModelBindingResult.Failed(); return; } // 确保数组存在,不存在则创建 if (!current.TryGetValue(arrayName, out var arrayToken) || arrayToken.Type != JTokenType.Array) { arrayToken = new JArray(); current[arrayName] = arrayToken; } var array = (JArray)arrayToken; // 确保数组元素数量足够,不足则补空对象 while (array.Count <= index) { array.Add(new JObject()); } // 最后一个层级直接赋值,否则切换到数组元素继续处理 if (i == keyParts.Length - 1) { array[index] = JToken.FromObject(kvp.Value); } else { current = (JObject)array[index]; } } else { // 处理普通属性键 if (i == keyParts.Length - 1) { current[part] = JToken.FromObject(kvp.Value); } else { // 确保对象存在,不存在则创建 if (!current.TryGetValue(part, out var objToken) || objToken.Type != JTokenType.Object) { objToken = new JObject(); current[part] = objToken; } current = (JObject)objToken; } } } } try { var model = modelObj.ToObject(bindingContext.ModelType); bindingContext.Result = ModelBindingResult.Success(model); } catch (JsonException) { bindingContext.Result = ModelBindingResult.Failed(); } } // 安全拆分表单键,避免误拆数组括号内的字符 private static string[] SplitFormKey(string key) { var parts = new List<string>(); var currentPart = new StringBuilder(); bool inBracket = false; foreach (var c in key) { if (c == '.' && !inBracket) { parts.Add(currentPart.ToString()); currentPart.Clear(); } else { if (c == '[') inBracket = true; if (c == ']') inBracket = false; currentPart.Append(c); } } parts.Add(currentPart.ToString()); return parts.ToArray(); }
代码说明
- SplitFormKey方法:安全拆分表单键,确保数组括号内的字符不会被误拆分(比如
list[0].item.name会被拆分为["list[0]", "item", "name"])。 - 嵌套结构构建:遍历拆分后的键层级,逐步创建数组、对象,将表单值赋值到对应位置,保证结构符合目标模型的要求。
- 直接映射模型:通过
JObject.ToObject直接转换为目标模型类型,无需手动拼接JSON,避免格式错误。
正则表达式的临时修复(不推荐)
如果一定要用正则,调整表达式以匹配开头的{和空格:
(?:\{|\s|,)\s*"(?<arrayName>\w+\[\d+\])\.(?<propertyName>\w+)"\s*:\s*"(?<value>.*?)"\s*(?:,|})
但仍建议使用结构化解析方案,避免正则带来的各种边界问题。
内容的提问来源于stack exchange,提问作者ShanieMoonlight
相关产品推荐
相关产品推荐

