How do I serialize a list without the outer element using the Data Contract Serializer? I am using .Net 3.5. I have a class that contains a list, amongst other things, that I wish to serialize without the outer element to be compliant with the pertinent XSD:
[DataContract(Name="MyClass")]
public class MyClass
{
...
[DataMember(Name="Parameters")]
public List<Parameter> Parameters;
...
}
[DataContract(Name="Parameter")]
public struct Parameter
{
[DataMember(Name="ValueName")]string ValueName;
[DataMember(Name="Value")]int Value;
public Parameter(string ValueName, int Value)
{
this.ValueName = ValueName;
this.Value = Value;
}
}
The above serializes as (assuming only one Parameter in the list):
<MyClass>
<Parameters>
<Parameter>
<ValueName></ValueName>
<Value></Value>
</Parameter>
</Parameters>
</MyClass>
I would like to serialize it as follows:
<MyClass>
<Parameter>
<ValueName></ValueName>
<Value></Value>
</Parameter>
</MyClass>
Using the XmlSerializer I can do this by applying the [XmlElement] to the list:
[XmlElement ("Parameter")]
public List<Parameter> Parameters;
However I do not want to use the XmlSerializer
because my class has a few properties that are not serialization friendly and I was hoping to deal with those using the [OnSerializing] family of attributes.
Thanks.
The DataContract
serializer does not allow this degree of control over the resulted XML, you will have to use instead the XmlSerializer
in order to achieve this.
Use a collection data contract:
[CollectionDataContract(Name = "MyClass", ItemName = "Parameter")]
public class ParameterList : List<Parameter>
{
}
Here is the actual code:
public class TestSerialize
{
[DataContract(Name = "Parameter")]
public struct Parameter
{
[DataMember(Name = "ValueName")] string ValueName;
[DataMember(Name = "Value")] int Value;
public Parameter(string ValueName, int Value)
{
this.ValueName = ValueName;
this.Value = Value;
}
}
[CollectionDataContract(Name = "MyClass", ItemName = "Parameter")]
public class ParameterList : List<Parameter>
{
}
public string Serialize(ParameterList plist)
{
var serializer = new DataContractSerializer(plist.GetType());
var output = new StringBuilder();
var xmlWriter = XmlWriter.Create(output);
serializer.WriteObject(xmlWriter, plist);
xmlWriter.Close();
return output.ToString();
}
public void Serialize_produces_2Levels_of_xml()
{
ParameterList p = new ParameterList
{
new Parameter("First", 1),
new Parameter("Second", 2),
};
var xml = Serialize(p);
}
}
if you run this you will get the following XML:
<?xml version="1.0" encoding="utf-16"?>
<MyClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/Serialize.Test">
<Parameter>
<Value>1</Value>
<ValueName>First</ValueName>
</Parameter>
<Parameter>
<Value>2</Value>
<ValueName>Second</ValueName>
</Parameter>
</MyClass>
The below works using MessageContracts although is a 'hack' - it attributes the "MyClass" element to the List member and excludes the wrapper namespace for "MyClass".
[ServiceContract(Namespace="")]
public interface IService1
{
[OperationContract]
MyClass GetParameters();
// TODO: Add your service operations here
}
[DataContract(Namespace="")]
public class Parameter
{
[DataMember]
public string ValueName
{
get;
set;
}
[DataMember]
public int Value
{
get;
set;
}
public Parameter(string ValueName, int Value)
{
this.ValueName = ValueName;
this.Value = Value;
}
}
[MessageContract(IsWrapped = false, WrapperNamespace="")]
public class MyClass
{
[MessageBodyMember(Name = "MyClass", Namespace = "")]
public List<Parameter> Parameters
{
get;
set;
}
}
来源:https://stackoverflow.com/questions/8591045/data-contract-serializer-how-to-omit-the-outer-element-of-a-collection