I am receiving the following exception when trying to serialize an object using XMLSerialization.
A circular reference was detected while serializing an object of type MyObject}
I know the circular reference is because ObjectA can have a childObject of ObjectB and ObjectB's parentObject is ObjectA, however I would like to keep that reference if possible . Is there a way to get this object to serialize with XML Serialization without losing any data during the serialization process? I'm not very familar with serialization so I'm hoping theres some kind of Attribute I could set.
There are several options depending on serializer type.
If you could use DataContractSerializer or BinaryFormatter then you may use OnSerializedAttribute and set Parent property for your child object to this:
[Serializable]
public class Child
{
public string Foo { get; set; }
public Parent Parent { get { return parent; } set { parent = value; } }
// We don't want to serialize this property explicitly.
// But we could set it during parent deserialization
[NonSerialized]
private Parent parent;
}
[Serializable]
public class Parent
{
// BinaryFormatter or DataContractSerializer whould call this method
// during deserialization
[OnDeserialized()]
internal void OnSerializedMethod(StreamingContext context)
{
// Setting this as parent property for Child object
Child.Parent = this;
}
public string Boo { get; set; }
public Child Child { get; set; }
}
class Program
{
static void Main(string[] args)
{
Child c = new Child { Foo = "Foo" };
Parent p = new Parent { Boo = "Boo", Child = c };
using (var stream1 = new MemoryStream())
{
DataContractSerializer serializer = new DataContractSerializer(typeof (Parent));
serializer.WriteObject(stream1, p);
stream1.Position = 0;
var p2 = (Parent)serializer.ReadObject(stream1);
Console.WriteLine(object.ReferenceEquals(p, p2)); //return false
Console.WriteLine(p2.Boo); //Prints "Boo"
//Prints: Is Parent not null: True
Console.WriteLine("Is Parent not null: {0}", p2.Child.Parent != null);
}
}
}
If you want to use XmlSerializer you should implement IXmlSerializable, use XmlIgnoreAttribute and implemented more or less the same logic in ReadXml method. But in this case you should also implement all Xml serialization logic manually:
[Serializable]
public class Child
{
public Child()
{
}
public string Foo { get; set; }
[XmlIgnore]
public Parent Parent { get; set; }
}
[Serializable]
public class Parent
{
public Parent()
{
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
throw new NotImplementedException();
}
public void ReadXml(System.Xml.XmlReader reader)
{
//Reading Parent content
//Reading Child
Child.Parent = this;
}
public void WriteXml(System.Xml.XmlWriter writer)
{
//Writing Parent and Child content
}
#endregion
public string Boo { get; set; }
public Child Child { get; set; }
}
If you can use the DataContractSerializer instead of the XMLSerializer then you can use the IsReference property on the DataContract attribute. Enabling this will keep the references, so that they will be recreated upon deserialization.
The DataContractSerializer also serializes to XML, but you have somewhat less control over what the output looks like, that you do with the older XMLSerializer. You can read more about the serializers here: http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/
Mark the parentObject property as [NonSerialized].
https://blog.kowalczyk.info/article/8n/serialization-in-c.html
Related
Is it possible to specify that I always want type-information in the json object when serializing a property in an class?
(Ideally with Newtonsoft).
I'm thinking something like this:
public abstract class Value {...}
public class BigValue : Value {...}
public class SmallValue : Value {...}
public class ValueContainer
{
[JsonSetting(TypenameHandling = TypenameHandling.All)] // <--- Something like this?
public Value TheValue { get; set; }
}
I am aware that I could specify this behavior when doing the parsing with a custom converter.
But I want to include the typeinformation every time objects of this type is serialized, without manually having to specify which serialization options to use.
Newtonsoft.Json's JsonPropertyAttribute has TypeNameHandling property which you can set:
public class Root
{
[JsonProperty(TypeNameHandling = TypeNameHandling.All)]
public Base Prop { get; set; }
}
public class Base
{
public int IntProp { get; set; }
}
public class Child:Base
{
}
// Example:
var result = JsonConvert.SerializeObject(new Root
{
Prop = new Child()
});
Console.WriteLine(result); // prints {"Prop":{"$type":"SOAnswers.TestTypeNamehandling+Child, SOAnswers","IntProp":0}}
Imaging an XML-file like this:
<?xml version="1.0" encoding="UTF-16"?>
<treffer>
<prod_internid>123456789</prod_internid>
<md_nr>123123</md_nr>
<md_mart_id>4</md_mart_id>
<md_mtyp_nr>9876</md_mtyp_nr>
<mra_th>
<ie_th_pth>-1</ie_th_pth>
<ie_th_ea_bez>Fehler: Keine Angabe</ie_th_ea_bez>
</mra_th>
</treffer>
As you can see, there are three tags with <md_XY></md_XY>.
I want to deserialize them into an object that looks like this:
public class DeMedienXmlDto
{
[XmlElement("md_nr")]
public int MedienNr { get; set; }
[XmlElement("md_mart_id")]
public int MedienArtId { get; set; }
[XmlElement("md_mtyp_nr")]
public string MedienTypId { get; set; }
}
But this should be a property of the whole deserialized object:
[XmlRoot("treffer")]
public class DeAnalyseArtikelXmlDto
{
[XmlElement("prod_internid")]
public long ArtikelId { get; set; }
[XmlElement("treffer")]
public DeMedienXmlDto Medium { get; set; }
[XmlElement("mra_th")]
public List<DeThemenXmlDto> Themen { get; set; }
}
I've tried annotating the Medium property with [XmlElement("treffer")] since the tags are childs of <treffer> but that didn't work...
Deserializing the <mra_th>...</mra_th> works since I can annotate the list with the grouped tag but I don't have such a tag for <md...>.
How can I achieve this?
My xml deserializer looks like this:
public class XmlDeserializer : IXmlDeserializer
{
public T Deserialize<T>(string xmlFilename)
{
var returnObject = default(T);
if (string.IsNullOrEmpty(xmlFilename)) return default(T);
try
{
var xmlStream = new StreamReader(xmlFilename);
var serializer = new XmlSerializer(typeof(T));
returnObject = (T)serializer.Deserialize(xmlStream);
}
catch (Exception exception) {
LogHelper.LogError($"Das XML-File {xmlFilename} konnte nicht deserialisiert werden: {exception.Message}");
throw;
}
return returnObject;
}
}
Thanks in advance
Edit (to clarify):
I want the following tags deserialized into an object of type DeMedienXmlDto:
<md_nr>
<md_mart_id>
<md_mtyp_nr>
This is not how XmlSerializer works. The class structure must correspond to structure of the XML in order to work automatically.
This:
[XmlElement("treffer")]
public DeMedienXmlDto Medium { get; set; }
doesn't work, because there is no nested <treffer> element. The XmlElementAttribute cannot denote the parent (surrounding) element.
The are two options how to solve your situation:
Use a separate set of classes for deserialization, and a separate set representing your DTO objects. You'd then need to create a mapping.
Implement IXmlSerializable on DeAnalyseArtikelXmlDto and parse the inner XML yourself.
I want to serialize an object with DataMember attribute to be ignored on some properties.
Say I have custom attribute MyIgnoreDataMember.
I want properties marked with it to be invisible for my custom DataContractSerializer, but visible for the normal DataContractSerializer.
And I have to use DataContractSerializer and nothing else.
The code is a Silverlight app.
Anyone have done subclassing DataContractSerializer successfully?
An answer to your question is complicated by the following issues:
DataContractSerializer is sealed, so can't be subclassed to check for an attribute like MyIgnoreDataMember.
Using a serialization surrogate to inject an appropriate DTO into your object graph during serialization would normally be the way to go -- but it looks like it's not available on silverlight, see this answer.
DataContractSerializer does not support the ShouldSerialize pattern, as explained here, so you can't just suppress serialization of the undesired properties via a callback method.
So, what are your options? Let's say your object graph looks like the following:
[DataContract(Name = "Root", Namespace = "http://www.MyNamespace.com")]
public class RootObject
{
[DataMember]
public NestedObject NestedObject { get; set; }
}
[DataContract(Name = "Nested", Namespace = "http://www.MyNamespace.com")]
public class NestedObject
{
[DataMember]
public string SensitiveData { get; set; }
[DataMember]
public string PublicData { get; set; }
}
And you want to conditionally suppress output of SensitiveData. Then the following are possibilities:
If you only need to eliminate a few properties, you could mark them with EmitDefaultValue = false and return a default value when some thread static is true, for instance:
[DataContract(Name = "Root", Namespace = "http://www.MyNamespace.com")]
public class RootObject
{
[DataMember]
public NestedObject NestedObject { get; set; }
}
[DataContract(Name = "Nested", Namespace = "http://www.MyNamespace.com")]
public class NestedObject
{
string sensitiveData;
[DataMember(IsRequired = false, EmitDefaultValue = false)]
public string SensitiveData
{
get
{
if (SerializationState.InCustomSerialization())
return null;
return sensitiveData;
}
set
{
sensitiveData = value;
}
}
[DataMember]
public string PublicData { get; set; }
}
public static class SerializationState
{
[ThreadStatic]
static bool inCustomSerialization;
public static bool InCustomSerialization()
{
return inCustomSerialization;
}
public static IDisposable SetInCustomDeserialization(bool value)
{
return new PushValue<bool>(value, () => inCustomSerialization, b => inCustomSerialization = b);
}
}
public struct PushValue<T> : IDisposable
{
Action<T> setValue;
T oldValue;
public PushValue(T value, Func<T> getValue, Action<T> setValue)
{
if (getValue == null || setValue == null)
throw new ArgumentNullException();
this.setValue = setValue;
this.oldValue = getValue();
setValue(value);
}
#region IDisposable Members
// By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
public void Dispose()
{
if (setValue != null)
setValue(oldValue);
}
#endregion
}
And then, when serializing, do something like:
using (SerializationState.SetInCustomDeserialization(true))
{
// Serialize with data contract serializer.
}
Honestly quite ugly.
You could make an entire DTO hierarchy with the same contract names and namespaces as your real types, map the real classes to the DTO with something like automapper, and serialize the DTOs:
[DataContract(Name = "Root", Namespace = "http://www.MyNamespace.com")]
class RootObjectDTO
{
[DataMember]
public NestedObjectDTO NestedObject { get; set; }
}
[DataContract(Name = "Nested", Namespace = "http://www.MyNamespace.com")]
class NestedObjectDTO
{
[DataMember]
public string PublicData { get; set; }
}
If automapper is not available on silverlight, you can use DataContractSerializer itself to do the mapping, since the contract names and namespaces are identical. I.e. - serialize the real root object to an XML string (or to an XDocument as shown below), deserialize the intermediate XML to the DTO root, then serialize out the DTO.
You could serialize to an in-memory XDocument (which is available in silverlight) using the following extension class:
public static partial class DataContractSerializerHelper
{
public static XDocument SerializeContractToXDocument<T>(this T obj)
{
return obj.SerializeContractToXDocument(null);
}
public static XDocument SerializeContractToXDocument<T>(this T obj, DataContractSerializer serializer)
{
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
(serializer ?? new DataContractSerializer(obj.GetType())).WriteObject(writer, obj);
}
return doc;
}
public static T DeserializeContract<T>(this XDocument doc)
{
return doc.DeserializeContract<T>(null);
}
public static T DeserializeContract<T>(this XDocument doc, DataContractSerializer serializer)
{
if (doc == null)
throw new ArgumentNullException();
using (var reader = doc.CreateReader())
{
return (T)(serializer ?? new DataContractSerializer(typeof(T))).ReadObject(reader);
}
}
}
Next, prune the undesired elements using XPATH queries, and then serialize the XDocument to a final XML representation.
Finally, if performance and memory use are at a premium, you could use the ElementSkippingXmlTextWriter from this answer to prune undesired elements as they are written.
I want to serialize object and pass it to method which parameter type is parent of object.
For example, I have this classes.
public class Base
{
public string TypeName => GetType().Name;
public string Data => JsonConvert.SerializeObject(this);
}
public class Derived : Base
{
public string Name { get; set; }
public int data1 { get; set; }
public int data2 { get; set; }
}
public class Derived2 : Base
{
...
}
....
I wrote the code as follows,
var obj = new Derived { Name = "John", data1 = 2000, data2 = 1500 };
Send(obj);
And Send(..) method is,
public void Send(Base info)
{
// Do Something with "info".
}
When I instantiate variable obj, program has fallen into infinite recursion because of "Data" in Base class.
How can I change the code?
Infinite recursion is caused by the Data property, which is serialized - that causes serialization of the this and the loop begins.
The best solution would be to simply change the property into method, which would not be serialized and would better serve the purpose. If you are dead set on property - you could just try marking the property with http://www.newtonsoft.com/json/help/html/PropertyJsonIgnore.htm which will cause it to be ignored during serialization.
I am using Newtonsoft's JsonSerializer to serialise some classes.
As I wanted to omit one field of my class in the serialisation process, I declared it as follow:
[JsonIgnore]
public int ParentId { get; set; }
This worked, but I am now facing a new problem : In a derived class, I would like this field to appear (and do so only in this specific derived class).
I have been looking through the documentation and on the Internet for a way to override this setting in child classes (I guess I need something like [JsonStopIgnore], but I couldn't find anything close).
Is there any way for me to force JsonSerializer to pick up again this attribute ?
Is it possible to explicitly mark an attribute as [JsonIgnore], but only in base class ?
The only way to "override" the behavior of the [JsonIgnore] attribute is to use a contract resolver, as #Yuval Itzchakov nicely explained in his answer.
However, there is another possible solution that might work for you: instead of using a [JsonIgnore] attribute, you could implement a ShouldSerializeParentId() method in your classes to control whether the ParentId property gets serialized. In the base class, make this method return false; then, override the method in the derived class to return true. (This feature is known as conditional property serialization in Json.Net.)
public class Base
{
public int Id { get; set; }
public int ParentId { get; set; }
public virtual bool ShouldSerializeParentId()
{
return false;
}
}
public class Derived : Base
{
public override bool ShouldSerializeParentId()
{
return true;
}
}
Fiddle: https://dotnetfiddle.net/65sCSz
You can do this by creating a custom DefaultContractResolver and overriding its CreateProperty method.
For example, given a Foo base and a derived Bar:
public class Foo
{
[JsonIgnore]
public string Name { get; set; }
public int Age { get; set; }
}
public class Bar : Foo
{ }
You can create the following contract resolver:
public class MyTypeContractResolver<T> : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member,
MemberSerialization
memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.Ignored = false;
property.ShouldSerialize = propInstance => property.DeclaringType != typeof (T);
return property;
}
}
This will set all properties to Ignored = false, and then analyze them by the given predicate:
propInstance => property.DeclaringType != typeof (T);
Which in our case means "you should serialize only if they are not of type Foo" (since Foo is the DeclaryingType).
And then when you want to deserialize, you pass an instance of the contract resolver to JsonSerializerSettings:
var bar = new Bar();
var result = JsonConvert.SerializeObject(bar,
new JsonSerializerSettings {ContractResolver = new MyTypeContractResolver<Bar>()});
I solved the same problem by using the new keyword on the property of the derived class.
public class Foo
{
[JsonIgnore]
public int ParentId { get; set; }
}
public class Bar: Foo
{
[JsonProperty("ParentId")]
public new int ParentId { get; set; }
}
You can probably simply overwrite ParentId in the derived class.
public new int ParentId
{
get { return base.ParentId; }
set { base.ParentId = value; }
}
I solved the same problem with a ghost property :
public class Foo
{
[JsonIgnore]
public int ParentId { get; set; }
[NotMapped]
public int FooParent { get; set; }
}
When I want to show this property quite always hidden, I populate it, other times it is null :
Foos.ForEach(x => x.FooParent = ParentId);