Reputation: 93
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.
Upvotes: 9
Views: 6646
Reputation: 1081
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>
Upvotes: 0
Reputation: 62970
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.
Upvotes: 5
Reputation: 107367
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;
}
}
Upvotes: 1