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