Сбой ExecuteXmlReader для конкретного JSON из SQL Server - PullRequest
0 голосов
/ 08 июня 2018

У меня есть рабочий процесс, который получает сгенерированный JSON из процедур хранения в SQL Server с использованием директивы for JSON.Но после получения определенного текста в данных столбца возникает ошибка ExecuteXmlReader в операции Read.

Исключение

XmlException:'=' - неожиданный токен.Ожидаемый токен - «;».Строка 1, позиция 94

Который, если бы я управлял выводом, скорее всего, поместил бы его в раздел CDATA.

Данные, возвращаемые с SQL Server

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-адрес, сохраненный в таблице

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?

Как ни странно, когда вы щелкаете по значению столбца таблицы JSON в SSMS, выдает ту же ошибку.

enter image description here

Ответы [ 2 ]

0 голосов
/ 10 июня 2018

С тех пор я сделал это загружаемым пакетом NUGET.См. SQLJSONReader с обновлениями для async.


Я воспользовался советом Дэвида и пометил его как ответ, но мне нужен был весь сырой JSON.

Поэтому я добавил убранный вызов к Newtonsoft.Json.JsonTextReader, потому что он не вернул мне просто строку, и изменил класс расширения Дэвида, чтобы он возвращал весь JSON, вызвав ReadAll.

Обратите внимание, что он использует JsonConvert.DeserializeObject.

кода Newtonsoft

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();

}
0 голосов
/ 08 июня 2018

Я предложу вам использовать неправильные API для чтения результатов запроса FOR JSON.Вот небольшой вспомогательный класс, который реализует метод расширения SqlCommand.ExecuteJsonReader ().

    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();
            }

        }


    }
...