简体   繁体   中英

XML Serialize dynamic object

I need to construct a set of dynamically created XML nodes from objects on the following format:

<Root>
    <Name>My Name</Name>
    <DynamicValues>
        <DynamicValue1>Value 1</DynamicValue1>
        <DynamicValue2>Value 2</DynamicValue2>
    </DynamicValues>
</Root>

The name of the nodes within the DynamicValues -tag are not known in advance. My initial thought was that this should be possible using an Expando Object , eg:

[DataContract]
public class Root
{
    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public dynamic DynamicValues { get; set; }
}

by initializing it with the values:

var root = new Root
                    {
                        Name = "My Name",
                        DynamicValues = new ExpandoObject()
                    };

root.DynamicValues.DynamicValue1 = "Value 1";
root.DynamicValues.DynamicValue2 = "Value 2";

and then Xml-serialize it:

string xmlString;

var serializer = new DataContractSerializer(root.GetType());
using (var backing = new StringWriter())
using (var writer = new XmlTextWriter(backing))
{
    serializer.WriteObject(writer, root);
    xmlString = backing.ToString();
}

However, when I run this, I get an SerializationException saying:

"Type 'System.Dynamic.ExpandoObject' with data contract name 'ArrayOfKeyValueOfstringanyType: http://schemas.microsoft.com/2003/10/Serialization/Arrays ' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer."

Any ideas how I can achieve this?

[Serializable]
public class DynamicSerializable : DynamicObject, ISerializable
{
    private readonly Dictionary<string, object> dictionary = new Dictionary<string, object>();

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;

        return true;
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        foreach (var kvp in dictionary)
        {
            info.AddValue(kvp.Key, kvp.Value);
        }
    }
}

[KnownType(typeof(DynamicSerializable))]
[DataContract]
public class Root
{
    [DataMember]
    public string Name { get; set; }

    [DataMember]
    public dynamic DynamicValues { get; set; }
}

Output:

<Program.Root xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://
schemas.datacontract.org/2004/07/">
  <DynamicValues i:type="Program.DynamicSerializable">
    <DynamicValue1 xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:st
ring" xmlns="">Value 1</DynamicValue1>
    <DynamicValue2 xmlns:d3p1="http://www.w3.org/2001/XMLSchema" i:type="d3p1:st
ring" xmlns="">Value 2</DynamicValue2>
  </DynamicValues>
  <Name>My Name</Name>
</Program.Root>

Tried this in vb.netbut didn't got the required output. Need help.

_ Public Class DynamicSerializable Inherits System.Dynamic.DynamicObject Implements ISerializable

Private ReadOnly dict As New Dictionary(Of String, Object)

Public Overrides Function TrySetMember(binder As SetMemberBinder, value As Object) As Boolean
    If Not dict.ContainsKey(binder.Name) Then
        dict.Add(binder.Name, value)
    Else
        dict(binder.Name) = value
    End If
    Return True
End Function

Public Overrides Function TryGetMember(binder As GetMemberBinder, ByRef result As Object) As Boolean
    Return dict.TryGetValue(binder.Name, result)
End Function

Public Sub GetObjectData(info As SerializationInfo, context As StreamingContext) Implements ISerializable.GetObjectData
    For Each keyValPair In dict
        info.AddValue(keyValPair.Key, keyValPair.Value)
    Next
End Sub

End Class

Code used :

Dim root As New Root root.name = "1" root.DynamicValues = New DynamicSerializable

    root.DynamicValues.DynamicValue1 = "Value1"
    root.DynamicValues.DynamicValue2 = "Value1"

    Dim serializer = New DataContractSerializer(Root.GetType)
    Dim backing As New StringWriter
    Dim writer As New XmlTextWriter(backing)
    serializer.WriteObject(writer, Root)

Output :

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM