开发者

XML Serialization using DataContractSerializer and XmlSerializer

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 attr开发者_如何学Pythonibute 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 {


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".
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜