I have a class which inherits from a collection, specifically List<> and I've listed the class below. The problem I'm encountering when I serialize the object to XML using DataContractSerializer is the additional fields I've added within the object are not getting serialized by the serializer.
Here is the class:
[CollectionDataContract(Name = "ServiceEvents", Namespace = "")]
public class ServiceEventList : List<ServiceEvent>
{
[DataMember]
public long StaleDate { get; set; }
[DataMember]
public long ExpirationDate { get; set; }
}
When I serialize the object and write to disk, here is the output (notice both StaleDate and ExpirationDate are missing).
<ServiceEvents xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><ServiceEvent><Date>2012-06-26T22:23:24.120817Z</Date><Description>A Service Event</Description><Id>634763462041210040</Id><Notes></Notes><Odometer>42</Odometer></ServiceEvent></ServiceEvents>
Here is the code that serializes the object:
using (FileStream fs = new FileStream(path, FileMode.Create))
{
//TODO: StaleDate is not serializing to disk
//TODO: ExpirationDate is not serializing to disk
DataContractSerializer ser = new DataContractSerializer(typeof(ServiceEventList));
ser.WriteObject(fs, list);
}
My next thought is to remove the inheritance structure and just embed a List object into the class. I'd prefer to just extend List but won't waste more time on it if the community confirms my approach won't work. Thanks in advance for the advice.
According to this post:
http://social.msdn.microsoft.com/Forums/eu/wcf/thread/57eb195a-43a9-47fe-8b1a-a9d23feb2df2
the problem is indeed that you inherit from a collection type - in this case the DataContractSerializer serializes only its items, but not any extra properties.
Related
I am using .net Core 1.1 and writing a console application. I need to Serialize an Object with some basic properties of strings and int as well as some IEnumerable Objects and serialize it as XML so I can save it to a "data.xml" file.
I receive the Exception:
System.Runtime.Serialization.SerializationException: 'Type 'System.Collections.Generic.List`1[[CorpsDataExtractor.ViewModels.LegacyView, CorpsDataExtractor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' with data contract name 'ArrayOfLegacyView:http://schemas.datacontract.org/2004/07/CorpsDataExtractor.ViewModels' is not expected. Add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.'
I currently am able to serialize my Object as JSON, but am having trouble utilizing the DataContractSerializer. I Added the Known Type List that the exception states I am missing but it still fails.
// This List isretrieved using Entity Framework Core
List<LegacyView> legacyData = await _corpsRepo.ListLegacyData();
// The Below Line will write to a JSON File. No Error and works
File.WriteAllText(#"E:\\CorporationsDataLegacy.json", JsonConvert.SerializeObject(legacyData));
// This Creates a Known Type List for the DataContractSerializer
var knownTypeList = new List<Type>
{
typeof(LegacyView),
typeof(People),
typeof(DocumentType)
};
FileStream writer = new FileStream(#"E:\\data.xml", FileMode.Create);
var ser = new DataContractSerializer(typeof(LegacyView), knownTypeList );
// When Debugging I Receive The stated exception at this line
ser.WriteObject(writer, legacyData);
Below Are my Class ViewModels:
Legacy View
[DataContract]
public class LegacyView
{
[DataMember]
public string Ubi { get; set; }
[DataMember]
public IEnumerable<Person> People{ get; set; }
[DataMember]
public IEnumerable<DocumentType> DocumentTypes { get; set; }
}
Person
[DataContract]
public class Person
{
[DataMember]
public string FirstName { get; set; }
[DataMember]
public string MiddleName { get; set; }
}
Documents
[DataContract]
public class DocumentType
{
[DataMember]
public string Document { get; set; }
[DataMember]
public DateTime? CompletedDate { get; set; }
}
Any Direction on what I am missing?
I might be a bit off as I've done more of XmlSerialize rather than DataContracts one, but I believe both assume eventual deserialization of the content. And with IEnumerable<T> as the type, deserializer wouldn't know what class to actually instantiate to back the interface during deserialization. Change fields to concrete classes instead of enumeration, and that should work.
By using a Both Gusman and LB2 comments I was able to solve the issue. As LB2 states "with IEnumerable as the type, deserializer wouldn't know what class to actually instantiate to back the interface during deserialization."
This is why the error was occurring, however the problem did not exist at the Class LegacyView [DataMember] level, it existed at the known Types that were being passed into the DataContractSerializer.
Gusman was correct that I needed to tell the DataContractSerializer that these were going to be an enumerable type.
// I needed to tell the DataContractSerializer what the types were
var knownTypeList = new List<Type>
{
typeof(List<LegacyView>),
typeof(List<People>),
typeof(List<DocumentType>)
};
using (var writer = new FileStream(#"E:\\myTestExample.xml", FileMode.Create))
{
var ser = new DataContractSerializer(typeof(LegacyView), knownTypeList);
ser.WriteObject(writer, legacyData);
}
I have the following business object
public class Employee
{
[JsonProperty("first_name")]
public string FirstName { get; set; }
public string Lastname { get; set; }
public DateTime DateOfBirth { get; set; }
public uint Salary { get; set; }
}
And i have the following interface and implementation for json serialization
interface IJSONSerializer<T>
{
string Serialize(T obj);
}
class NewtonJsonSerialization<T> : IJSONSerializer<T>
{
public string Serialize(T obj)
{
return JsonConvert.SerializeObject(obj, Formatting.Indented);
}
}
And here is my client code
var Employee = new Employee();
Employee.FirstName = "Ihor";
Employee.Lastname = "fff";
IJSONSerializer<Employee> serailizer = new NewtonJsonSerialization<Employee>();
var result = serailizer.Serialize(Employee);
What i dislike here - that Employee knows that it will be serialized with some specific library(because of JsonProperty attribute). So, if i decide to use another json serializer or write my own, i will need to go through all business objects and modify them. Is it possible to make my business objects serialization ignorance ? If yes how ?
The same with XML serialization and XmlSerializer class: i need to mark properties in business object with some attribute.
There is a term "persistence ignorance" which means that business objects are not aware of persistence. Is there the same about serialization ?
Most serializers make use of .Net's DataContract attributes. Json.net does as well. Try this sample out and make sure to look up the documentation for DataMember on MSDN to learn how to influence serialization.
Unless you need serialized key/element names to different than defined on your C# class, you should not worry about attributes at all. Both JSON and XML work just fine without decorating you class properties with serialization specific attributes.
If you really need custom key/element names in serialized data, then you must decorate your class props with multiple attributes. Any serializer will just read relevant attribute and ignore rest.
public class Person
{
[JsonProperty("first_name")]
[XmlElement("first_name")]
public string FirstName { get; set; }
}
Calling Code
ISerializer<Person> serializer;
string result;
var person = new Person { FirstName = "Nikhil" };
serializer = new NewtonsoftJsonSerializer<Person>();
result = serializer.Serialize(person);
/* Output
{"first_name":"Nikhil"}
*/
serializer = new BuiltInXmlSerializer<Person>();
result = serializer.Serialize(person);
/* Output
<Person
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<first_name>Nikhil</first_name>
</Person>
*/
Edit:
As per #Michael Nero DataContract and DataMember attributes will work in most cases but not all. Very first exception on such list is .NET's built in XmlSerializer which does not work without XmlElement attribute for custom element name.
This question already has answers here:
Circular reference detected exception while serializing object to JSON
(9 answers)
Closed 9 years ago.
I'm having trouble making an client-server app.
I'm working with Entity Framework(EF) and I need to serialize an object to send it via sockets that contains List attributes.
I'm using XMLSerialization for the Serialization part.
My problem is: When I try to Serialize a new Survey object and the OPTIONs List is Empty I can Serialize the object SURVEY. But, when I add an OPTION object to the SURVEY.OPTIONS list I cannot Serialize the object.
One of the classes that EF auto-generates from the Entity-Relationship Diagram is:
public partial class SURVEY
{
public SURVEY()
{
this.OPCIONs = new List<OPTION>();
}
public int id_survey { get; set; }
public System.DateTime initial_date { get; set; }
public System.DateTime end_date { get; set; }
public virtual List<OPTION> OPTIONs { get; set; }
}
I'm using this Code for get a Survey from the Database:
DateTime actualDate = new DateTime().Today;
private static ComedorCaniaDBContext context = new ComedorCaniaDBContext();
Survey survey = context.SURVEYs.Create()
survey = (SURVEY)context.SURVEYs
.Include("Options")
.Where(e => e.initial_date < actualDate && e.end_date > actualDate)
.FirstOrDefault();
I'm using this Code for Serialization:
public static Byte[] ObjectToByteArray<T>(T obj)
{
try
{
using (MemoryStream ms = new MemoryStream())
{
XmlSerializer xmlS = new XmlSerializer(typeof(T));
xmlS.Serialize(ms, obj);
return ms.ToArray();
}
}
catch
{
return null;
}
}
I'll appreciate your help.
Thanks.
Entity Framework is near impossible to make work with the built-in XML serializer and BinaryFormatter serializer, if you don't want to lose features like lazy loading. They just aren't made to deal with that.
You're going to have to use a different serializer that can handle Entity Framework objects, such as JSON.Net, or else write your own serializer.
See the following articles for the long line of others who have had the same question:
Circular reference detected exception while serializing object to JSON
How did I solve the Json serializing circular reference error?
Basically, you either get to keep lazy loading and use some other serializer or lose it and continue to use the built-in serializer.
I hope to find a solution from you. What I need is to serialize ValidatorList class object into an xml document. How to do this?
I tried like this:
XmlSerializer _serializer = new XmlSerializer(list);
But I don't know how to make output of xml for list that has several classes.
C#
_list= new ListVal();
Type _type = typeof(ras);
_list.Add(new RequiredField
{
Property = _type.GetProperty("CustRef")
}.Add(new AsciiVal()));
_list.Add(new RequiredField
{
Property = _type.GetProperty("ctr")
}.Add(new StringLengthVal
{
min= 3,
max= 3
}));
[Serializable]
public class Field
{
public Field Next
{
get;
set;
}
public Field TypeName
{
get;
set;
}
public Field PropertyName
{
get;
set;
}
}
public class RequiredField : Field
{
//TODO
}
public class AsciiVal: Field
{
//TODO
}
public class StringLengthVal: Field
{
//TODO
}
public class ListVal: List<Field>
{
//TODO
}
I have something close, but not exactly the Xml you want. In actual fact I think you'll see that the Xml produced below makes a bit more sense than what you have.
To get you started, you control the serialization and deserialization using attributes in the System.Xml.Serialization namespace. A few useful ones to read up on are
XmlRootAttribute
XmlElementAttribute
XmlAttributeAttribute
XmlIncludeAttribute
So I mocked up some code which closely matches your own. Notice the addition of some attributes to instruct the serializer how I want the Xml to be laid out.
[XmlInclude(typeof(AsciiValidator))]
[XmlInclude(typeof(RequiredValidator))]
[XmlInclude(typeof(StringLengthValidator))]
public class FieldValidator
{
[XmlElement("Next")]
public FieldValidator Next
{
get;
set;
}
[XmlElement("PropertyName")]
public string PropertyName
{
get;
set;
}
}
public class AsciiValidator: FieldValidator
{
}
public class RequiredValidator: FieldValidator
{
}
public class StringLengthValidator: FieldValidator
{
[XmlElement]
public int MinLength{get;set;}
[XmlElement]
public int MaxLength{get;set;}
}
[XmlRoot("ValidatorList")]
public class ValidatorList : List<FieldValidator>
{
}
Point of interest; Every class inheriting FieldValidator must be added to the list of known types using XmlIncludeAttribute so the serializer knows what to do with them)
Then I created an example object map:
var test = new ValidatorList();
test.Add(
new RequiredValidator()
{
PropertyName="CustRef",
Next = new AsciiValidator()
});
test.Add(
new RequiredValidator()
{
PropertyName="CurrencyIndicator",
Next = new StringLengthValidator(){
MinLength=3,
MaxLength = 10
}
});
Finally I told the serializer to serialize it (and output the result to the console)
var ser = new XmlSerializer(typeof(ValidatorList));
ser.Serialize(Console.Out,test);
This was the result:
<?xml version="1.0" encoding="utf-8"?>
<ValidatorList xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FieldValidator xsi:type="RequiredValidator">
<Next xsi:type="AsciiValidator" />
<PropertyName>CustRef</PropertyName>
</FieldValidator>
<FieldValidator xsi:type="RequiredValidator">
<Next xsi:type="StringLengthValidator">
<MinLength>3</MinLength>
<MaxLength>10</MaxLength>
</Next>
<PropertyName>CurrencyIndicator</PropertyName>
</FieldValidator>
</ValidatorList>
Not a million miles away from what you wanted. There is the need to output certain things in a certain way (eg xsi:type tells the serializer how to deserialize back to the object map). I hope this gives you a good start.
Here is a live, working example: http://rextester.com/OXPOB95358
Deserialization can be done by calling the Deserialize method on the XmlSerializer.
For example, if your xml is in a string:
var ser = new XmlSerializer(typeof(ValidatorList));
var test = "<..../>" // Your Xml
var xmlReader = XmlReader.Create(new StringReader(test));
var validatorList = (ValidatorList)ser.Deserialize(xmlReader);
There are many overrides of Deserialize which take differing inputs depending if the data is in a Stream an existing reader, or saved to a file.
You have to decorate the class that contains the _validators field with the KonwnType attribute
[Serializable]
[KwownType(typeof(RequiredFieldValidator)]
[KwownType(typeof(AsciValidator)]
public class MySerialisableClass
I have several SO answers that detail how to serialize objects using XML. I'll provide links below.
However, since you're looking for a rather simple serialization of your object, you may want to read up on the DataContractSerializer. It's much less complicated than the old .NET 1.x XML Serialization.
Here's the list of SO answers:
Omitting all xsi and xsd namespaces when serializing an object in .NET?
XmlSerializer: remove unnecessary xsi and xsd namespaces
Suppress xsi:nil but still show Empty Element when Serializing in .Net
Using XmlAttributeOverrides on Nested Properties
Even though many of these have to do with XML serialization and namespaces, they contain complete examples of serializing an object to XML using .NET 1.x XML Serialization.
I am using the XmlSerializer, and was wondering if there is any way, using overrides or something to that effect to get the XmlSerializer to output the types of some nodes.
My problem is that I have serialized a byte array.
class MyClass {
public string Name { get; set; }
public byte[] Bytes { get; set; }
}
I am consuming the xml in a generic service.
The service collects the xml as .
<MyClass>
<Name>Test</Name>
<Bytes>U2NhcnkgQnVnZ2Vy</Bytes>
</MyClass>
Is there any way to either generate an xsd at runtime, or somehow output something like this.
I cannot change the class I am serializing, but I can apply overrides to the serializer or in some other way control the serialization.
<Bytes xsi:type='BinaryOfSomeKind'>BlahBlah</Bytes>
I need to know that the data is binary somehow.
Thanks
Craig.
If your class is supplied by a third party then you know your properties and property types and you can deduce your XML and XSD from it. You can create your XSD manually or with the help of a XML tool for example XMLSpy (not free BTW) or XMLFox which is free of charge.
If you know the xml is going to be in that format that you put in the question and you have your class ready you can decorate it as such for it to be deserialized.
The Deserialization class:
[XmlTypeAttribute]
[XmlRootAttribute("MyClass")]
public class MyClass
{
[XmlElementAttribute("Name")]
public string Name { get; set; }
[XmlElementAttribute("Bytes")]
public byte[] Bytes { get; set; }
}
The Deserialzation Method
public static object Deserialize(string xml)
{
var deserializer = new System.Xml.Serialization.XmlSerializer(typeof(MyClass));
using (var reader = XmlReader.Create(new StringReader(xml)))
{
return (MyClass)deserializer.Deserialize(reader);
}
}
The Main Method
static void Main(string[] args)
{
string xml = #"<MyClass>
<Name>Test</Name>
<Bytes>U2NhcnkgQnVnZ2Vy</Bytes>
</MyClass>";
MyClass obj = (MyClass)Deserialize(xml);
Console.ReadKey();
}
Make sure to add the following using statements:
using System.Xml.Serialization;
using System.Xml;
It deserialized it into an obj with "Test" as the byte array.
If you generate the XSD at run time, then theres no way you can know what properties there are and it would be down to using reflection to test for specific properties, and then subsequently finding out what types they may be, is this what your after?