C# xml Serialize with XmlIgnore and Deserialize problem - c#

Hello I have problem with deserialize xml
First I have class like that
public class ReportsViewModel
{
private DateTime fromDateTime;
[XmlIgnore]
public DateTime FromDateTime
{
get { return fromDateTime; }
set
{
fromDateTime = value;
}
}
[XmlElement]
public int FromDateTimeCal
{
get
{
return fromDateTime.Subtract(DateTime.Today).Days;
}
set
{
var a = fromDateTime.Subtract(DateTime.Today).Days;
a = value;
}
}
private DateTime toDateTime;
[XmlIgnore]
public DateTime ToDateTime
{
get { return toDateTime; }
set
{
toDateTime = value;
}
}
[XmlElement]
public int ToDateTimeCal
{
get
{
return ToDateTime.Subtract(DateTime.Today).Days;
}
set
{
var a = ToDateTime.Subtract(DateTime.Today).Days;
a = value;
}
}
}
And then I serialize them
ReportsViewModel reportVM = new ReportsViewModel();
reportVM.FromDateTime = new DateTime(2019, 02, 18);
reportVM.ToDateTime = new DateTime(2019, 02, 22);
using (StreamWriter sw = new StreamWriter(#"D:\Temp\Report.xml"))
{
XmlSerializer xml = new XmlSerializer(typeof(ReportsViewModel));
xml.Serialize(sw, reportVM);
}
Now I get XML file that contain only FromDateTimeCal and ToDateTimeCal
but the problem begin when I deserialize them.
I using deserialize with ReportViewModel class
using (StreamReader sw = new StreamReader(#"D:\Temp\Report.xml"))
{
XmlSerializer xml = new XmlSerializer(typeof(ReportsViewModel));
ReportsViewModel reportVM = (ReportsViewModel)xml.Deserialize(sw);
reportVM.Dump();
reportVM.FromDateTimeCal.Dump();
reportVM.ToDateTimeCal.Dump();
}
It didn't work. I guess the problem is FromDateTime and ToDateTime property wasn't set.
Can I serialize and deserialize with the same class?

your FromDateTime and ToDateTime are never being assigned a value when you Deserialize..
your set inside your cal properties are not doing anything with the value passed to them.
var a = fromDateTime.Subtract(DateTime.Today).Days;
a = value;
that line is keeping the value and calculated value inside that block but never forwards the calculated value.
im going to just guess and say what you want is something like:
var a = value.Subtract(DateTime.Today).Days;
ToDateTime = a;
but then you are going to run into an issue. when you get the value of ToDateTimeCal and FromDateTimeCal, you are going to run the same calculation again, on a already calculated value. Since you are using the current date in the calculation, and you never save that date in the file - you dont have a way to reverse the value to figure out what the FromDateTime was. Unless you read the date from the file itself. It would make more sense to serialze the FromDateTime instead. But if the original date used in the calculation is not necessary, maybe you can do something like:
[XmlIgnore]
public DateTime FromDateTime
{
get { return fromDateTime; }
set
{
fromDateTime = value;
}
}
[XmlElement]
public int FromDateTimeCal
{
get
{
return fromDateTime.Subtract(DateTime.Today).Days;
}
set
{
fromDateTime = DateTime.Today.AddDays(value);
}
}

Related

Deserializing xml to list object returning null

I'm trying to deserialize xml data using xmlreader into a list object but I am getting a null back from my call. Here is a sample of my xml data...
<ExceptionLog>
<ExceptionLogData MessageCount="1" SourceDateTime="2016-02-08T09:32:41.713" MinSourceDateTime="2016-02-08T09:32:41.713" DataId="610029" MaxExceptionLogID="610029" MessageText="INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session. Session not found, missing session hash: hX7K7LONeTilw5RfGT432g==
This is expected, it can happen if the session has expired and swept away, or if the user logs out, or if its just someone trying to hack in. " MachineName="VERTEXDPORTSQL1" AppDomainName="VTMS.Windows.SalesforceServicingAgent.exe" ProcessName="VTMS.Windows.SalesforceServicingAgent" />
<ExceptionLogData MessageCount="1" SourceDateTime="2016-02-08T09:22:39.340" MinSourceDateTime="2016-02-08T09:22:39.340" DataId="610028" MaxExceptionLogID="610028" MessageText="INVALID_SESSION_ID: Invalid Session ID found in SessionHeader: Illegal Session. Session not found, missing session hash: rtZTrLk2f99iVttLoz31tg==
This is expected, it can happen if the session has expired and swept away, or if the user logs out, or if its just someone trying to hack in. " MachineName="VERTEXDPORTSQL1" AppDomainName="VTMS.Windows.SalesforceServicingAgent.exe" ProcessName="VTMS.Windows.SalesforceServicingAgent" />
</ExceptionLog>
This is the object class code that I am trying to create...
public class ExceptionLog {
public ExceptionLog() {
ExceptionLogData = new List<ExceptionLogExceptionLogData>();
}
public List<ExceptionLogExceptionLogData> ExceptionLogData { get; set; }
}
public class ExceptionLogExceptionLogData {
private DateTime _sourceDateTimeField;
private DateTime _minSourceDateTimeField;
private uint dataIdField;
private uint _maxExceptionLogIdField;
private string _messageTextField;
private string _machineNameField;
private string _appDomainNameField;
private string _processNameField;
public byte MessageCount { get; set; }
public DateTime SourceDateTime {
get {
return _sourceDateTimeField;
}
set {
_sourceDateTimeField = value;
}
}
public DateTime MinSourceDateTime {
get {
return _minSourceDateTimeField;
}
set {
_minSourceDateTimeField = value;
}
}
public uint DataId {
get {
return dataIdField;
}
set {
dataIdField = value;
}
}
public uint MaxExceptionLogID {
get {
return _maxExceptionLogIdField;
}
set {
_maxExceptionLogIdField = value;
}
}
public string MessageText {
get {
return _messageTextField;
}
set {
_messageTextField = value;
}
}
public string MachineName {
get {
return _machineNameField;
}
set {
_machineNameField = value;
}
}
public string AppDomainName {
get {
return _appDomainNameField;
}
set {
_appDomainNameField = value;
}
}
public string ProcessName {
get {
return _processNameField;
}
set {
_processNameField = value;
}
}
}
And finally here is how I am trying to deserialize the data...
using (var dataReader = sqlCommand.ExecuteXmlReader())
{
var serializer = new XmlSerializer(typeof(ExceptionLog));
var returnDataList = serializer.Deserialize(dataReader) as List<ExceptionLogExceptionLogData>;
return returnDataList;
}
What have I missed or what am I doing wrong?
I have another approach that I can use until I figure this out and that is the old fashioned way of creating my object list and programmatically populating it with my objects on the fly - not very graceful but for the time being it works.
TIA
XmlSerializer is defined of type ExceptionLog but you're then casting the result to List
var serializer = new XmlSerializer(typeof(ExceptionLog));
var returnDataList = serializer.Deserialize(dataReader) as List<ExceptionLogExceptionLogData>;
The casting should be to the type of serializer:
var returnDataList = serializer.Deserialize(dataReader) as ExceptionLog;
I didn't check all the elements but you should also mark ExceptionLogData with XmlElement attribute.
[XmlElement]
public List<ExceptionLogExceptionLogData> ExceptionLogData { get; set; }
There might be some issues with the other properties but this should address the problem in the question

Avoid expanding linked objects when serialising

I am using JSON.NET to serialize some c# objects into JSON (and then write to a file).
My two main classes are:
public class Reservoir {
private Well[] mWells;
public Well[] wells {
get { return mWells; }
set { mWells = value; }
}
}
and
public Well() {
private string mWellName;
private double mY;
private double mX;
public string wellName {
get { return mWellName; }
set { mWellName = value; }
}
public double y {
get { return mY; }
set { mY = value; }
}
public double x {
get { return mX; }
set { mX = value; }
}
private Well[] mWellCorrelations;
}
The problem is that the output looks like:
'{"wells":[{"wellName":"B-B10","y":217.04646503367468,"x":469.5776343820333,"wellCorrelations":[{"wellName":"B-B12","y":152.71005958395972,"x":459.02158140110026,"wellCorrelations":[{"wellName":"B-B13","y":475.0,"x":495.14804408905263,"wellCorrelations":[{"wellName":"B-B11","y":25.0,"x":50.0,"wellCorrelations":[]}
i.e. the associated wells of each well object are expanded as objects themselves and this becomes a serious problem of space and time when there lots of associated objects.
I suppose I would have preferred something like:
'{"wells":[{"wellName":"B-B10","y":217.04646503367468,"x":469.5776343820333,"wellCorrelations":[{"wellName":"B-B12"}], {"wellName":"B-B11","y":217.04646503367468,"x":469.5776343820333,"wellCorrelations":[{"wellName":"B-B13"}
i.e maintaining only the well name as the link (assume its unique).
Is there a way to do this with JSON.NET?
You have set
serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
but it doesn't make any difference.
You could add a new readonly property called WellCorrelations that only got the names of the well correlations, and slap a JsonIngore attribute on your mWellCorrelations, like so:
[JsonIgnore]
private Well[] mWellCorrelations;
public string[] WellCorrelations
{
get { return mWellCorrelations.Select(w => w.wellName).ToArray(); }
}
http://james.newtonking.com/projects/json/help/html/ReducingSerializedJSONSize.htm
That way, the serializer will only serialize the names of the correlated wells.

Storing entity in XML, using MVVM to read/write in WPF Application

Say I've a class (model) called Instance with Properties DatbaseHostname, AccessManagerHostname, DatabaseUsername and DatabasePassword
public class Instance
{
private string _DatabaseHostname;
public string DatabaseHostname
{
get { return _DatabaseHostname; }
set { _DatabaseHostname = value; }
}
private string _AccessManagerHostname;
public string AccessManagerHostname
{
get { return _AccessManagerHostname; }
set { _AccessManagerHostname = value; }
}
private string _DatabaseUsername;
public string DatabaseUsername
{
get { return _DatabaseUsername; }
set { _DatabaseUsername = value; }
}
private string _DatabasePassword;
public string DatabasePassword
{
get { return _DatabasePassword; }
set { _DatabasePassword = value; }
}
}
I'm looking for a sample code to read/write this Model to XML (preferably linq2XML) => storing 1:n instances in XML.
i can manage the the view and ViewModel part myself, although it would be nice if someone had a sample of that part too..
Well, you could use Linq to XML, but your class is a perfect candidate for XML Serialization, which is much simpler IMHO :
var list = new List<Instance>();
...
// Serialization
var xs = new XmlSerializer(typeof(List<Instance>));
using (var writer = XmlWriter.Create(filename))
{
xs.Serialize(writer, list);
}
...
// Deserialization
using (var reader = XmlReader.Create(filename))
{
list = xs.Deserialize(reader) as List<Instance>;
}
Not sure how you want your xml structured, but this should work:
List<Instance> instances = new List<Instance>();
// Get your instances here...
var baseNode = new XElement("Instances");
instances.ForEach(instance => baseNode.Add("Instance",
new XAttribute("DatabaseHostname", instance.DatabaseHostname),
new XAttribute("AccessManagerHostname", instance.AccessManagerHostname),
new XAttribute("DatabaseUsername", instance.DatabaseUsername),
new XAttribute("DatabasePassword", instance.DatabasePassword)));

Serializing a DataType="time" field using XmlSerializer

I'm getting an odd result when serializing a DateTime field using XmlSerializer.
I have the following class:
public class RecordExample
{
[XmlElement("TheTime", DataType = "time")]
public DateTime TheTime { get; set; }
[XmlElement("TheDate", DataType = "date")]
public DateTime TheDate { get; set; }
public static bool Serialize(
Stream stream, object obj, Type objType, Encoding encoding)
{
try
{
var settings = new XmlWriterSettings { Encoding = encoding };
using (var writer = XmlWriter.Create(stream, settings))
{
var xmlSerializer = new XmlSerializer(objType);
if (writer != null) xmlSerializer.Serialize(writer, obj);
}
return true;
}
catch (Exception)
{
return false;
}
}
}
When i call the use the XmlSerializer with the following testing code:
var obj = new RecordExample
{
TheDate = DateTime.Now.Date,
TheTime = new DateTime(0001, 1, 1, 12, 00, 00)
};
var ms = new MemoryStream();
RecordExample.Serialize(ms, obj, typeof(RecordExample), Encoding.UTF8);
txtSource2.Text = Encoding.UTF8.GetString(ms.ToArray());
I get some strange results, here's the xml that is produced:
<?xml version="1.0" encoding="utf-8"?>
<RecordExample
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<TheTime>12:00:00.0000000+00:00</TheTime>
<TheDate>2010-03-08</TheDate>
</RecordExample>
Any idea's how i can get the "TheTime" element to contain a time which looks more like this:
<TheTime>12:00:00.0Z</TheTime>
...as that's what i was expecting?
Thanks
Dave
I've had different issues with this myself... however I was attempting to serialize a TimeSpan object. The solution was to have two properties, one that held the TimeSpan, and one that was a string representation of the TimeSpan which got Serialized. Here was the pattern:
[XmlIgnore]
public TimeSpan ScheduledTime
{
get;
set;
}
[XmlElement("ScheduledTime", DataType="duration")]
public string XmlScheduledTime
{
get { return XmlConvert.ToString(ScheduledTime); }
set { ScheduledTime = XmlConvert.ToTimeSpan(value); }
}
However, with this code, the time is printed out in the following format:
<ScheduledTime>PT23H30M</ScheduledTime>
The W3C definition of duration is here which explains it.
take a look at this question Serializing DateTime to time without milliseconds and gmt
Expanding on the comment I made on one of the others answers.
public class RecordExample : IXmlSerializable
{
public DateTime TheTime { get; set; }
public DateTime TheDate { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
// TODO : Deserialization logic here
}
public void WriteXml(XmlWriter writer)
{
writer.WriteElementString(
"date",
this.TheDate.ToString("yyyy-MM-dd"));
writer.WriteElementString(
"time",
this.TheTime.ToString("hh:mm:ss.fK"));
}
}
Serializing like this:
var rc = new RecordExample()
{
TheDate = DateTime.Today,
TheTime = DateTime.UtcNow
};
var serializer = new XmlSerializer(typeof(RecordExample));
var ms = new MemoryStream();
serializer.Serialize(ms, rc);
ms.Seek(0, SeekOrigin.Begin);
Console.WriteLine(new StreamReader(ms).ReadToEnd());
Output example:
<?xml version="1.0"?>
<RecordExample>
<date>2010-03-08</date>
<time>04:26:16.1Z</time>
</RecordExample>
I concur with the other answers (I was not done writing when they popped up). it does not look like it is possible, in a direct way.
A look at the source with Reflector shows that a time value ends up being converted to a string with the System.Xml.XmlConvert.ToString, that has a hard-coded format of:
HH:mm:ss.fffffffzzzzzz
So having two properties, the real one being [XmlIgnore] and a string that you build yourself is a good way to go.

Suppress xsi:nil but still show Empty Element when Serializing in .Net

I have a c# class that has 20+ string properties. I set about a fourth of those to an actual value. I would like to serialize the class and get an output of
<EmptyAttribute></EmptyAttribute>
for a property
public string EmptyAttribute {get;set;}
I do not want the output to be
<EmptyAttribute xsi:nil="true"></EmptyAttribute>
I am using the following class
public class XmlTextWriterFull : XmlTextWriter
{
public XmlTextWriterFull(string filename) : base(filename,Encoding.UTF8) { }
public override void WriteEndElement()
{
base.WriteFullEndElement();
base.WriteRaw(Environment.NewLine);
}
}
so that I can get the full tags. I just don't know how to get rid of the xsi:nil.
The way to have the XmlSerializer serialize a property without adding the xsi:nil="true" attribute is shown below:
[XmlRoot("MyClassWithNullableProp", Namespace="urn:myNamespace", IsNullable = false)]
public class MyClassWithNullableProp
{
public MyClassWithNullableProp( )
{
this._namespaces = new XmlSerializerNamespaces(new XmlQualifiedName[] {
new XmlQualifiedName(string.Empty, "urn:myNamespace") // Default Namespace
});
}
[XmlElement("Property1", Namespace="urn:myNamespace", IsNullable = false)]
public string Property1
{
get
{
// To make sure that no element is generated, even when the value of the
// property is an empty string, return null.
return string.IsNullOrEmpty(this._property1) ? null : this._property1;
}
set { this._property1 = value; }
}
private string _property1;
// To do the same for value types, you need a "helper property, as demonstrated below.
// First, the regular property.
[XmlIgnore] // The serializer won't serialize this property properly.
public int? MyNullableInt
{
get { return this._myNullableInt; }
set { this._myNullableInt = value; }
}
private int? _myNullableInt;
// And now the helper property that the serializer will use to serialize it.
[XmlElement("MyNullableInt", Namespace="urn:myNamespace", IsNullable = false)]
public string XmlMyNullableInt
{
get
{
return this._myNullableInt.HasValue?
this._myNullableInt.Value.ToString() : null;
}
set { this._myNullableInt = int.Parse(value); } // You should do more error checking...
}
// Now, a string property where you want an empty element to be displayed, but no
// xsi:nil.
[XmlElement("MyEmptyString", Namespace="urn:myNamespace", IsNullable = false)]
public string MyEmptyString
{
get
{
return string.IsNullOrEmpty(this._myEmptyString)?
string.Empty : this._myEmptyString;
}
set { this._myEmptyString = value; }
}
private string _myEmptyString;
// Now, a value type property for which you want an empty tag, and not, say, 0, or
// whatever default value the framework gives the type.
[XmlIgnore]
public float? MyEmptyNullableFloat
{
get { return this._myEmptyNullableFloat; }
set { this._myEmptyNullableFloat = value; }
}
private float? _myEmptyNullableFloat;
// The helper property for serialization.
public string XmlMyEmptyNullableFloat
{
get
{
return this._myEmptyNullableFloat.HasValue ?
this._myEmptyNullableFloat.Value.ToString() : string.Empty;
}
set
{
if (!string.IsNullOrEmpty(value))
this._myEmptyNullableFloat = float.Parse(value);
}
}
[XmlNamespaceDeclarations]
public XmlSerializerNamespaces Namespaces
{
get { return this._namespaces; }
}
private XmlSerializerNamespaces _namespaces;
}
Now, instantiate this class and serialize it.
// I just wanted to show explicitly setting all the properties to null...
MyClassWithNullableProp myClass = new MyClassWithNullableProp( ) {
Property1 = null,
MyNullableInt = null,
MyEmptyString = null,
MyEmptyNullableFloat = null
};
// Serialize it.
// You'll need to setup some backing store for the text writer below...
// a file, memory stream, something...
XmlTextWriter writer = XmlTextWriter(...) // Instantiate a text writer.
XmlSerializer xs = new XmlSerializer(typeof(MyClassWithNullableProp),
new XmlRootAttribute("MyClassWithNullableProp") {
Namespace="urn:myNamespace",
IsNullable = false
}
);
xs.Serialize(writer, myClass, myClass.Namespaces);
After retrieving the contents of the XmlTextWriter, you should have the following output:
<MyClassWithNullableProp>
<MyEmptyString />
<MyEmptyNullableFloat />
</MyClassWithNullableProp>
I hope this clearly demonstrates how the built-in .NET Framework XmlSerializer can be used to serialize properties to an empty element, even when the property value is null (or some other value you don't want to serialize). In addition, I have shown how you can make sure that null properties are not serialized at all. One thing to note, if you apply an XmlElementAttribute and set the IsNullable property of that attribute to true, then that property will serialize with the xsi:nil attribute when the property is null (unless overriden somewhere else).
I was actually able to figure this out. I know its a bit of a hack in some ways but this is how I got it to work
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(header.GetType());
XmlTextWriterFull writer = new XmlTextWriterFull(FilePath);
x.Serialize(writer, header);
writer.Flush();
writer.BaseStream.Dispose();
string xml = File.ReadAllText(FilePath);
xml = xml.Replace(" xsi:nil=\"true\"", "");
File.WriteAllText(FilePath, xml);
Hope this helps someone else out

Categories

Resources