В настоящее время я ищу простой способ сериализации объектов (в C # 3).
Я погуглил несколько примеров и придумал что-то вроде:
MemoryStream memoryStream = new MemoryStream ( );
XmlSerializer xs = new XmlSerializer ( typeof ( MyObject) );
XmlTextWriter xmlTextWriter = new XmlTextWriter ( memoryStream, Encoding.UTF8 );
xs.Serialize ( xmlTextWriter, myObject);
string result = Encoding.UTF8.GetString(memoryStream .ToArray());
Прочитав этот вопрос, я спросил себя, почему бы не использовать StringWriter? Вроде намного проще.
XmlSerializer ser = new XmlSerializer(typeof(MyObject));
StringWriter writer = new StringWriter();
ser.Serialize(writer, myObject);
serializedValue = writer.ToString();
Другая проблема заключалась в том, что первый пример сгенерировал XML, который я не мог просто записать в столбец XML базы данных SQL Server 2005.
Первый вопрос: есть ли причина, по которой мне не следует использовать StringWriter для сериализации объекта, когда он мне впоследствии понадобится в виде строки? Я так и не нашел результата с помощью StringWriter при поиске в Google.
Во-вторых, конечно: если вы не должны делать это с помощью StringWriter (по каким-либо причинам), что было бы хорошим и правильным способом?
Дополнение:
Как уже упоминалось в обоих ответах, я подробнее остановлюсь на проблеме XML в БД.
При записи в БД возникло следующее исключение:
System.Data.SqlClient.SqlException: синтаксический анализ XML: строка 1, символ 38, невозможно переключить кодировку
Для строки
<?xml version="1.0" encoding="utf-8"?><test/>
Я взял строку, созданную из XmlTextWriter, и просто поместил туда как xml. Этот не работал (ни при ручной вставке в БД).
Впоследствии я попытался вставить вручную (просто написав INSERT INTO ...) с помощью encoding = "utf-16", что тоже не удалось. Удаление кодировки полностью сработало. После этого я вернулся к коду StringWriter и вуаля - все заработало.
Проблема: я действительно не понимаю, почему.
Кристиан Хейтер: С этими тестами я не уверен, что мне нужно использовать utf-16 для записи в БД. Тогда не будет ли работать кодировка UTF-16 (в теге xml)?
источник
Ответы:
<TL; DR> На самом деле проблема довольно проста: вы не сопоставляете заявленную кодировку (в объявлении XML) с типом данных входного параметра. Если вы вручную добавили
<?xml version="1.0" encoding="utf-8"?><test/>
строку, то объявлениеSqlParameter
типа как типаSqlDbType.Xml
илиSqlDbType.NVarChar
выдаст вам ошибку «Невозможно переключить кодировку». Затем, при вставке вручную через T-SQL, поскольку вы переключили объявленную кодировку на значение «быть»utf-16
, вы явно вставлялиVARCHAR
строку (без префикса «N» в верхнем регистре, следовательно, 8-битная кодировка, такая как UTF-8) а неNVARCHAR
строку (с префиксом «N» в верхнем регистре, следовательно, 16-битная кодировка UTF-16 LE).Исправление должно было быть таким простым, как:
encoding="utf-8"
: просто не добавляйте декларацию XML.encoding="utf-16"
: либоSqlDbType.NVarChar
вместоSqlDbType.VarChar
:-) (или, возможно, даже переключитесь на использованиеSqlDbType.Xml
)(Подробный ответ ниже)
Все ответы здесь слишком сложны и ненужны (независимо от 121 и 184 голосов за ответы Кристиана и Джона соответственно). Они могут предоставить рабочий код, но на самом деле ни один из них не отвечает на вопрос. Проблема в том, что никто по-настоящему не понял вопроса, который в конечном итоге касается того, как работает тип данных XML в SQL Server. Ничего не имею против этих двух явно умных людей, но этот вопрос практически не имеет ничего общего с сериализацией в XML. Сохранить данные XML в SQL Server намного проще, чем то, что здесь подразумевается.
На самом деле не имеет значения, как создается XML, если вы следуете правилам создания XML-данных в SQL Server. У меня есть более подробное объяснение (включая рабочий пример кода для иллюстрации пунктов, изложенных ниже) в ответ на этот вопрос: Как решить ошибку «невозможно переключить кодировку» при вставке XML в SQL Server , но основные положения:
NVARCHAR(MAX)
илиXML
/SqlDbType.NVarChar
(maxsize = -1) илиSqlDbType.Xml
, или, если используется строковый литерал, он должен иметь префикс «N» в верхнем регистре.VARCHAR(MAX)
/SqlDbType.VarChar
(maxsize = -1), или, если используется строковый литерал, он не должен иметь префикс с заглавной буквой «N».Принимая во внимание изложенные выше моменты и учитывая, что строки в .NET всегда имеют формат UTF-16 LE / UCS-2 LE (нет разницы между ними с точки зрения кодировки), мы можем ответить на ваши вопросы:
Нет, с вашим
StringWriter
кодом все в порядке (по крайней мере, я не вижу проблем в моем ограниченном тестировании с использованием второго блока кода из вопроса).Предоставлять XML-декларацию необязательно. Если он отсутствует, предполагается, что кодировка будет UTF-16 LE, если вы передадите строку в SQL Server как
NVARCHAR
(т.е.SqlDbType.NVarChar
) илиXML
(т.е.SqlDbType.Xml
). Предполагается, что кодировка является 8-битной кодовой страницей по умолчанию, если она передается какVARCHAR
(т.е.SqlDbType.VarChar
). Если у вас есть какие-либо символы нестандартного ASCII (например, значения 128 и выше) и вы передаете их какVARCHAR
, то вы, вероятно, увидите "?" для символов BMP и "??" для дополнительных символов, поскольку SQL Server преобразует строку UTF-16 из .NET в 8-битную строку кодовой страницы текущей базы данных перед ее обратным преобразованием в UTF-16 / UCS-2. Но ошибок не должно быть.С другой стороны, если вы укажете объявление XML, вы должны передать в SQL Server соответствующий 8-битный или 16-битный тип данных. Поэтому, если у вас есть объявление, в котором указано, что используется кодировка UCS-2 или UTF-16, вы должны передать как
SqlDbType.NVarChar
илиSqlDbType.Xml
. Или, если у вас есть заявление о том , что кодирование является одним из 8-битных вариантов (то естьUTF-8
,Windows-1252
,iso-8859-1
и т.д.), то вы должны пройти какSqlDbType.VarChar
. Несоответствие заявленной кодировки правильному 8- или 16-битному типу данных SQL Server приведет к полученной вами ошибке «Невозможно переключить кодировку».Например, используя ваш
StringWriter
код сериализации, я просто распечатал полученную строку XML и использовал ее в SSMS. Как вы можете видеть ниже, декларация XML включена (потомуStringWriter
что не имеет опцииOmitXmlDeclaration
какXmlWriter
делает), что не представляет проблемы, если вы передаете строку как правильный тип данных SQL Server:Как видите, он обрабатывает даже символы, выходящие за рамки стандартного ASCII, учитывая, что
ሴ
это точка кода BMP U + 1234 и😸
точка кода дополнительного символа U + 1F638. Однако следующее:приводит к следующей ошибке:
Таким образом, если отбросить все эти объяснения, полное решение вашего исходного вопроса:
Вы явно передавали строку как
SqlDbType.VarChar
. Переключитесь на,SqlDbType.NVarChar
и он будет работать без необходимости выполнять дополнительный шаг по удалению объявления XML. Это предпочтительнее сохраненияSqlDbType.VarChar
и удаления объявления XML, потому что это решение предотвратит потерю данных, когда XML включает символы нестандартного ASCII. Например:Как видите, на этот раз ошибки нет, но теперь есть потеря данных 🙀.
источник
SqlDbType.NVarChar
илиXml
.Одна из проблем
StringWriter
заключается в том, что по умолчанию он не позволяет вам устанавливать кодировку, которую он рекламирует, поэтому вы можете получить XML-документ, рекламирующий его кодировку как UTF-16, что означает, что вам нужно закодировать его как UTF-16, если вы записать это в файл. У меня есть небольшой класс, чтобы помочь с этим:Или, если вам нужен только UTF-8 (это все, что мне часто нужно):
Что касается того, почему вы не смогли сохранить свой XML в базе данных - вам нужно будет предоставить нам более подробную информацию о том, что произошло, когда вы попытались, если вы хотите, чтобы мы могли диагностировать / исправить это.
источник
StringWriter
кодировка не принимается во внимание, но тем не менее, спасибо за отличный метод :)MemoryStream
и aStreamWriter
с правильной кодировкой.StreamWriter
этоTextWriter
(тип , которыйXmlWriter.Create
ожидает) с возможностью настройки кодирования, в конце концов.При сериализации XML-документа в строку .NET необходимо установить кодировку UTF-16. Строки хранятся внутри как UTF-16, так что это единственная кодировка, которая имеет смысл. Если вы хотите хранить данные в другой кодировке, вместо этого используйте массив байтов.
SQL Server работает по аналогичному принципу; любая строка, передаваемая в
xml
столбец, должна быть закодирована как UTF-16. SQL Server отклонит любую строку, в которой в объявлении XML не указан UTF-16. Если объявление XML отсутствует, то стандарт XML требует, чтобы по умолчанию использовался UTF-8, поэтому SQL Server также отклонит его.Имея это в виду, вот несколько служебных методов для выполнения преобразования.
источник
StringWriter
ожидаемой. Смотрите мой ответ. Формат внутреннего хранилища здесь не имеет значения.Nothing
неявно конвертируется в любой тип. Я исправилDeserialize
код.Serialize
Предупреждение должно быть Resharper только вещь, компилятор сам по себе не возражает , и это законно сделать.Прежде всего, остерегайтесь старых примеров. Вы нашли тот, который использует
XmlTextWriter
, который устарел в .NET 2.0.XmlWriter.Create
следует использовать вместо этого.Вот пример сериализации объекта в столбец XML:
источник
XmlReader
может ее анализировать. Он будет отправлен в базу данных предварительно проанализированным, и тогда БД не нужно будет ничего знать о кодировках символов - UTF-16 или иначе. В частности, обратите внимание, что объявления XML даже не сохраняются вместе с данными в базе данных, независимо от того, какой метод используется для их вставки. Пожалуйста, не тратите впустую, выполняя XML через дополнительные преобразования, как показано в других ответах здесь и в другом месте.источник
Это могло быть описано в другом месте, но простое изменение строки кодировки источника XML на «utf-16» позволяет вставить XML в тип xml'data SQL Server.
В результате весь текст XML вставляется в поле типа данных «xml», но строка «заголовок» удаляется. То, что вы видите в результирующей записи, просто
Использование метода сериализации, описанного в записи «Ответил», - это способ включения исходного заголовка в целевое поле, но в результате оставшийся текст XML заключен в
<string></string>
тег XML .Адаптер таблицы в коде - это класс, автоматически созданный с помощью мастера Visual Studio 2013 «Добавить новый источник данных:». Пять параметров для вставки метода сопоставляют поля в таблице SQL Server.
источник