Баг в XmlSerializer.Deserialize...
От: VVitaliy Россия  
Дата: 03.02.06 05:50
Оценка:
Обаружил противный баг в методе XmlSerializer.Deserialize.
Суть:
Если сериализован класс со строковыми полями содержащими escapе characters like \r\n\t то сериализуются они нормально, при десериализации вычитываются в поток тоже нормально, но как только мы делаем Deserialize для объекта то в стоковые поля попают с строки с искаженными последовательностями таких символов. Наблюдаются разные искажения но чаще всего исчезает символ \r или он же заменяется на \t.

Была мысль поотлаживать создаваемый слр код десериализатора, а смысл,
потеряю времени день два, может даже найду баг, а чего дальше с этим делать, собственный десериализатор для нескольких десятков классов как-то не вписывается в проект по срокам...

Это критичная часть проекта, и как обойти не представляю, вынимать строки через regexp... бред.

Есть у кого какие мнения по данному поводу?
Re: Баг в XmlSerializer.Deserialize...
От: MatFiz Россия  
Дата: 03.02.06 06:47
Оценка: 60 (8)
Здравствуйте, VVitaliy, Вы писали:

VV>Обаружил противный баг в методе XmlSerializer.Deserialize.

VV>Суть:
VV>Если сериализован класс со строковыми полями содержащими escapе characters like \r\n\t то сериализуются они нормально, при десериализации вычитываются в поток тоже нормально, но как только мы делаем Deserialize для объекта то в стоковые поля попают с строки с искаженными последовательностями таких символов. Наблюдаются разные искажения но чаще всего исчезает символ \r или он же заменяется на \t.

VV>Была мысль поотлаживать создаваемый слр код десериализатора, а смысл,

VV>потеряю времени день два, может даже найду баг, а чего дальше с этим делать, собственный десериализатор для нескольких десятков классов как-то не вписывается в проект по срокам...

VV>Это критичная часть проекта, и как обойти не представляю, вынимать строки через regexp... бред.


VV>Есть у кого какие мнения по данному поводу?


Вот код:

Program.cs
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.Xml;
using System.Text;
using System.IO;

namespace XmlSerialization
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            string param = "a\rb\nc\td";
            Class1 class1 = new Class1(param, param);

            XmlSerializer ser = new XmlSerializer(typeof(Class1));
            StringBuilder sb = new StringBuilder();
            StringWriter sw = new StringWriter(sb);

            XmlWriterSettings xws = new XmlWriterSettings();  // Смотри сюда
            xws.NewLineHandling = NewLineHandling.Entitize;   // Особенно сюда
            xws.Indent = true;
            XmlWriter xw = XmlTextWriter.Create(sw, xws);
            ser.Serialize(xw, class1);

            string serializedObject = sb.ToString();
            Console.WriteLine(serializedObject);

            StringReader sr = new StringReader(serializedObject);
            Class1 deserCalss1 = (Class1)ser.Deserialize(sr);

            Console.WriteLine(string.Format("Original == deserialized is {0}", class1 == deserCalss1));

            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }
    }
}


Class1.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;

namespace XmlSerialization
{
    public class Class1
    {
        public Class1()
        {
        }

        public Class1(string name1, string name2)
        {
            _name1 = name1;
            _name2 = name2;
        }

        private string _name1;
        private string _name2;

        [XmlAttribute]
        public string Name1
        {
            get { return _name1; }
            set { _name1 = value; }
        }

        [XmlElement]
        public string Name2
        {
            get { return _name2; }
            set { _name2 = value; }
        }

        public static bool operator ==(Class1 c1, Class1 c2)
        {
            return (c1._name1 == c2.Name1 && c1._name2 == c2.Name2);
        }

        public static bool operator !=(Class1 c1, Class1 c2)
        {
            return !(c1 == c2);
        }
    }
}


Смотри комментарии в коде.
How are YOU doin'?
Re: Баг в XmlSerializer.Deserialize...
От: MatFiz Россия  
Дата: 03.02.06 06:52
Оценка:
Здравствуйте, VVitaliy, Вы писали:

VV>Обаружил противный баг в методе XmlSerializer.Deserialize.

VV>Суть:
VV>Если сериализован класс со строковыми полями содержащими escapе characters like \r\n\t то сериализуются они нормально, при десериализации вычитываются в поток тоже нормально, но как только мы делаем Deserialize для объекта то в стоковые поля попают с строки с искаженными последовательностями таких символов. Наблюдаются разные искажения но чаще всего исчезает символ \r или он же заменяется на \t.

VV>Была мысль поотлаживать создаваемый слр код десериализатора, а смысл,

VV>потеряю времени день два, может даже найду баг, а чего дальше с этим делать, собственный десериализатор для нескольких десятков классов как-то не вписывается в проект по срокам...

VV>Это критичная часть проекта, и как обойти не представляю, вынимать строки через regexp... бред.


VV>Есть у кого какие мнения по данному поводу?


Кстати, это не баг
How are YOU doin'?
Re[2]: Баг в XmlSerializer.Deserialize...
От: VVitaliy Россия  
Дата: 03.02.06 07:48
Оценка:
Грейт сенк за наводку на XmlWriterSettings!
Новый объект для меня...
Щас проверим...
Re[2]: Баг в XmlSerializer.Deserialize...
От: VVitaliy Россия  
Дата: 03.02.06 07:56
Оценка:
MF>Кстати, это не баг

Другого объяснения мне в голову не пришло, когда в стриме видишь одни символы в десериализованом объекте немного другие...
Re[3]: Баг в XmlSerializer.Deserialize...
От: MatFiz Россия  
Дата: 03.02.06 08:06
Оценка: 2 (1)
Здравствуйте, VVitaliy, Вы писали:

VV>Грейт сенк за наводку на XmlWriterSettings!

VV>Новый объект для меня...
VV>Щас проверим...

Плюсик мне, плюсик!
Я, кстати, вспомнил, что у меня в одном проекте тоже есть такая проблема.
Но я почему-то на нее забил. Теперь можно исправить.

Это и недоработка в статье Конфигурирование .NET-приложений
Автор(ы): Андрей Корявченко
Дата: 12.05.2003
Не секрет, что практически каждое приложение требует каких-то настроек. Данная статья рассказывает об одном из возможных способов реализации механизма их хранения и редактирования. Исходные коды взяты из реального приложения, RSDN@Home, оффлайн-клиента для форумов www.rsdn.ru.
. Я пользуюсь кодом из нее и очень благодарен автору, но замечание, ИМХО, вполне оправданное.
How are YOU doin'?
Re[4]: Баг в XmlSerializer.Deserialize...
От: VVitaliy Россия  
Дата: 03.02.06 08:23
Оценка: +1
Ещё раз пасиб! Замечательно работает!
Аккуратно преобразовывает непечатные символы в коды через диез, красота!

А статью надо правда подправить, наверно, немало таких как я не подозревают здесь рояль в кустах.
Re[2]: Баг в XmlSerializer.Deserialize...
От: KirillSon  
Дата: 24.09.07 10:53
Оценка: 2 (1)
Здравствуйте, MatFiz, Вы писали:

MF>Вот код:



            XmlWriterSettings xws = new XmlWriterSettings();  // Смотри сюда
            xws.NewLineHandling = NewLineHandling.Entitize;   // Особенно сюда


Это только видимость — код строк все-равно портится (только по-другому). Правильно будет так десериализовать:


        /// <summary>    
        /// Restores object's copy from XML-representation.
        /// </summary>    
        /// <param name="xml">String with XML representation.</param>
        /// <typeparam name="T">Type of object for restoring.</typeparam>
        /// <returns>Object's instance.</returns>    
        public static T XmlStr2Obj<T>(string xml)
        {
            if (xml == null)
                return default(T);
            if (xml == string.Empty)
                return (T)Activator.CreateInstance(typeof(T));
            StringReader reader = new StringReader(xml);
            XmlTextReader xr = new XmlTextReader(reader);
            xr.Normalization = false; // Смотри сюда
            XmlSerializer sr = new XmlSerializer(typeof(T));
            
            return (T)sr.Deserialize(xr);
        }


Теперь строки возвращаются в исходном виде.

Удачи...
Re[3]: Баг в XmlSerializer.Deserialize...
От: MatFiz Россия  
Дата: 24.09.07 21:16
Оценка:
Здравствуйте, KirillSon, Вы писали:

KS>Это только видимость — код строк все-равно портится (только по-другому). Правильно будет так десериализовать:


Как конкретно?
How are YOU doin'?
Re[3]: Баг в XmlSerializer.Deserialize...
От: VVitaliy Россия  
Дата: 25.09.07 04:33
Оценка:
Здравствуйте, KirillSon, Вы писали:

KS>Здравствуйте, MatFiz, Вы писали:


MF>>Вот код:


KS>

KS>            XmlWriterSettings xws = new XmlWriterSettings();  // Смотри сюда
KS>            xws.NewLineHandling = NewLineHandling.Entitize;   // Особенно сюда

KS>


KS>Это только видимость — код строк все-равно портится (только по-другому). Правильно будет так десериализовать:



KS>
KS>        /// <summary>    
KS>        /// Restores object's copy from XML-representation.
KS>        /// </summary>    
KS>        /// <param name="xml">String with XML representation.</param>
KS>        /// <typeparam name="T">Type of object for restoring.</typeparam>
KS>        /// <returns>Object's instance.</returns>    
KS>        public static T XmlStr2Obj<T>(string xml)
KS>        {
KS>            if (xml == null)
KS>                return default(T);
KS>            if (xml == string.Empty)
KS>                return (T)Activator.CreateInstance(typeof(T));
KS>            StringReader reader = new StringReader(xml);
KS>            XmlTextReader xr = new XmlTextReader(reader);
KS>            xr.Normalization = false; // Смотри сюда
KS>            XmlSerializer sr = new XmlSerializer(typeof(T));
            
KS>            return (T)sr.Deserialize(xr);
KS>        }
KS>


KS>Теперь строки возвращаются в исходном виде.


Да, хотелось бы узнать при каких условиях он портится, в своём проекте с активным использованием XML сериализации ничего плохого при использовании xws.NewLineHandling = NewLineHandling.Entitize не обраруживается...
Re[4]: Баг в XmlSerializer.Deserialize...
От: KirillSon  
Дата: 25.09.07 07:05
Оценка:
Здравствуйте, MatFiz, Вы писали:

MF>Здравствуйте, KirillSon, Вы писали:


KS>>Это только видимость — код строк все-равно портится (только по-другому). Правильно будет так десериализовать:


MF>Как конкретно?


Сорри, посмотрел внимательнее — заменило \r\n на \n. По-быстрому не заметил, что \n тоже вставляет, поэтому из двух вариантов выбрал тот, который выключает нормализацию.

Так что можно использовать и

xws.NewLineHandling = NewLineHandling.Entitize;
при записи


и

xr.Normalization = false;
при чтении

И то и то работает. Только продуцируют немного отличающиеся представления XML-строк.

Снимаю своё замечание.

Удачи...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.