Overriding XML deserialization to use base deserialization and adding functionality Overriding XML deserialization to use base deserialization and adding functionality xml xml

Overriding XML deserialization to use base deserialization and adding functionality


using System.Xml.Serialization;namespace Custom.Xml.Serialization{    public interface IXmlDeserializationCallback    {        void OnXmlDeserialization(object sender);    }    public class CustomXmlSerializer : XmlSerializer    {        protected override object Deserialize(XmlSerializationReader reader)        {            var result = base.Deserialize(reader);            var deserializedCallback = result as IXmlDeserializationCallback;            if (deserializedCallback != null)            {                deserializedCallback.OnXmlDeserialization(this);            }            return result;        }    }}

inherit your class from IXmlDeserializationCallback and implement your synchronizing logic in OnXmlDeserialization method.

credits to How do you find out when you've been loaded via XML Serialization?

UPDATE:

well, as far as I understand the topicstarter, he does not want to "manually" call some logic after each XML deserialization. So instead of doing this:

public class MyEntity{     public string SomeData { get; set; }     public void FixReferences()     {          // call after deserialization          // ...     }}foreach (var xmlData in xmlArray){    var xmlSer = new XmlSerializer(typeof(MyEntity));    using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData)))    {       var entity = (MyEntity)xmlSer.Deserialize(memStream);       entity.FixReferences();       // do something else with the entity       // ...      }}

he wants to do just deserialization, without worrying about extra calls. In this case, proposed solution is the cleanest / simplest - you only need to inherit your entity class from IXmlDeserializationCallback interface, and replace XmlSerializer with CustomXmlSerializer:

 public class MyEntity: IXmlDeserializationCallback    {         public string SomeData { get; set; }         private void FixReferences()         {              // call after deserialization              // ...         }         public void OnXmlDeserialization(object sender)         {             FixReferences();         }     }    foreach (var xmlData in xmlArray)    {        var xmlSer = new CustomXmlSerializer(typeof(MyEntity));        using (var memStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlData)))        {           var entity = (MyEntity)xmlSer.Deserialize(memStream);           // entity.FixReferences(); - will be called automatically           // do something else with the entity           // ...          }    }


Your options using XmlSerializer are limited.

  • Deserialize your entire object graph and then apply whatever fix-ups you require.
  • Do some processing in the property setters of your object.
  • Implement IXmlSerializable on your types so that you have explicit control of serialization/deserialization. Not an easy option.

If you can change to using the DataContractSerializer, which has its advantanges (and disadvantages) then you can use the OnDeserializedAttribute. For example

[DataContract]public class MyClass{    [DataMember]    public string AMember{get;set;}    [OnDeserialized]    public void OnDeserialized(StreamingContext context)    {        // called after deserializing instance of MyClass    }}


i have a nice solution 4 u

write this static class

public delegate void OnDeserializedEventArgs(object itemDeserialized, string xmlSource);public delegate void OnDeserializedFailedEventArgs(string xmlSource);public static class SerializationServices{    public static event OnDeserializedEventArgs OnDeserializedEvent;    public static event OnDeserializedFailedEventArgs OnDeserializedFailedEvent;    public static T Deserialize<T>(this string item) where T : class    {        XmlSerializer ser = new XmlSerializer(item.GetType());        StringReader sr = new StringReader(item);        var obj = ser.Deserialize(sr);        if (obj is T)        {            if (OnDeserializedEvent != null)                OnDeserializedEvent(obj, item);            return obj as T;        }        if (OnDeserializedFailedEvent != null)            OnDeserializedFailedEvent(item);        //callback - invalid event        return null;    }}

and then use it with this code

public class MyDesrializedClass{    //put some properties here...}class Program{    static void Main(string[] args)    {        SerializationServices.OnDeserializedEvent += SerializationServices_OnDeserializedEvent;        SerializationServices.OnDeserializedFailedEvent += SerializationServices_OnDeserializedFailedEvent;        string someXml = string.Empty; //replace this with something...        MyDesrializedClass deserializedClass = someXml.Deserialize<MyDesrializedClass>();    }    private static void SerializationServices_OnDeserializedFailedEvent(string xmlSource)    {        //will get here before 'deserializedClass' will get it's results    }    private static void SerializationServices_OnDeserializedEvent(object itemDeserialized, string xmlSource)    {        //will get here before 'deserializedClass' will get it's results    }}

if u paste these code into diferent namespaces don't forget to add the 'using ...' otherwize u wont see the method deserialize in the program context

Tzahi