Szybki
Szybki

Reputation: 1111

Force order in NetDataContractSerializer without using DataContractAttribute

I want to force the NetDataContractSerializer to write property values in a specific order, because the serializer writes them in an alphabetic order.

I know I can achieve this by adding [DataMember(Order = X)] attributes to these properties but this works only when I add [DataContract] attribute to the class I am serializing.

Unfortunately, I can't add the [DataContract] attribute to this class since its base class doesn't have one.

Is there another way to force the order?

Upvotes: 0

Views: 100

Answers (1)

Szybki
Szybki

Reputation: 1111

I've came up with the idea of using own ISerializationSurrogate where I can handle getting the properties that are being serialized myself.

private class MySerializationSurrogate<T> : ISerializationSurrogate
{
    private IEnumerable<DataMemberAttribute> GetXmlAttribs(PropertyInfo p) => p.GetCustomAttributes(false).OfType<DataMemberAttribute>();

    public void GetObjectData(Object obj, SerializationInfo info, StreamingContext context)
    {
        var myobj = (T)obj;
        foreach (var property in myobj.GetType().GetProperties().Where(p => GetXmlAttribs(p).Any()).OrderBy(p => GetXmlAttribs(p).First().Order))
        {
            info.AddValue(property.Name, property.GetValue(myobj));
        }
    }

    public Object SetObjectData(Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    {
        var myobj = (T)obj;
        foreach (var property in myobj.GetType().GetProperties().Where(p => GetXmlAttribs(p).Any()).OrderBy(p => GetXmlAttribs(p).First().Order))
        {
            property.SetValue(myobj, info.GetValue(property.Name, property.PropertyType));
        }
        return null;
    }
}

Then I assign the serialization surrogate to the serializer.

var formatter = new NetDataContractSerializer();
var surrogateSelector = new SurrogateSelector();
surrogateSelector.AddSurrogate(typeof(T), new StreamingContext(StreamingContextStates.All), new MySerializationSurrogate<T>());
formatter.SurrogateSelector = surrogateSelector;

And everything works like hell.

NOTE that T is the type of the object being serialized/deserialized.

Upvotes: 2

Related Questions