XML Serialization using DataContractSerializer and XmlSerializer

杀马特。学长 韩版系。学妹 提交于 2019-12-30 11:12:12

问题


I have 2 service reference (WCF).

  • the first visual studio generate code using DataContractSerializer
  • the second one, visual studio generates code using XmlSerializer

I can't change anything on the web server side.

So I'm creating an object aggregating objects from both references.

How can I serialize this object so it respect the serialization specification for a DataContractSerializer and for a XmlSerializer. If I use a DataContractSerializer I'll have every field from my reference 2 serialized like that

<dataField>

instead of

<data>

because it serializes only the private fields by default (??)

and if I use a XmlSerializer every string array in my reference 2 will be serialized like that

<myArray>
<string>test</string>
<string>test</string>
</myArray>

instead of

<myArray>
<url>test</url>
<url>test</url>
</myArray>

because it ignores the attribute CollectionDataContractAttribute which specified how to serialize every item in the array.

So what would be your solution ?

My first solution would be to add all of them as good ol' web reference but maybe there is some nice solution.

EDIT :

here is the declaration of the type from the 1/ web service (datcontract,wcf style)

    [System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="productInformations", Namespace="http://abcedf.net/")]
[System.SerializableAttribute()]
public partial class productInformations : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {

回答1:


The first problem: since the types generated by "Add Web Reference" are decorated with [Serializable] by default, the serializable model used by the DataContractSerializer is that all fields (public or not) are serialized. If you decorate the type with [DataContract] and the members you want serialized (the properties) with [DataMember]. A type can have the attributes for both serializers without problems, as shown below.

public class StackOverflow_7348240
{
    [Serializable]
    [DataContract(Name = "myRoot", Namespace = "")]
    [XmlRoot(ElementName = "myRoot", Namespace = "")]
    public class MyType
    {
        private string dataField;

        [XmlElement(ElementName = "data")]
        [DataMember(Name = "data")]
        public string Data
        {
            get { return this.dataField; }
            set { this.dataField = value; }
        }
    }

    public static void Test()
    {
        MyType obj = new MyType { Data = "hello world" };

        MemoryStream ms = new MemoryStream();
        new DataContractSerializer(obj.GetType()).WriteObject(ms, obj);
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));

        ms.SetLength(0);
        new XmlSerializer(obj.GetType()).Serialize(ms, obj);
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
    }
}

For the second issue, if the collection type is a member of another object, you can also add the appropriate attributes (this time the ones for XML serialization), namely [XmlArray] (to specify the collection name) and [XmlArrayItem] (to specify the item name), and you can have the same type serialized the same way, like in the example below.

public class StackOverflow_7348240_b
{
    [DataContract(Name = "myRoot", Namespace = "")]
    [XmlRoot(ElementName = "myRoot", Namespace = "")]
    public class MyType
    {
        [DataMember(Name = "myArray")]
        [XmlArray(ElementName = "myArray")]
        [XmlArrayItem(ElementName = "url")]
        public MyArray myArray;
    }

    [CollectionDataContract(Name = "myArray", Namespace = "", ItemName = "url")]
    [XmlType(Namespace = "")]
    [XmlRoot(ElementName = "myArray", Namespace = "")]
    public class MyArray : List<string>
    {
    }

    public static void Test()
    {
        MyType obj = new MyType { myArray = new MyArray { "one", "two" } };

        MemoryStream ms = new MemoryStream();
        new DataContractSerializer(obj.GetType()).WriteObject(ms, obj);
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));

        ms.SetLength(0);
        new XmlSerializer(obj.GetType()).Serialize(ms, obj);
        Console.WriteLine(Encoding.UTF8.GetString(ms.ToArray()));
    }
}

Update

I understood that you wanted to merge the types "by hand", but based on the comment this is not the case. In this case, if you want to use both Add Web Reference (AWR) and Add Service Reference (ASR), then you'll need to fall back to the common serializer, which is the XmlSerializer. AWR always uses the XmlSerializer (XS), while ASR can use both that one and the DataContractSerializer (DCS). The DCS is the default one for ASR, but you can change it to use the other one. You have two options:

  • Use svcutil.exe (instead of ASR), and pass the /serializer:XmlSerializer command line
  • After adding the service reference, open the Reference.svcmap file (you may need to check the "Show All Files" option for the project), then change the option <Serializer> from Auto to XmlSerializer, then select "Update Service Reference".


来源:https://stackoverflow.com/questions/7348240/xml-serialization-using-datacontractserializer-and-xmlserializer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!