xml serializing a list of base class - c#

Consider the below class structure
[XmlInclude(typeof(DerivedClass))]
public class BaseClass
{
public string mem1;
public string mem2;
}
public class DerivedClass : List<BaseClass>
{
public string mem3;
public string mem4;
}
class Program
{
static void Main(string[] args)
{
DerivedClass obj = new DerivedClass();
obj.mem3 = "test3";
obj.mem4 = "test4";
BaseClass base11 = new BaseClass();
base11.mem1 = "test1";
base11.mem2 = "test2";
obj.Add(base11);
XElement
.Parse(XMLSerializerUtil.GetXMLFromObject(obj))
.Save(#"C:\new_settings1.xml");
}
}
The code for GetXMLFromObject given is below
public static string GetXMLFromObject(object instance)
{
string retVal = string.Empty;
if (instance != null)
{
XmlSerializer xmlSerializer = new XmlSerializer(instance.GetType());
using (MemoryStream memoryStream = new MemoryStream())
{
xmlSerializer.Serialize(memoryStream, instance);
memoryStream.Position = 0;
retVal = new StreamReader(memoryStream).ReadToEnd();
}
}
return retVal;
}
Even after adding the XmlInclude attribute, in the generated XML file, the derived class members are not present.
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfBaseClass xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<BaseClass>
<mem1>test1</mem1>
<mem2>test2</mem2>
</BaseClass>
</ArrayOfBaseClass>
Please let me know, what is missing to include the derived class members in the generated XML file.

Here's the problem:
DerivedClass : List<BaseClass>
For XmlSerializer, an item is either a list exclusive-or an entity. If it looks like a list, then only the list-items are serialized; members of the "list" itself are not serialized. Basically, don't do that. Instead of deriving from a list, encapsulate a list:
Also, note that [XmlInclude(...)] would expect DerivedClass : BaseClass. So, something like:
public class SomeType // note DOES NOT INHERIT
{
private readonly List<SomeOtherType> items = new List<SomeOtherType>();
public List<SomeOtherType> Items { get { return items; } }
[XmlElement("mem3")] public string Mem3 {get;set;}
[XmlElement("mem4")] public string Mem4 {get;set;}
}
public class SomeOtherType
{
[XmlElement("mem1")] public string Mem1 {get;set;}
[XmlElement("mem2")] public string Mem2 {get;set;}
}

Related

How to apply generic constraint to accept multi level of inheritance C#

I am looking for a way to support multi level of inheritance for generic type constraint.
Common generic interface
public interface ICommon<T>
{
T OrignalData {get;set;}
string ChangeJson {get;set;}
T Merged {get;set;}
void Inject();
}
Common base class implements ICommon
public class Base <T>: ICommon<T>
{
public T OrignalData {get;private set;}
public string ChangeJson {get;set;}
public T Merged {get;private set;}
public void Inject(T orignal)
{
if (orignal == null)
return;
var settings = new JsonSerializerSettings
{
ObjectCreationHandling = ObjectCreationHandling.Auto
};
dynamic merged = orignal.Clone();
JsonConvert.PopulateObject(this.ChangeJson, merged, settings);
this.Merged = merged;
this.Orignal = orignal;
}
}
Department class inherits Base class
public class Deparment : Base<Deparment>
{
}
OrgnizationDepartment class inherits Deparment
public class OrgnizationDepartment : Deparment
{
}
class View expect ICommon must implement on passed calls
public class View<T> where T : ICommon<T>
{
//This class is totally dynamic to visualize any json data along with old and new value of requested json for any class like department or org..
}
Test
public class Test
{
public void TestConstraint()
{
//No error
var deptView = new View<Deparment>();
//Error as Base not directly implemented on OrgnizationDepartment
var orgView = new View<OrgnizationDepartment>();
}
}
how do I define my constraint that should support for multi level as well.
One way out of this would be "composition over inheritance".
Here is a naive example, that is still relatively close to your code:
using System;
using Newtonsoft.Json;
public class Program
{
public static void Main()
{
//No error
var deptView = new View<Deparment>();
//Formerly Error
var orgView = new View<OrgnizationDepartment>();
}
}
public interface ICommon<T> where T : ICloneable
{
// returns a tuple
(T,T,string) Inject(T original, string change);
}
public class Base <T>: ICommon<T> where T : ICloneable
{
// we can reuse this...
private readonly JsonSerializerSettings settings = new JsonSerializerSettings
{
ObjectCreationHandling = ObjectCreationHandling.Auto
};
public (T,T,string) Inject(T original, string change)
{
if (original is null)
return default;
// this forces T to implement ICloneable ... just saying...
dynamic merged = original.Clone();
JsonConvert.PopulateObject(change, merged, settings);
return (original, merged, change);
}
}
public class Deparment : ICloneable, ICommon<Deparment>
{
// could also be created in ctor. Maybe use Ctor injection.
private readonly Base<Deparment> common = new Base<Deparment>();
public object Clone(){return this;} // this is of course nonsense. Clone properly! I did this to avoid dotnetfiddle screaming at me.
public (Deparment, Deparment, string) Inject(Deparment original, string change){
return common.Inject(original, change);
}
}
public class OrgnizationDepartment : ICloneable, ICommon<OrgnizationDepartment>
{
private readonly Base<OrgnizationDepartment> common = new Base<OrgnizationDepartment>();
public object Clone() {return this;}
public (OrgnizationDepartment, OrgnizationDepartment, string) Inject(OrgnizationDepartment original, string change){
return common.Inject(original, change);
}
}

How to add an optional memeber in a regular C # modal class to avoid duplicate entity class

Could you please look into a C# design problem (see below) and suggest the right approach? I am not sure how to handle this situation.
I have a class called ClassA like this:
public class ClassA
{
public string Name;
public string Address;
public string Details;
}
for which I am creating an object like this:
ClassA call = new ClassA ();
and then setting values on run time like this:
call .Name= "Praveen";
and sending it over to some client using a service call.
My requirement is that I have to send another call which has the same data member and an additional one only and I want to utilize the existing ClassA so that my code is not duplicated everywhere.
By using an if/else, I should be able to do this.
So ClassA would become something like:
public class ClassA
{
public string Name;
public string Address;
public string Details;
//Optional
Public String Phone
}
so that If I set the value of phone then it is sent in my xml call, otherwise it should not appear in the xml.
<?xml version="1.0"?>
<CallA xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Name>Prav </Name>
<Address>Zurich </Address>
<Details>KEMP Tower</Details>
</CallA>
You need to add ShouldSerializeXXX() method to your class to handle this. I did a quick test and it worked. Here is the code snippet. Test with or without ShouldSerializePhoneNumbers() method to notice difference.
class Program
{
static void Main(string[] args)
{
SerializationHelper.SerializeTest();
Console.Read();
}
}
public static class SerializationHelper
{
[Serializable]
public class ClassA
{
public string Name;
public string Address;
public string Details;
public List<string> PhoneNumbers = new List<string>();
public bool ShouldSerializePhoneNumbers()
{
if (PhoneNumbers == null || PhoneNumbers.Count <= 0)
return false;
else
return true;
}
}
public static void SerializeTest()
{
ClassA call = new ClassA();
call.Name = "Praveen";
XmlSerializer ser = new XmlSerializer(typeof(ClassA));
TextWriter writer = new StringWriter();
ser.Serialize(writer, call);
string xml = writer.ToString();
}
}

Cascading the effect of an attribute to overridden properties in child classes

Is it possible to mark a property in base class with some attribute that remains effective in child classes too?
Question might be very specific to Serialization, but I definitely think there can be other uses as well.
Consider the following code:
using System;
using System.IO;
using System.Xml.Serialization;
namespace Code.Without.IDE
{
[Serializable]
public abstract class C1
{
[XmlIgnore]
public abstract bool IsValid_C1 { get; set;}
}
[Serializable]
public class C2 : C1
{
public bool IsValid_C2 { get; set; }
public override bool IsValid_C1 { get; set;}
public C2()
{
IsValid_C1 = true;
IsValid_C2 = false;
}
}
public static class AbstractPropertiesAttributeTest
{
public static void Main(string[] args)
{
C2 c2 = new C2();
using(MemoryStream ms = new MemoryStream())
{
XmlSerializer ser = new XmlSerializer(typeof(C2));
ser.Serialize(ms, c2);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(result);
}
}
}
}
Above code returns:
------ C:\abhi\Code\CSharp\without IDE\AbstractPropertiesAttributeTest.exe
<?xml version="1.0"?>
<C2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<IsValid_C2>false</IsValid_C2>
<IsValid_C1>true</IsValid_C1>
</C2>
------ Process returned 0
I thought IsValid_C1 will be ignored, though it is not so. Is there any way of achieving this other than marking the property as protected?
Edit: A quick code to show that XmlIgnore attibute is being inherited.
http://ideone.com/HH41TE
I don't believe there is a way to inherit the attribute since you override the base class property. You would need to decorate the IsValid_C1 of C2 with XmlIgnore:
[Serializable]
public class C2 : C1
{
public bool IsValid_C2 { get; set; }
[XmlIgnore]
public override bool IsValid_C1 { get; set; }
public C2()
{
IsValid_C1 = true;
IsValid_C2 = false;
}
}
I will offer a different view of this question. Maybe you just used those properties as an example and want to have severall properties to be cascaded. But i think that this may be a good time to think about the inheritance model proposed.
Basicly you can use regular inheritance or think about some Design Pattern, that can not just solve you issue related to the serialization, but may offer you some more "loose coupling" in you application, making it in a more component model and allowwing each class to deal only with what is concern, this way you can re-use lots of stuff and make your life easier.
Based on that thinking im providing you a sample of the Decorator Design Pattern mixed with the Strategy Design Pattern. If i were developing classes like the ones on your sample, this is how i would do it:
/// <summary>
/// The interface for validation strategy (since we are using interface, there is no need for another abstract class)
/// </summary>
public interface IValidation
{
bool IsValid { get; set; }
}
/// <summary>
/// The decorator (it dont need to be abstract) that has the serializable properties
/// </summary>
[Serializable]
public class ValidatableDecorator : IValidation
{
protected IValidation instance;
public ValidatableDecorator()
{
Init();
}
public ValidatableDecorator(IValidation instance)
{
Init();
}
protected virtual void Init() { }
public void Set(IValidation instance)
{
this.instance = instance;
}
[XmlIgnore]
public bool IsValid
{
get
{
return instance.IsValid;
}
set
{
instance.IsValid = value;
}
}
}
Then you need to implement some classes that have the logic of the strategy Pattern, like this:
public class BossValidatorImplementation : IValidation
{
public bool IsValid
{
get
{
return false; ;
}
set
{
throw new InvalidOperationException("I dont allow you to tell me this!");
}
}
}
public class EasyGoingValidator : IValidation
{
public bool IsValid { get; set; }
}
Now that we have the logic separated from the class, we can inherit from the decorators, choosing wich strategy they use to the IsValid field, like this:
public class ChildWithBossValidation : ValidatableDecorator
{
protected ChildWithBossValidation(IValidation instance)
: this()
{
Init();
}
public ChildWithBossValidation()
: base(new BossValidatorImplementation())
{
Init();
}
protected override void Init()
{
Name = "I'm the boss!";
Sallary = 10000d;
}
public string Name { get; set; }
public double Sallary { get; set; }
}
public class ChildWithEasyGoingValidation : ValidatableDecorator
{
public ChildWithEasyGoingValidation()
: base(new EasyGoingValidator())
{
}
protected ChildWithEasyGoingValidation(IValidation instance)
: this()
{
}
protected override void Init()
{
Name = "Do as you please... :) ";
}
public string Name { get; set; }
}
This is the code to show that the solution works:
public static void Main(string[] args)
{
var boos = new ChildWithBossValidation();
var coolGuy = new ChildWithEasyGoingValidation();
using (var ms = new MemoryStream())
{
var ser = new XmlSerializer(boos.GetType());
ser.Serialize(ms, boos);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine("With override");
Console.WriteLine(result);
}
Console.WriteLine("-------------");
using (var ms = new MemoryStream())
{
var ser = new XmlSerializer(coolGuy.GetType());
ser.Serialize(ms, coolGuy);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine("With override");
Console.WriteLine(result);
}
Console.ReadKey();
}
The result is:
{<?xml version="1.0"?>
<ChildWithBossValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>I'm the boss!</Name>
<Sallary>10000</Sallary>
</ChildWithBossValidation>-------------------<?xml version="1.0"?>
<ChildWithEasyGoingValidation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Do as you please... :) </Name>
</ChildWithEasyGoingValidation>}
So, maybe this does not answer how to cascade the Attribute in this case (because you can easily do it by creating your own attribute(marking to allow inheritance) and then implementing some code to SerializeXML). This is just another option that can improve overall architecture of solutions using Design Pattern. But this solve this particular issue also :)
A needed behaviour can be achieved using classes XmlAttributeOverrides and XmlAttributes. I've written helper method for XmlSerializer creation:
public static XmlSerializer GetXmlSerializerWithXmlIgnoreFields(Type t)
{
XmlAttributeOverrides xmlOverrides = new XmlAttributeOverrides();
foreach (var prop in t.GetProperties(BindingFlags.Public|BindingFlags.Instance))
{
Attribute xmlIgnoreAttribute = Attribute.GetCustomAttribute(prop, typeof(XmlIgnoreAttribute));
if (xmlIgnoreAttribute == null)
continue;
XmlAttributes xmlAttributes = new XmlAttributes();
xmlAttributes.XmlIgnore = true;
xmlOverrides.Add(t, prop.Name, xmlAttributes);
}
return new XmlSerializer(t, xmlOverrides);
}
The Main method became:
public static void Main(string[] args)
{
C2 c2 = new C2();
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer ser = GetXmlSerializerWithXmlIgnoreFields(typeof(C2));
ser.Serialize(ms, c2);
string result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(result);
}
}
It appears this feature is broken in C#.
You could write an attribute which through reflection will bring down the attributes for you. Pretty straight forward if you understand reflection.

Serializing IEnumerable Containing Derived classes: Circular Reference Issue

I am trying to serialize IEnumerable using the following code. I am getting the following exception.
There was an error generating the XML document. "A circular reference was detected while serializing an object of type DBML_Project.FixedBankAccount."}.
Why does this error come? How to correct it?
Note: I am already using InheritanceMapping attribute.
public class BankAccountAppService
{
public RepositoryLayer.ILijosBankRepository AccountRepository { get; set; }
public void FreezeAllAccountsForUser(int userId)
{
IEnumerable<DBML_Project.BankAccount> accounts = AccountRepository.GetAllAccountsForUser(userId);
foreach (DBML_Project.BankAccount acc in accounts)
{
acc.Freeze();
}
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
System.Xml.XPath.XPathNavigator nav = xmlDoc.CreateNavigator();
using (System.Xml.XmlWriter writer = nav.AppendChild())
{
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(typeof(List<DBML_Project.BankAccount>));
ser.Serialize(writer, accounts);
}
}
}
namespace DBML_Project
{
[System.Xml.Serialization.XmlInclude(typeof(FixedBankAccount))]
[System.Xml.Serialization.XmlInclude(typeof(SavingsBankAccount))]
public partial class BankAccount
{
//Define the domain behaviors
public virtual void Freeze()
{
//Do nothing
}
}
public class FixedBankAccount : BankAccount
{
public override void Freeze()
{
this.Status = "FrozenFA";
}
}
public class SavingsBankAccount : BankAccount
{
public override void Freeze()
{
this.Status = "FrozenSB";
}
}
}
Autogenerated Class using LINQ to SQL
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.BankAccount")]
[InheritanceMapping(Code = "Fixed", Type = typeof(FixedBankAccount), IsDefault = true)]
[InheritanceMapping(Code = "Savings", Type = typeof(SavingsBankAccount))]
public partial class BankAccount : INotifyPropertyChanging, INotifyPropertyChanged
Use the data contract serializer instead of the xmlserializer:
http://jameskovacs.com/2006/11/18/going-around-in-circles-with-wcf/

.NET Serializable entity

I need to make all my entities serializable. So I was thinking in a BaseEntity with a Backup and a Restore method. But in the restore I can't override the object with the saved one because this is read-only.
Any solution or some other way to get the serializable entities?
My code:
internal class BaseEntity
{
private MemoryStream ms = new MemoryStream();
private BinaryFormatter bf = new BinaryFormatter();
public void Backup()
{
bf.Serialize(ms, this);
}
public void Restore()
{
this = (BaseEntity)bf.Deserialize(ms);
}
}
The more common pattern is to not make it the responsibility of your objects to serialize/deserialize themselves; rather, use an external serializer:
var serializer = new DataContractJsonSerializer(typeof(YourClass));
var stream = ...;
YourClass yourObj = ...;
serializer.WriteObject(stream, yourObj);
var restoredObj = serializer.ReadObject(stream);
Edit: One way serialization can work is to use the System.Runtime.Serialization.Formatters.Binary.BinaryFormatter (or other implementation of IFormatter). To serialize an object you pass the object and a stream. To Deserialize the object, you pass a stream (positioned at the begining of your serialized data), and it returns the serialized object and all its depenedencies.
public static class EntityBackupServices
{
public static MemoryStream Backup (BaseEntity entity)
{
var ms = new MemoryStream();
Serialize (ms, entity);
ms.Position = 0;
return ms;
}
public static void Serialize (Stream stream, BaseEntity entity)
{
var binaryFormatter = new BinaryFormatter();
binaryFormatter.Serialize (stream, entity);
}
public static BaseEntity Restore (Stream stream)
{
var binaryFormatter = new BinaryFormatter();
var entity = (BaseEntity) binaryFormatter.Deserialize (stream);
return entity;
}
}
One thing a formatter don't do (though the FormatterServices class makes it possible) is modify existing objects. So you probably don't want to have an instance method called Deserialize. You can't really do this: new LionEntity().Deserialize () where it replaces the fields of an existing instance.
Note: You'll need to put Serializable over all your types. Any fields that can't be serialized (because it's either not a struct, or it's not marked as [Serializable] will need to be marked with NonSerialized.
// A test object that needs to be serialized.
[Serializable()]
public class BaseEntity
{
public int member1;
public string member2;
public string member3;
public double member4;
// A field that is not serialized.
[NonSerialized()] public MyRuntimeType memberThatIsNotSerializable;
public TestSimpleObject()
{
member1 = 11;
member2 = "hello";
member3 = "hello";
member4 = 3.14159265;
memberThatIsNotSerializable = new Form ();
}
public MemoryStream Backup ()
{
return EntityBackupServices.Backup (this);
}
}
Edit:
The way I've mentioned is a rather standard and accepted way. If you want to venture into hackdom, you can deserialize the object the way I've mentioned, then use reflection to set each field on your existing object to the value of the deserialized object.
public class BaseEntity
{
void Restore(Stream stream)
{
object deserialized = EntityBackupServices.RestoreDeserialize(stream);//As listed above
if (deserialized.GetType () != this.GetType ())
throw new Exception();
foreach (FieldInfo fi in GetType().GetFields())
{
fi.SetValue(this, fi.GetValue (deserialized));
}
}
}
public IEntidadBase Restore()
{
return (IEntidadBase)bf.Deserialize(ms);
}
#jacklondon how would you do EntitySerializer methods?
You can do serialization process with http://www.servicestack.net/ StackService.Text module for clean entities. You don't need any attribute (serializable/datacontract) in ms way.
public class EntityFoo
{
public string Bar { get; set; }
public EntityFoo (string bar)
{
Bar = bar;
}
}
public class EntityDumper //and the EntitySerializer
{
public static string Dump<T> (T entity)
{
return new TypeSerializer<T> ().SerializeToString (entity);
}
public static T LoadBack<T> (string dump)
{
return new TypeSerializer<T> ().DeserializeFromString (dump);
}
}
public class dump_usage
{
public void start ()
{
string dump = EntityDumper.Dump (new EntityFoo ("Space"));
EntityFoo loaded = EntityDumper.LoadBack<EntityFoo> (dump);
Debug.Assert (loaded.Bar == "Space");
}
}
I don't necessarily recommend this, but here is one pattern for an object that can persist and restore its own state using serialization that creates new instances:
public sealed class MyClass
{
private Data _data = new Data();
//Properties go here (access the public fields on _data)
public void Backup()
{
//Serialize Data
}
public void Restore()
{
//Deserialize Data and set new instance
}
private sealed class Data
{
//Public fields go here (they're private externally [because Data is private], but public to MyClass.)
}
}
Note that this only works if your serializer supports non-public classes. Worst-case, you have to make the nested class public, which is ugly, but doesn't hurt encapsulation (since the instance is private).

Categories

Resources