I am trying to serialize an object graph. It works up until I have to load a child entity that is an entity set. The system won't allow it to serialize... it gives me this error:
Type 'System.Data.Linq.EntitySet`1[NetDataContractSerializerTest.JobService]' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
Here is the code I am using:
DataClasses1DataContext dataAccessContext = new DataClasses1DataContext();
MemoryStream stream = new MemoryStream();
DataLoadOptions dataloadOptions = new DataLoadOptions();
dataloadOptions.LoadWith<JN>(j => j.nh);
dataloadOptions.LoadWith<JN>(j => j.JobServices);// this is the child entity set
dataAccessContext.LoadOptions = dataloadOptions;
var jn= dataAccessContext.JN.Where(j => j.LocnID.Trim() == "HT").ToList();
var netDataContractSerializer = new NetDataContractSerializer();
netDataContractSerializer.Serialize(stream, jn); //the error happens here
If I remove the
dataloadOptions.LoadWith(j => j.JobServices)
the data will serialize with the JN and nh tables intact. But when I put
dataloadOptions.LoadWith(j => j.JobServices)
back in I get the error.
I personally think that it wants me to add a ToList() to the JobServices, unfortunately I can't do
dataloadOptions.LoadWith(j => j.JobServices.ToList())
This throws an error.
Any ideas?
The error message is very informative: the JobService class is not marked to be serialized as a data contract.
You'll need to decorate it with the DataContractAttribute attribute, and decorate the members with DataMember attribute.
[DataContract]
public class JobService
{
[DataMember]
public string SomeProperty { get; set;}
}
Well well well.... look what I found..... This seemed to serialize and deserialize my stuff just fine. Instead of using NetDataContractSerializer.Serialize() to it, this guy wrote serialize and deserialize functions that used DataContractSerializer, XMLWriter and XMLReader
Check the link below
http://www.codeproject.com/Tips/47054/How-to-serialize-list-of-linq-entities-ex-from-DBM
Related
I have seen a lot of issues using the XmlSerializer on SO, and yes most of the issues seem to be around complex objects.
Mine issue is the same in essence, but with a twist.
I have used the Entityframework POCO generator to create my database objects.
Now, I am trying to compare complex objects using XmlSerializer.
So in my save, I am doing the following:
viewModelObj = returned object model from MVC page.
db.originalData.ToList() = original data object
var a = SerializeObject(viewModelObj);
var b = SerializeObject(db.originalData.ToList());
with the following definition for my SerializeObject function.
public static string SerializeObject(this List<myObject> toSerialize)
{
var xmlSerializer = new XmlSerializer(toSerialize.GetType());
using (StringWriter textWriter = new StringWriter())
{
xmlSerializer.Serialize(textWriter, toSerialize);
return textWriter.ToString();
}
}
Because myObject repersents my POCO classes, Lists are defined as ICollection, which in turn causes the XmlSerializer to fail with the following message:
Cannot serialize member toSerialize of type System.Collections.Generic.ICollection`1[[myObject]] because it is an interface.
Which is the correct response.
Every time i run the EF POCO Generator, it changes everything back to ICollections, so my question is how can i use XmlSerializer using the POCO classes?
Update
Changed code from
public static string SerializeObject(this List<myObject> toSerialize)
to
public static string SerializeObject<T>(this List<T> toSerialize)
This is when I get the error message:
Cannot serialize member [object] of type System.Collection.Generic.ICollection'1[[object]] because it is an interface.
Just given up. re coded around this issue by adding a status field and checking to see if it has changed.
I have a custom base class Entity decorated with [DataContract(IsReference = true)] and deriving from UndoableBase of CSLA.net. Keeping IsReference is important to preserve object reference data.
[Serializable]
[DataContract(IsReference = true)]
public abstract class Entity : UndoableBase
I am getting exception upon serialization using below code snippet:
public void SerializeToFile(string fileName, T obj)
{
_serializer = new DataContractSerializer(typeof(T));
Serialize(fileName, obj);
}
private void Serialize(string fileName, T obj)
{
using (var fs = File.Open(fileName, FileMode.Create))
{
_serializer.WriteObject(fs, obj);
fs.Close();
}
}
System.Runtime.Serialization.InvalidDataContractException
The IsReference setting for type 'Entity' is 'True', but the same
setting for its parent class 'Csla.Core.UndoableBase' is 'False'.
Derived types must have the same value for IsReference as the base
type. Change the setting on type 'Entity' to 'False', or on type
'Csla.Core.UndoableBase' to 'True', or do not set IsReference
explicitly.
If I remove this IsReference attribute altogether I start getting following error:
Object graph for type 'XYZ' contains cycles and cannot be serialized
if reference tracking is disabled.
Now my question is how to solve it by changing the IsReference setting for Csla.Core.UndoableBase during serialization using some API.
While researching on this topic I came across this post, which talks about using DataContractSurrogate. Please help how to use it specifically if it is helpful in this case or suggest any other technique solving it.
How to serialize class that derives from class decorated with DataContract(IsReference=true)?
After quite a struggle I was finally able to find the answer to this question. There is an overloaded constructor which takes preserveObjectReferences flag to instruct the serializer to preserve the References. In my case, I have now removed IsReference annotation from all over and used below overload for serialization and life is good.
var serializer = new DataContractSerializer(typeof(T), knownTypes,
int.MaxValue /*maxObjectsInGraph*/,
false /*ignoreExtensionDataObject*/,
true /*preserveObjectReferences*/,
null /*dataContractSurrogate*/);
Reference: Preserving Object Reference in WCF
I have a custom collection that looks like this:
class SpecialReadOnlyCollection<T> : IReadOnlyCollection<T>{
private readonly List<T> entries;
public SpecialReadOnlyCollection(IEnumerable<T> source){
entries = new List<T>(source);
}
...
}
That (among other things) wraps a list but doesn't offer an Add method.
Now I have two other classes:
class A{
public string Name;
public int Value;
}
class ContainerOfA{
public SpecialReadOnlyCollection<A> list;
public ContainerOfA(IEnumerable<A> source){
this.list = new SpecialReadOnlyCollection<A>(source);
}
}
I want to serialize a ContainerOfA. Since I don't like attributes, this is how I build the model and try to serialize.
// Make A serializable
var metaType = Model.Add(typeof(A),true);
metaType.AddField(1,"Name");
metaType.AddField(2,"Value");
metaType.UseConstructor = false;
// Make SpecialCollection serializable
Model.Add(typeof(SpecialReadOnlyCollection<A>),true).AddField(1,"entries");
Model[typeof(SpecialReadOnlyCollection<A>)].IgnoreListHandling = true;
Model[typeof(SpecialReadOnlyCollection<A>)].UseConstructor = false;
// Make container serializable
Model.Add(typeof(ContainerOfA),true).AddField(1,"list");
Model[typeof(ContainerOfA)].UseConstructor = false;
// Initialize the container
A a = new A{Name ="Name", Value =1};
A[] arr = {a};
var container = new ContainerOfA(arr);
// Try and serialize ....
Model.DeepClone(container);
However, when I try to serialize, I get an exception:
Unable to resolve a suitable Add method for SpecialReadOnlyCollection[A]
What I find weird is that if I try to serialize just the list it works fine:
Model.DeepClone(container.list);
Everything works fine as well if I instead of building the model in code use attributes. In fact, everything works if I use attributes only in ContainerOfA and make A and the SpecialReadOnlyCollection serializable via code.
Is there something I am doing wrong? How can I get around this? (Probably the easiest answer is to use attributes ... but I really want to avoid attributes).
tl;dr: How to, via RuntimeTypeModel, use protobuf-net serialize a class that has as a member an IEnumerable that should not be treated as a list (IgnoreListHandling = true).
protobuf-net supports a range of list patterns; in your case, it is trying to use the IEnumerable<T>/GetEnumerator() and Add(T) pattern. It needs both of those things: the IEnumerable<T>/GetEnumerator() is used for serialization, and the Add(T) is used for deserialization. If your custom collection does not have an obvious Add(T) method, then protobuf-net will refuse to work with the collection, because it won't ever be able to deserialize. That is what the method is telling you.
The only way to get around this is probably with a mutable DTO model, rather than this read-only collection. There are things like implicit type conversions that protobuf-net supports, but not for this scenario.
Background: This question is about logging the change tracking of a POCO class in C# .NET 4.0.
Let's say I have a Person class with a Name (string) property. That Name property has a custom Attribute called [IsDirty(true/false)] that is set dynamically by a property-auditing class.
[IsDirty(true)]
public string Name { get; set; }
After the changes are detected and the attributes are set, I'm storing the object via normal XML Serialization in a MS SQL Database (XML column type).
What I can't figure out is if it's possible to somehow serialize my custom attribute IsDirty along with it's current value - preferably as an XML attribute on the serialized XML element (Name) so that the final xml is like:
<Name IsDirty="true">John</Name>
Any ideas/info would be appreciated-
I think you're going to have to write your own XML serialization for this and mix in some reflection to check attribute values on properties.
There's a good guide to implementing the IXMLSerializable interface here. Unfortunately you will have to implement serialization of all properties in the class, but on the bright side, if you implement IXmlSerializable correctly, you can still use the XmlSerializer class.
In your serialization code, you can check the attribute value using something like this:
public class YourClass : IXmlSerializable
{
[IsDirty(true)]
public string Name { get; set; }
// skipped ReadXml and GetSchema interface methods for brevity
public void WriteXml(XmlWriter writer)
{
writer.WriteStartElement("YourClass");
var myType = typeof(YourClass);
foreach(var propInfo in myType.GetProperties())
{
writer.WriteStartElement(propInfo.Name);
foreach(var attr in propInfo.GetCustomAttributes(typeof(IsDirtyAttribute), false))
{
var myAttr = attr as IsDirtyAttribute;
writer.WriteAttributeString("Dirty", attr.Value ? "true" : "false");
}
writer.WriteEndElement();
}
writer.WriteEndElement();
}
}
This code is untested and written from memory, so there are probably some bugs lurking around, but hopefully it'll get you on the right track.
It would be possible by manually reading your Attribute and its value. You could do this by wrapping the serialization and deserialization in methods that appended/read the to/from the xml and the attribute..
However I would inherit these classes from a base class that had the property IsDirty then you neednt worry!
I'm having issues deserializing certain Guid properties of ORM-generated entities using protobuf-net.
Here's a simplified example of the code (reproduces most elements of the scenario, but doesn't reproduce the behavior; I can't expose our internal entities, so I'm looking for clues to account for the exception). Say I have a class, Account with an AccountID read-only guid, and an AccountName read-write string. I serialize & immediately deserialize a clone.
Deserializing throws an Incorrect wire-type deserializing Guid exception while deserializing.
Here's example usage...
Account acct = new Account() { AccountName = "Bob's Checking" };
Debug.WriteLine(acct.AccountID.ToString());
using (MemoryStream ms = new MemoryStream())
{
ProtoBuf.Serializer.Serialize<Account>(ms, acct);
Debug.WriteLine(Encoding.UTF8.GetString(ms.GetBuffer()));
ms.Position = 0;
Account clone = ProtoBuf.Serializer.Deserialize<Account>(ms);
Debug.WriteLine(clone.AccountID.ToString());
}
And here's an example ORM'd class (simplified, but demonstrates the relevant semantics I can think of). Uses a shell game to deserialize read-only properties by exposing the backing field ("can't write" essentially becomes "shouldn't write," but we can scan code for instances of assigning to these fields, so the hack works for our purposes).
Again, this does not reproduce the exception behavior; I'm looking for clues as to what could:
[DataContract()]
[Serializable()]
public partial class Account
{
public Account()
{
_accountID = Guid.NewGuid();
}
[XmlAttribute("AccountID")]
[DataMember(Name = "AccountID", Order = 1)]
public Guid _accountID;
/// <summary>
/// A read-only property; XML, JSON and DataContract serializers all seem
/// to correctly recognize the public backing field when deserializing:
/// </summary>
[IgnoreDataMember]
[XmlIgnore]
public Guid AccountID
{
get { return this._accountID; }
}
[IgnoreDataMember]
protected string _accountName;
[DataMember(Name = "AccountName", Order = 2)]
[XmlAttribute]
public string AccountName
{
get { return this._accountName; }
set { this._accountName = value; }
}
}
XML, JSON and DataContract serializers all seem to serialize / deserialize these object graphs just fine, so the attribute arrangement basically works. I've tried protobuf-net with lists vs. single instances, different prefix styles, etc., but still always get the 'incorrect wire-type ... Guid' exception when deserializing.
So the specific questions is, is there any known explanation / workaround for this? I'm at a loss trying to trace what circumstances (in the real code but not the example) could be causing it.
We hope not to have to create a protobuf dependency directly in the entity layer; if that's the case, we'll probably create proxy DTO entities with all public properties having protobuf attributes. (This is a subjective issue I have with all declarative serialization models; it's a ubiquitous pattern & I understand why it arose, but IMO, if we can put a man on the moon, then "normal" should be to have objects and serialization contracts decoupled. ;-) )
Thanks!
Agreed, you shouldn't need an explicit dependency - DataMember is fine. And protobuf-net uses the same logic re ignore etc. How / where are you storing the data? In my experience the most common cause of this is that people are over-writing a buffer (or file) with different data, and not truncating it (leaving garbage at the end of the stream), as discussed here. Is this related to your scenario?