来自 SQL 服务器的特定 JSON 上的 ExecuteXmlReader 失败
ExecuteXmlReader Fails on Specific JSON from SQL Server
我有一个现有的工作进程,它使用 for JSON
指令从 SQL 服务器中的存储过程接收生成的 JSON。但是在列数据中收到特定文本后,Read
操作中的 ExecuteXmlReader
失败。
异常
XmlException: '=' is an unexpected token. The expected token is ';'.
Line 1, position 94
如果我控制输出,我很可能会把它放在 CDATA 部分。
从 SQL 服务器返回的数据
JSON_F52E2B61-18A1-11d1-B105-00805F49916B
{"photoId":1000000007,"photoType":"image\/gif","photoUrl":"https:\/\/slack-imgs.com\/?c=1&url=https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2F3o84U9arAYRM73AIvu%2Fgiphy-downsized.gif" }
最终 JSON 应由 Read
返回的字符串
{
"photoId": 1000000007,
"photoType": "image/gif",
"photoUrl": "https://slack-imgs.com/?c=1&url=https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2F3o84U9arAYRM73AIvu%2Fgiphy-downsized.gif",
"isActive": true
}
URL 保存到 Table
https://slack-imgs.com/?c=1&url=https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2F3o84U9arAYRM73AIvu%2Fgiphy-downsized.gif
最终这是 SQL Server 2016 的更改,但我需要比 Microsoft 提供的修复更快的修复。那么,是否可以通过 SQL 或 C# .Net 代码来解决这个问题?
奇怪的是,当在 SSMS 中单击 table 列值 JSON 时,它会给出相同的错误。
我会继续并建议您使用错误的 API 来读取 FOR JSON 查询结果。这是一个实现 SqlCommand.ExecuteJsonReader() 扩展方法的小帮手 class。
static class SqlJsonUtils
{
public static Newtonsoft.Json.JsonReader ExecuteJsonReader(this SqlCommand cmd)
{
var rdr = cmd.ExecuteReader();
var jr = new Newtonsoft.Json.JsonTextReader(new SqlJSONReader(rdr));
return jr;
}
class SqlJSONReader : System.IO.TextReader
{
SqlDataReader rdr;
string currentLine = "";
int currentPos = 0;
public SqlJSONReader(SqlDataReader rdr)
{
this.rdr = rdr;
}
public override int Peek()
{
return GetChar(false);
}
public override int Read()
{
return GetChar(true);
}
public int GetChar(bool Advance)
{
while (currentLine.Length == currentPos)
{
if (!rdr.Read())
{
return -1;
}
currentLine = rdr.GetString(0);
currentPos = 0;
}
int rv = (int)currentLine[currentPos];
if (Advance) currentPos += 1;
return rv;
}
public override void Close()
{
rdr.Close();
}
}
}
此后我将其设为可下载的 NUGET 包。请参阅 SQLJSONReader 异步更新。
我采纳了 David 的建议并将他的标记为答案,但我需要整个原始 JSON。
所以我添加删除了对 Newtonsoft.Json.JsonTextReader
的调用,因为它不会 return 我只是一个字符串,并将 David 的扩展名 class 修改为 return 整个 JSON 通过调用 ReadAll
。
请注意,它使用了 Newtonsoft 的 JsonConvert.DeserializeObject
。
代码
public static SqlJSONReader ExecuteJsonReader(this SqlCommand cmd)
{
var rdr = cmd.ExecuteReader();
return new SqlJSONReader(rdr);
}
public class SqlJSONReader : System.IO.TextReader
{
private SqlDataReader SqlReader { get; set; }
private string CurrentLine { get; set; }
private int CurrentPostion { get; set; }
public SqlJSONReader(SqlDataReader rdr)
{
CurrentLine = "";
CurrentPostion = 0;
this.SqlReader = rdr;
}
public override int Peek()
{
return GetChar(false);
}
public override int Read()
{
return GetChar(true);
}
public int GetChar(bool Advance)
{
while (CurrentLine.Length == CurrentPostion)
{
if (!SqlReader.Read())
{
return -1;
}
CurrentLine = SqlReader.GetString(0);
CurrentPostion = 0;
}
var rv = CurrentLine[CurrentPostion];
if (Advance)
CurrentPostion += 1;
return rv;
}
public string ReadAll()
{
var sbResult = new StringBuilder();
if (SqlReader.HasRows)
{
while (SqlReader.Read())
sbResult.Append(SqlReader.GetString(0));
}
else
return string.Empty;
// Clean up any JSON escapes before returning
return JsonConvert.DeserializeObject(sbResult.ToString()).ToString();
}
public override void Close() { SqlReader.Close(); }
}
用法
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "exec [dbo].[GetPhoto] @PhotoId=4";
conn.Open();
var rdr = cmd.ExecuteJsonReader();
string jsonResult = rdr.ReadAll();
conn.Close();
}
我有一个现有的工作进程,它使用 for JSON
指令从 SQL 服务器中的存储过程接收生成的 JSON。但是在列数据中收到特定文本后,Read
操作中的 ExecuteXmlReader
失败。
异常
XmlException: '=' is an unexpected token. The expected token is ';'. Line 1, position 94
如果我控制输出,我很可能会把它放在 CDATA 部分。
从 SQL 服务器返回的数据
JSON_F52E2B61-18A1-11d1-B105-00805F49916B
{"photoId":1000000007,"photoType":"image\/gif","photoUrl":"https:\/\/slack-imgs.com\/?c=1&url=https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2F3o84U9arAYRM73AIvu%2Fgiphy-downsized.gif" }
最终 JSON 应由 Read
{
"photoId": 1000000007,
"photoType": "image/gif",
"photoUrl": "https://slack-imgs.com/?c=1&url=https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2F3o84U9arAYRM73AIvu%2Fgiphy-downsized.gif",
"isActive": true
}
URL 保存到 Table
https://slack-imgs.com/?c=1&url=https%3A%2F%2Fmedia0.giphy.com%2Fmedia%2F3o84U9arAYRM73AIvu%2Fgiphy-downsized.gif
最终这是 SQL Server 2016 的更改,但我需要比 Microsoft 提供的修复更快的修复。那么,是否可以通过 SQL 或 C# .Net 代码来解决这个问题?
奇怪的是,当在 SSMS 中单击 table 列值 JSON 时,它会给出相同的错误。
我会继续并建议您使用错误的 API 来读取 FOR JSON 查询结果。这是一个实现 SqlCommand.ExecuteJsonReader() 扩展方法的小帮手 class。
static class SqlJsonUtils
{
public static Newtonsoft.Json.JsonReader ExecuteJsonReader(this SqlCommand cmd)
{
var rdr = cmd.ExecuteReader();
var jr = new Newtonsoft.Json.JsonTextReader(new SqlJSONReader(rdr));
return jr;
}
class SqlJSONReader : System.IO.TextReader
{
SqlDataReader rdr;
string currentLine = "";
int currentPos = 0;
public SqlJSONReader(SqlDataReader rdr)
{
this.rdr = rdr;
}
public override int Peek()
{
return GetChar(false);
}
public override int Read()
{
return GetChar(true);
}
public int GetChar(bool Advance)
{
while (currentLine.Length == currentPos)
{
if (!rdr.Read())
{
return -1;
}
currentLine = rdr.GetString(0);
currentPos = 0;
}
int rv = (int)currentLine[currentPos];
if (Advance) currentPos += 1;
return rv;
}
public override void Close()
{
rdr.Close();
}
}
}
此后我将其设为可下载的 NUGET 包。请参阅 SQLJSONReader 异步更新。
我采纳了 David 的建议并将他的标记为答案,但我需要整个原始 JSON。
所以我添加删除了对 Newtonsoft.Json.JsonTextReader
的调用,因为它不会 return 我只是一个字符串,并将 David 的扩展名 class 修改为 return 整个 JSON 通过调用 ReadAll
。
请注意,它使用了 Newtonsoft 的 JsonConvert.DeserializeObject
。
代码
public static SqlJSONReader ExecuteJsonReader(this SqlCommand cmd)
{
var rdr = cmd.ExecuteReader();
return new SqlJSONReader(rdr);
}
public class SqlJSONReader : System.IO.TextReader
{
private SqlDataReader SqlReader { get; set; }
private string CurrentLine { get; set; }
private int CurrentPostion { get; set; }
public SqlJSONReader(SqlDataReader rdr)
{
CurrentLine = "";
CurrentPostion = 0;
this.SqlReader = rdr;
}
public override int Peek()
{
return GetChar(false);
}
public override int Read()
{
return GetChar(true);
}
public int GetChar(bool Advance)
{
while (CurrentLine.Length == CurrentPostion)
{
if (!SqlReader.Read())
{
return -1;
}
CurrentLine = SqlReader.GetString(0);
CurrentPostion = 0;
}
var rv = CurrentLine[CurrentPostion];
if (Advance)
CurrentPostion += 1;
return rv;
}
public string ReadAll()
{
var sbResult = new StringBuilder();
if (SqlReader.HasRows)
{
while (SqlReader.Read())
sbResult.Append(SqlReader.GetString(0));
}
else
return string.Empty;
// Clean up any JSON escapes before returning
return JsonConvert.DeserializeObject(sbResult.ToString()).ToString();
}
public override void Close() { SqlReader.Close(); }
}
用法
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "exec [dbo].[GetPhoto] @PhotoId=4";
conn.Open();
var rdr = cmd.ExecuteJsonReader();
string jsonResult = rdr.ReadAll();
conn.Close();
}