Не пойму почему на получается обычную коллекцию сериализовать в XML (без SOAP)

vbnet2000
Дата: 29.04.2007 13:29:13
Ну допустим вот так все сериализуется на раз:
        Dim Buf(10000) As Byte
        Dim MS As New System.IO.MemoryStream(Buf)
        Dim CL As New System.Collections.Specialized.NameValueCollection
        CL.Add("Color", "Red")
        CL.Add("Font-Size", "XX-Small")
        CL.Add("Width", "100px")
        Dim X3 As New System.Runtime.Serialization.Formatters.Soap.SoapFormatter
        X3.Serialize(MS, CL)
        Dim Encoder As New System.Text.ASCIIEncoding
        Dim XML As String = Encoder.GetString(Buf)
Только все вот эти SOAP-приблуды меня в данном конкретном случае не радуют, типа
автор
<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:NameValueCollection id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/System.Collections.Specialized/System%2C%20Version%3D2.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Db77a5c561934e089">

...

<SOAP-ENC:Array id="ref-16" SOAP-ENC:arrayType="xsd:anyType[1]">
<item id="ref-19" xsi:type="SOAP-ENC:string">Red</item>
</SOAP-ENC:Array>
<SOAP-ENC:Array id="ref-17" SOAP-ENC:arrayType="xsd:anyType[1]">
<item id="ref-20" xsi:type="SOAP-ENC:string">XX-Small</item>
</SOAP-ENC:Array>
<SOAP-ENC:Array id="ref-18" SOAP-ENC:arrayType="xsd:anyType[1]">
<item id="ref-21" xsi:type="SOAP-ENC:string">100px</item>
</SOAP-ENC:Array>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Хотел сделать так - чтобы СОАП-конверт отрезать.
        Dim X1 As New System.Xml.Serialization.XmlSerializer(CL.GetType)
        X1.Serialize(MS, CL)
А неполучацца. Ругается -
автор
An exception of type 'System.InvalidOperationException' occurred in System.Xml.dll but was not handled in user code

Additional information: To be XML serializable, types which inherit from ICollection must have an implementation of Add(System.String) at all levels of their inheritance hierarchy. System.Collections.Specialized.NameValueCollection does not implement Add(System.String).

Не понимаю, это вообще невозможно без SOAP, или надо еще где-то чего-то подкрутить?
vbnet2000
Дата: 30.04.2007 10:35:48
UP
zoldat
Дата: 02.05.2007 05:30:11
Это может показаться странным, но XML-сериализация и Soap-сериализация юзают совершенно разные механизмы. Поэтому Soap-сериализация проходит на ура (она сериализует внутренности общим механизмом), а XML-сериализация нет (она сериализует только публичный интерфейс) (подробности см. в книге Дино Эспозито "Applied XML Programming for Microsoft .NET"). В данном случае XML-сериализация требует, чтобы у коллекции был метод Add с одним аргументом, а c NameValueCollection это не так.

Какие могут быть решения. Их целая куча. Я скажу только два. Ну первый сделать класс типа:
public class DataMustXmlSerialize
    {
        public string Color;
        [XmlElement("Font-Size")]
        public string FontSize;
        public string Width;
    }
И объект этого класса уже сериализовать.
Конечно по неизвестным мне причинам данный подход возможно не может быть использован (согласитесь мне же неизвестна Ваша задача).
Есть приятная новость, WCF наделил нас кучей всяких прибамбасов в плане XML, которые можно юзать и без всяких там SOA. Одной из таких фич является новый сериалайзер. Он сериализует тоже XML, но без написания SOAP-заголовков. Это класс DataContractSerializer. Правда c NameValueCollection у меня он не захотел работать, но с его аналогом Dictionary<string, string> работает на ура. Вот пример:

Dictionary<string, string> dictionary = new Dictionary<string, string>();
            dictionary.Add("Color", "Red");
            dictionary.Add("Font-Size", "XX-Small");
            dictionary.Add("Width", "100px");
            DataContractSerializer serializer = new DataContractSerializer(typeof(Dictionary<string, string>));
            StringBuilder builder = new StringBuilder();
            XmlWriter writer = XmlWriter.Create(builder);
            serializer.WriteObject(writer, dictionary);
            writer.Flush();
            string str = builder.ToString();

Конечно, может Вам и это не подойдет, но тогда расскажите свою задачу более подробнее. Подумаем.
vbnet2000
Дата: 02.05.2007 12:48:48
Большое спасибо за подробнейший ответ. В принципе у меня задача была такая. В моем SiteMap-провайдере есть куча атрибутов у каждого узла - ну например цвет фонта, размер и тд.

Все это лежит в SQL-базе. Я хотел бы дать возможность оператору сайта ЛЕГКО менять набор этих атрибутов вручную прямо по базе. Как вы понимаете, с SOAP - это совсем нелегко.

Сейчас я сделал все с SOAP, но недовольство по этому поводу уже выслушал. Поэтому это пока болтается так, но хорошо бы в перспективе переделать.

Есть приятная новость, WCF наделил нас кучей всяких прибамбасов в плане XML Вот этого я не знал вообще. Спасибо, буду разбираться.