c# xmlSerializer fails because POCO generator creating ICollection objects - c#

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.

Related

Serializing custom IEnumerable<T> as field not working

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.

type xxxx not expected use xmlinclude or soapinclude

I have a curious case of this serialization issue - which has been asked many times on this site and I have gone through a few of these questions and tried the usual items to no avail:
Add [XmlInclude] to the class throwing the error
Remove namespaces
Add a different namespace to each class
To explain further, I have provided a simplified version of my code below. Essentially I am using a WebServiceHost object to run a RESTful service and one of my endpoints returns an object serialized as XML (I have annotated the object with [DataContract] and [DataMember] attributes). This object contains a SerializableDictionary<string, object> (here) where the value has been typed as object. I believe this is why it is failing:
Works fine when the value is assigned a primitive
When I assign a custom object to the KV pair V, I get the unexpected type exception probably because the Serializer does not know how to serilaize the object / some sort of namespacing issue
Obviously, I am unable to annotate Object.cs with [XmlInclude] and because it is a service and I am not myself serializing I cannot using something like
new Serializer(typeof(...), new Type[] { ... }}
Any idea's of what I can do? I thought about not typing the dict value as object and rtaher comething more concrete but the problem is that this value can take primitives or cusotm types. Some code to explain the above:
Edit: Updated the code below to make it more clear
[DataContract]
public class ResponseObject
{
[DataMember(Name = "data")]
public SerializableDictionary<string, object> Data { get;set; }
public ResponseObject()
{
Data = new SerializableDictionary<string, object>();
}
}
...
var d1 = new ResponseObject();
d1.Data.Add("some key", "some value"); //WORKS AND SERIALIZES PERFECLTY
var d2 = new ResponseObject();
d2.Data.Add("some other key", new SomeOtherObjecT());
var d3 = new ResponseObject();
d3.Data.Add("another key", d2); //THIS THROWS THE UNEXPECTED TYPE ERROR WHEN SEIRLAIZING SomeOtherObject
Edit: The error is thrown in SerializableDictionary where it is attempting to serialize an object of type ResponseObject. The two are in seperate projects - if that is significant?
Normally, you should add an [XmlInclude] to the ResponseObject class. In this case, it doesn't work because of the SerializableDictionary that you're using. That class creates another XmlSerializer in its implementation, and therefore it doesn't care about your [XmlInclude]'s. Basically it just cannot handle your use case. You should switch from the XmlSerializer to the DataContractSerializer which handles the Dictionary class and supports the [KnownType] attribute to register additional types: http://pastebin.com/vGLSaxHF . Also note that it's pointless to add [DataContract] and [DataMember] attributes in your current case because the XmlSerializer ignores those attributes, they are used by the DataContractSerializer only. Or if you're not sure how to change your serializer (I know I'm not) then you should either not be using a Dictionary or change the SerializableDictionary implementation to handle the dynamic object types that you want to use (find every line where it creates a new XmlSerializer). Or, as an alternative, define a base class for all your objects that you will ever put into the dictionary and do it like this:
[XmlInclude(typeof(Class1), XmlInclude(typeof(Class2)), etc]
public class AbstractBase { }
public class Class1 : AbstractBase { ... }
public class Class2 : AbstractBase { ... }
public class BigClass {
public SerializableDictionary<string, AbstractBase> Dictionary { get; set; }
}
This way, when the SerializableDictionary creates its own XmlSerializer, it will recognize the AbstractBase and from there, all of its descendants.

Deserialization of JSON object by using DataContractJsonSerializer in C#

I'm sure this question has been asked over and over again, but for some reason, I still can't manage to get this to work.
I want to deserialize a JSON object that contains a single member; a string array:
[{"idTercero":"cod_Tercero"}]
This is the class that I'm trying to deserialize into:
[DataContract]
public class rptaOk
{
[DataMember]
public string idTercero { get; set; }
public rptaOk() { }
public rptaOk(string idTercero)
{
this.idTercero = idTercero;
}
}
This is the method that I try to deserialize:
public T Deserialise<T>(string json)
{
DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
T result = (T)deserializer.ReadObject(stream);
return result;
}
}
And so I try to fill the object:
rptaOk deserializedRpta = deserializarOk(rpta);
But for some reason, this returns ""
MessageBox.Show(deserializedRpta.idTercero);
Without any dependencies outside of the .net framework, you could do it this way
[DataContract(Name="rptaOk")]
public class RptaOk
{
[DataMember(Name="idTercero")]
public string IdTercero { get; set; }
}
[CollectionDataContract(Name="rptaOkList")]
public class RptaOkList : List<RptaOk>{}
var stream = new StreamReader(yourJsonObjectInStreamFormat);
var serializer = new DataContractSerializer(typeof(RptaOkList));
var result = (RptOkList) serializer.ReadObject(stream);
I don't know if your're wiling to change the library that you're using, but I use library "Newtonsoft.Json" to desserialize JSON objects, it's pretty easy to use
[HttpPost]
public void AddSell(string sellList)
{
var sellList = JsonConvert.DeserializeObject<List<Sell>>(sellListJson);
BD.SaveSellList(sellList);
}
As you can see you can deserialize a whole json object list to a List<> fo the type "Sell", an object that i've created... And, of course, you can do that to an array too. I don't know the correct syntax for this, but you can convert this list to an array afterwards
Hope this helps
I think you're making this a lot more difficult than it needs to be. Firstly, your sample json and the class you're trying to deserialize into do not have an array of strings. They have a single property of type string. Secondly, why are you using this class DataContractJsonSerializer? You're not doing anything with it that you can't get from a simple call to json.NET's generic deserialization method. I would remove all of your code except the class definition and replace it with this simple one liner;
rptaOk[] myInstances = JsonConvert.DeserializeObject<rptaOk>(jsonString);
Also, no matter what the structure of your json is, if you have a class to correctly model it that method will correctly deserialize it. If you want to enforce some kind of contract I recommend using json schemas which json.NET also supports. If you use a schema it enforces a rigid contract, if you attempt to deserialize into an object there is something of an implicit contract. I don't know every scenario which will cause it to throw, but if your json is too far from the class definition it will. If your class has properties that don't appear in the json I believe they will just get initialized with the default values for that type.
EDIT: I just noticed your json is actually an array of objects. So you simply need to make the lhs of that assignment an array or rptaOk objects, rather than a singleton.

Linq To Sql objects and Serialization issue

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

C# XML Serialization - weakening encapsulation?

Am I correct in thinking that, in order to get C# to serialize an object, I MUST have a public property for every field that needs its state stored?
If so, is that not very very sucky, as it weakens (if not breaks entirely) any encapsulation my class has?
In Java, XStream can iterate over every non-transient field and archive it. In C# this can't happen, and just to make things worse, things like Dictionaries don't serialize AT ALL. It's all a bit of a mess, no?
I've seen the DLL for a "port" of XStream to .net, but there are no docs and I'm suspicious.
You should use DataContractSerializer, and mark every property/field you want to serialize with [DataMember]. It doesn't care if your fields are private or public. By the way you can serialize Dictionaries with it...
[DataContract]
public class MyClass
{
[DataMember]
private string _privateField;
[DataMember]
public int PublicProperty { get; set;}
}
Serialization :
private static string SerializeXml<T>(T item)
{
DataContractSerializer ser = new DataContractSerializer(item.GetType());
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings { OmitXmlDeclaration = true, ConformanceLevel = ConformanceLevel.Fragment };
using (XmlWriter writer = new XmlWriter(sb, settings))
{
ser.WriteObject(writer, item);
}
return sb.ToString();
}
Look here for differences between XmlSerializer and DataContractSerializer : http://www.danrigsby.com/blog/index.php/2008/03/07/xmlserializer-vs-datacontractserializer-serialization-in-wcf/
The binaryformatter serializes private and even readonly fields without the need for properties. The XmlSerializer can only serialize with a public no-arg constructor and public properties. If you want to use XmlSerializer with encapsulation you can use IXmlSerializable, but that is rather painful.
If your object model is fairly simple or you can make it fairly simple by introducing special DTO:s for serialization (e.g. to avoid structs), then I recommend using a contract based serializer that can serialize private fields or properties. Have a look at protobuf-net.

Categories