C#中如何还原Azure SQL数据库中转义双大括号的JSON数据
解决Azure SQL中转义双大括号JSON的解析问题
这个场景确实很头疼——直接全局替换{{和}}虽然简单,但很容易误伤字符串内容里的合法双大括号(比如如果某个字段值是"{{VIP}} Customer",替换后就会变成"{VIP} Customer",完全破坏了原始数据)。不过用Newtonsoft.Json的话,我们可以通过自定义解析逻辑,精准区分JSON语法层面的双大括号和字符串值内部的双大括号,完美解决这个问题。
核心思路
我们需要写一个自定义的TextReader包装器,它会在读取字符流时:
- 跟踪当前是否处于JSON的字符串值内部(通过检测双引号切换状态)
- 仅在非字符串的语法区域,把连续的
{{替换为单个{,}}替换为单个} - 字符串内部的双大括号保持原样,不做修改
实现代码
首先定义自定义的Reader类:
using Newtonsoft.Json; using System.IO; public class DoubleBracketJsonReader : TextReader { private readonly TextReader _innerReader; private bool _inString; private char? _pendingChar; public DoubleBracketJsonReader(TextReader innerReader) { _innerReader = innerReader; } public override int Read() { // 先处理上次遗留的字符 if (_pendingChar.HasValue) { var c = _pendingChar.Value; _pendingChar = null; return c; } var currentInt = _innerReader.Read(); if (currentInt == -1) return -1; char currentChar = (char)currentInt; // 切换字符串状态(遇到双引号时) if (currentChar == '"') { _inString = !_inString; return currentInt; } // 仅在非字符串区域处理双大括号 if (!_inString) { if (currentChar == '{') { var nextInt = _innerReader.Read(); if (nextInt == -1) return currentInt; char nextChar = (char)nextInt; if (nextChar == '{') { // 遇到{{,返回单个{ return '{'; } else { // 不是连续的{,把下一个字符存起来下次返回 _pendingChar = nextChar; return currentInt; } } else if (currentChar == '}') { var nextInt = _innerReader.Read(); if (nextInt == -1) return currentInt; char nextChar = (char)nextInt; if (nextChar == '}') { // 遇到}},返回单个} return '}'; } else { _pendingChar = nextChar; return currentInt; } } } // 其他情况直接返回原字符 return currentInt; } }
然后用这个Reader来解析你的转义JSON:
// 从Azure SQL读取的转义JSON字符串 var escapedJson = "{{\"Id\":10,\"Title\":\"Account Data\",\"Date\":\"0001-01-01T00:00:00.000Z\",\"Data\":{{\"Id\":22,\"Name\":\"My Object\"}}}}"; // 使用自定义Reader解析 using var stringReader = new StringReader(escapedJson); using var customReader = new DoubleBracketJsonReader(stringReader); var parsedObject = JsonConvert.DeserializeObject<JObject>(customReader); // 输出格式化后的合法JSON Console.WriteLine(parsedObject.ToString(Formatting.Indented));
为什么这个方案可靠?
- 精准区分场景:只有当双大括号出现在JSON的语法位置(比如对象/数组的开头结尾)时才会替换,字符串内部的双大括号完全保留。
- 无需修改存储:直接在读取解析环节处理,完全不影响Azure SQL里的原始数据。
- 兼容复杂JSON:即使嵌套多层对象,或者字符串里包含特殊字符,都能正确解析。
额外说明
如果你的双大括号是因为双重序列化导致的(比如先把对象序列化为JSON字符串,然后又把这个字符串再次序列化,导致{被转义为\{,但存储时丢失了反斜杠变成{{),也可以用这个方案处理——本质上它解决的是同一个解析问题。
内容的提问来源于stack exchange,提问作者Lucas Araujo
相关产品推荐
相关产品推荐

