xml serialize crash when calling serialize mehod - c#

After lot of debugging I came to know exact cause of the crash. Firstly
Test 1:
I am loading an XML file from drive deserializing it against a MOTORCLASS and using the MOTORCLASS properties, later serializing back again to XML It works fine.
Test 2:
I have a Datatable and all its rows are mapped to the MOTORCLASS properties and now when serializing to XML a crash occurs..
When looking into MOTORCLASS property
`public object APPOINTMENT
{
get
{
return this.aPPOINTMENTField;
}
set
{
this.aPPOINTMENTField = value;
}
}`
On run time the TEST 1 sets APPOINTMENT as Xmlnode whereas
TEST 2 assign APPOINTMENT as Datetime.
I think if I convert Datetime to Xmlnode than it should solve the problem. But not sure how to achieve it. I have tried
[System.Xml.Serialization.XmlElementAttribute("APPOINTMENT")].
But it still Datetime. Can anyone shed some light here.
TEST 1:
TEST 2:

The problem isn't the type of value itself that happens to be assigned to the property; It's the XmlSerializer that needs to know beforehand what type it can expect.
If APPOINTMENT should always be a DateTime, just change the property type to DateTime. Besides fixing the xml serialization problem, this will also prevent bugs and improve your application's performance.
If APPOINTMENT can be different things, you can supply type candidates to the serializer:
[XmlElement("AppointmentAsDateTime", Type = typeof(DateTime))]
[XmlElement("AppointmentAsOtherType", Type = typeof(OtherType))]
public object APPOINTMENT { get; set; }
This allows the serializer to be able to deal with situations where APPOINTMENT is a DateTime or an OtherType.
(Credit to that solution goes to Marc Gravell: How to serialize property of type Object with XmlSerializer)

Related

Serialize but not deserialize fields/properties in XML, JSON and (particularly) YAML?

I have a set of objects that contain fields & properties that need to be inspectable in the output of serialization but not read back in when deserialized.
This is purely for debugging/confirmation purposes. We are creating hundreds of files and I want to spot check that serialization is occurring correctly by adding supplementary information. I do not want this supplementary information to be read in during deserialization - it's impossible to do so in fact.
I also need to do this with equal facility across different serialization formats, so we can assess which one is working best. I have a generic serialization approach where the desired format is passed in as an argument, so don't want anything too messy or intricate for each different format.
I've hunted around and found various things on related topics - mostly to do with the opposite: not writing certain fields during serialization. What's out there seems to be quite complicated and at times hacky.
Is it possible to serialize an object differently to deserializing it using Json.Net?
JsonConvert .NET Serialize/Deserialize Read Only
Serialize Property, but Do Not Deserialize Property in Json.Net
Also it appears any approach is inconsistent between serialization formats. i.e. unlike the [*Ignore] attributes, there are no [*SerializeOnly] attributes (where * = JSON, XML, YAML).
Is there an easy way to do this across these serialization formats? Is there a single family of attributes that can help? Or is it idiosyncratic and hacky in each case?
I have tested and applied this only to XML serialization, but it works for me:
When I want a property to be serialized, but not read back, I just declare an empty setter.
public String VersionOfApplicationThatHasWrittenThisFile
{
get
{
return "1.0";
}
set
{
// Leave empty
}
}

How do I retrieve a CimInstance property of a certain type?

So, I have been searching for a while now, and I can't seem to find the answer to what seems to be (at least, to me) a simple, foundational C# question.
To set it up, I am putting together a C# GUI program that leverages CIM classes from remote machines to retrieve data about said machine, which will be used to determine it's current "Status" from an End-User Support Technician's point of view.
I have had no problems with setting up the CIM session to the remote machine, and retrieving the data I requested by querying for instances. The problem I have run into is that I can't seem to figure out how to retrieve a value from a property from one of these instances with the value returned being of a certain expected type. Without actually running the query before the code is compiled and executed, the IDE (Visual Studio 2017) assumes the return value to be of the super-type "Object" (Please forgive any vernacular problems).
Here is the Code I am using for reference:
public class DispRecord
{
//declare properties for record object
public string Hostname;
public string Status;
public string User;
public string NTLogin;
public string LockTime;
public string LockDuration;
public string LogonTime;
public string LogonDuration;
public string LastRestart;
public string PwrOnDuration;
}
I have a constructed custom class object that contains the properties I am retrieving and calculating.
This custom object is then passed to a function that is performing the query and assigning the value to the properties. My method class has several methods, but here is the one that currently is the sticking point:
//method for gathering CIM data
public static DispRecord QueryCIMData (DispRecord Record)
{
//use cimsession to remote host
using (CimSession Session = CimSession.Create(Record.Hostname, new DComSessionOptions()))
{
//declare queries
string PwrQuery = "Select LastBootUpTime from CIM_OperatingSystem";
//string ProcQuery = "Select CreationDate,Caption from CIM_Process where Name='explorer.exe' or Name='logonui.exe'";
//declare namespace
string Namespace = #"root\cimv2";
//perform PwrQuery and retrieve lastbootuptime
IEnumerable<CimInstance> Results = Session.QueryInstances(Namespace, "WQL", PwrQuery);
DateTime LastBootUpTime = DateTime.Parse(Results.First().CimInstanceProperties["LastBootUpTime"].Value.ToString());
//add PwrOnDuration and LastRestart to Record
Record.LastRestart = LastBootUpTime.ToString();
Record.PwrOnDuration = (DateTime.Now - LastBootUpTime).ToString(#"dd\/hh\:mm\:ss");
}
//return changed record object
return Record;
}
What you see above does work, but I feel like the code gyrations necessary to achieve the proper output are a bit ridiculous and I feel that there must be another, possibly easier or cleaner, way to achieve my desired output. Surely there is a better way to retrieve the DateTime object I am expecting than to retrieve a property value as a string constructed from a DateTime object, that is then parsed into a new Datetime object, especially considering that I am turning around and converting it back into a string to insert into the record.
Ideally, I would like to do something like this, but I'm not sure how to achieve it:
DateTime LastBootUpTime = Results.First().CimInstanceProperties["LastBootUpTime"].Value;
When I attempt the above, the Compiler will throw an exception stating that it cannot implicitly convert a value of type 'Object' to type 'DateTime'
Essentially, since the query isn't performed until runtime, the returned CIM instance properties are all just expected as Objects, instead of their expected output based on the class that the instance is built from (Which in this case, a 'DateTime' object is expected as the value of the "LastBootUpTime" property).
The Code doesn't know what is coming out of the egg before it hatches, even if MSDN does.
Can anyone help me with this seeming easy problem?
Okay, after some trial and error, I found the easy solution I was sure existed.
To work with the compiler, a call to the Convert.ToDateTime() method allowed the code to compile and no exception was thrown at run-time.
//perform PwrQuery and retrieve lastbootuptime
IEnumerable<CimInstance> Results = Session.QueryInstances(Namespace, "WQL", PwrQuery);
DateTime LastBootUpTime = Convert.ToDateTime(Results.First().CimInstanceProperties["LastBootUpTime"].Value);
//add PwrOnDuration and LastRestart to Record
Record.LastRestart = LastBootUpTime.ToString();
Record.PwrOnDuration = (DateTime.Now - LastBootUpTime).ToString(#"dd\/hh\:mm\:ss");
The only cost was a few "DOH!"s :)

Serialize a decimal to a human readable currency format

I am using json.net library to serialize an object which has a decimal value that represents a cost. When serializing, I want the json to look something like '$400,000' instead of '400000.0'.
Is there a way that I can accomplish this in an easy and efficient way? This object contains many other secondary objects and subsequent properties.
The application will be used locally and the specs say that the output should be in human readable format. Culture variance isn't of any importance in this context.
There's no easy way to perform this since you can't work around a fact that serializer is directly accessing your properties.
If you need a formatted JSON output I would recommend writing a helper class that wraps the class you want to expose. Unfortunately I've done this once for some XML report and really the easiest way went something like this:
class PersonXml
{
Person _person;
void PersonXml(Person person) { _person = person; }
string Age { get { return _person.Age + " years"; } }
}
This is just a simple example I wrote on the fly but the principle is always the same. Even if some advanced JSON serializer offered me ways to format my output, I'd really keep this concept out of my main objects in a separate file with separate helper classes.
Again this isn't quite the solution, in my opinion it should never come to this but if it does, this is the lesser of the evils in my experience.
Also, just note that if you reference the class in your property getters there's a danger of null reference.
As D Stanley suggested, I changed the field type to string from decimal as data in it was only being read and not used for data manipulation.

Override Json.net behaviour to take more attributes into account

I need to use Json.net to serialize my object to the client side, which it does brilliantly. However I want to extend it's behaviour to use more attributes during serialization, specifically attributes from the Data Annotations namespace.
Here's one example:
I need to output a date, and rather than send the date to the client side, and format it there, I want to control the format of the output on the server side.
[DisplayFormat(DataFormatString = "{0:d}")]
public DateTime BirthDate { get;set;}
I looked at using a converter to process this, but at the stage a converter is executed, it has no reference back to the member information of the declaring property, so I wouldn't be able to examine the attribute. I'm assuming I would need to override/extend the IContractResolver behaviour, but there is very little documentation on how all the pieces fit, like JsonContract etc.
I just need some pointers as to how the whole thing hangs together, and I'll work the rest out. Thanks in advance to anyone kind enough to assist.

Serializing Object - Replacing Values

I've got a collection of around 20,000 objects that need to get persisted to my database. Now, instead of doing 20,000 insert statements, I want to pass all the records in using an XML parameter.
As far as serializing the object and passing it into the procedure goes, I'm all set. However, I'm wondering if anyone has an elegant way to do the following:
In our C# code base; we have some static values that represent a NULL when saved to the database. For example, if an integer equals -1, or a DateTime equals DateTime.MinValue; save NULL. We have our own little custom implementation that handles this for us when saving objects.
Is there any way I can do something similar to this when performing the XML serialization? Right now it's outputting -1 and DateTime.MinValue in the XML. I do have an extension method (IsNull()) that will return true/false if the value being saved is the null default value.
Any suggestions? Tips/Tricks?
The XmlSerializer understands a number of different attributes; one of them is DefaultValueAttribute.
When included, the XmlSerializer will only serialize the value check if the actual value differs from the default, so all you should need is:
[DefaultValue(-1)]
public int SomeProperty
{get;set;}
Also, if you haven't considered it, take a look at the SqlBulkCopy class, which is a highly-performant approach to sending a large number of records to SQL Server.
You can implement IXmlSerializable to control an object's XML serialization. In particular, implement WriteXml to substitute blank or xsi:null values (however you want to handle this) for those properties/fields that contain your null signifier values.

Categories

Resources