After deserialization set property in class that wasn't in dataset - c#

The class I made exists of a bunch of properties. Most of the properties are included in the received dataset. After the deserialization of the dataset, I retreive a list of objects. So some of the properties where ignored by using 'jsonignore'.
In the objects I have a property for example called 'foo'. I want this property to be set before I continue.
A possible solution could be looping through the list and setting the property. --> but this seems like double work, because all items were just looped in the deserialization of json.net. Is it possible to override the deserialization so the property I want is set after all other properties (that were in the dataset)?
Can someone get me started? Thanks in advance.

There are several options to achieve what you want:
set the property foo in the class'es constructor,
use a CustomCreationConverter<T> to instantiate the class and set foo; there's a good example in Json.NET's documentation here,
use a [OnDeserialized] callback method; again, there's an example here.

Related

Json.Net Class hierarchy with ObservableCollection and INotifyPropertyChange gets serialized but not deserialized

I find myself a bit lost on this one. I honestly can't see the error if it's just a class structure doesn't match JSON error. But I doubt it since it's the very same class structure I'm using to create the JSON.
If anyone can point me in the right direction, I'd be most greateful.
I've created a dotnetfiddle to avoid clutching the question with huge pieces of code. Here's the link: Fiddle
I generate that JSON with a console application that gets info on the DB schema. I use a common project with all the entities defined in it to load the data in memory and then generate the JSON from that structure. Then I use the same project with the same entities on another application to compare another DB schema to the JSON log. That application is unable to deserialize the JSON. Tried to provide a minimal example with a single class and as you can see on the fiddle...that doesn't deserialize either.
It is my understanding that ObservableCollections should in fact serialize and deserialize without issues, and that INotifyPropertyChange should not cause issues (as long as you're not trying to fire an event with a null reference). So...anyone has any idea what's going on here?.
EDIT: Forgot to mention. Notice how only the base type string gets deserialized...so it IS running some deserialization, just not of classes like ObservableCollection or user classes. Maybe that helps somehow to pinpoint the issue.
EDIT2: Added a trace writer and the JSON.Net trace is detecting the right type for the objects, so I'm guessing the issue is on converting types or initializing some of the types
The problem is in how your property getters work combined with the default ObjectCreationHandling setting in Json.Net. Allow me to explain:
By default, if a reference property has an existing (non-null) value during deserialization, Json.Net tries to reuse the existing instance and populate it instead of creating a new instance. To find out whether the property has a value, Json.Net calls the getter. In your case, the getter returns a new instance when the backing field is null, but, critically, it does not set the backing field to the new instance:
get { return _header ?? new StoredProcedureDataHeader(); }
Json.Net then populates the new instance. Because the backing field was never set to the new instance, that instance ultimately gets thrown away. Json.Net never calls your setter because it assumes that your object already has a reference to the new instance, since it got that instance from the getter. Then, when you next call that getter after deserialization, you get a new, empty instance back instead of what you were expecting.
There are two ways to fix the problem:
Change your getters to set the backing field whenever a new instance is created, for example:
get
{
if (_header == null)
{
_header = new StoredProcedureDataHeader();
}
return _header;
}
OR
Change the ObjectCreationHandling setting to Replace to force Json.Net to always create new instances when deserializing. Json.Net will then call the setter and not the getter, which I think is what you want.
var settings = new JsonSerializerSettings
{
ObjectCreationHandling = ObjectCreationHandling.Replace
};
var data = JsonConvert.DeserializeObject<StoredProcedureData>(json, settings);
In your case, I would actually recommend that you apply both fixes. If you don't fix your getters (option 1), you could run into a similar issue elsewhere in your code. For example, you might have something like this:
var data = new StoredProcedureData();
data.Header.SPName = "foo";
if (data.Header.SPName == "foo")
{
Console.WriteLine("foo");
}
else
{
Console.WriteLine("oops");
}
Guess which value will be printed?
And option 2 will protect against possibly unexpected results if you happen to have initialized a collection somewhere to have a default set of values. For example, if you had something like this:
public StoredProcedureData()
{
_funcRef = new ObservableCollection<string>();
_funcRef.Add("Initialize");
}
then when you deserialize, you will get the default values plus the values from the JSON, which is probably not what you want. Setting ObjectCreationHandling to Replace will ensure that you will end up with just the values which were deserialized from the JSON.

set base class property to appear first in json output for web api 2

I have a BaseDTO c# class which just has one property of type boolean called Success
I then have a derived class which has some extra properties.
When this derived class gets outputted in JSON in web api the Success property appears # the bottom.
I would like it to appear first.
Is there any attribute i can set on the property to allow this?
Thanks
It doesn't matter what order they are in:
An object is an unordered set of name/value pairs.
- http://json.org/
If you're requiring an order to the properties, then you are no longer dealing with true JSON and can't expect existing libraries to accommodate this requirement out the box.
Having said that, JSON.NET allows you to implement a IContractResolver which you could create to search for a custom attribute and favour that. More details can be found in this Stack Overflow answer.
Actually this answer on the same question shows an existing attribute you can use instead of the above.

Object to Object Mapping

I have a RESTful service which returns JSON that I am deserialising into classes in c#.
I need to map some of the properties from the deserialised object model into properties in a different class.
However, I would like to do this through an (xml?) config file which can specify the from/to property names, so that mappings can be changed without recompiling code.
For example:
objectA.Name.FirstName = objectB.FirstName
objectA.Name.LastName = objectB.LastName
What is the best way to do this?
You could let something like AutoMapper do the mapping for you.
There are samples in the source code and configuration options in the wiki.
If you want it to to be based on late binding you can use reflection to dynamically execute the property assignments based on xml definitions.
You can see some examples in this asnwer: Set object property using reflection

Populating A New Object With Existing Objects Data

I have a service that is returning a custom object called "UserSettings" In my application I want to add more properties to the "UserSettings" object so I created a new object called "MyUserSettings" that inherits from "UserSettings" now I want to populate my new object with the existing data held in "UserSettings" and the new data I have for my new properties. I do not want to have to map each property one by one to the same property in the new object like this..
_MyUserSettings.Name=_UserSettings.Name;
Is there a way or better approach to what I am doing to populate ALL the properties of the existing object into my new object in one shot??
Yes, you can use Copy Constructor pattern. It would give you an other benefit - you do not need public property setters so object becomes immutable.
public MyUserSettings(UserSettings baseSettings)
{
// TODO: set all properties
}
Unfortunately this is the only way, however, the specific mechanism can change. There are a numerous ways (not listing them all):
Copy constructor, that takes an item and does this manual copying of fields across.
Use reflection to have a more generic mechanism of achieving the same.
Use something like AutoMapper.
They all boil down to pretty much doing the same thing.
If the UserSettings is actually a MyUserSettings then you can simply cast it:
var mySettings = (MyUserSettings)settings;
However, this will fail if UserSettings is really UserSettings.

XML Serialization and empty collections

I have a a property defined as:
[XmlArray("delete", IsNullable = true)]
[XmlArrayItem("contact", typeof(ContactEvent)),
XmlArrayItem("sms", typeof(SmsEvent))]
public List<Event> Delete { get; set; }
If the List<> Delete has no items
<delete />
is emitted. If the List<> Delete is set to null
<delete xsi:nil="true" />
is emitted. Is there a way using attributes to get the delete element not to be emitted if the collection has no items?
Greg - Perfect thanks, I didn't even read the IsNullable documentation just assumed it was signalling it as not required.
Rob Cooper - I was trying to avoid ISerializable, but Gregs suggestion works. I did run into the problem you outlined in (1), I broke a bunch of code by just returning null if the collection was zero length. To get around this I created a EventsBuilder class (the class I am serializing is called Events) that managed all the lifetime/creation of the underlying objects of the Events class that spits our Events classes for serialization.
I've had the same issue where I did not want an element outputted if the field is empty or 0.
The XML outputted could not use xsi:null="true" (by design).
I've read somewhere that if you include a property of type bool with the same name as the field you want to control but appended with 'Specified', the XMLSerializer will check the return value of this property to determine if the corresponding field should be included.
To achieve this without implementing IXMLSerializer:
public List<Event> Delete { get; set; }
[XMLIgnore]
public bool DeleteSpecified
{
get
{
bool isRendered = false;
if (Delete != null)
{
isRendered = (Delete.Count > 0);
}
return isRendered;
}
set
{
}
}
If you set IsNullable=false or just remove it (it is false by default), then the "delete" element will not be emitted. This will work only if the collection equals to null.
My guess is that there is a confusion between "nullability" in terms of .NET, and the one related to nullable elements in XML -- those that are marked by xml:nil attribute. XmlArrayAttribute.IsNullable property controls the latter.
First off, I would say ask yourself "What is Serialization?".
The XmlSerializer is doing exactly what it is supposed to be doing, persisting the current state of the object to XML. Now, I am not sure why the current behaviour is not "right" for you, since if you have initialized the List, then it is initialized.
I think you have three options here:
Add code to the Getter to return null if the collection has 0 items. This may mess up other code you have though.
Implement the IXmlSerializable interface and do all the work yourself.
If this is a common process, then you may want to look at my question "XML Serialization and Inherited Types" - Yes, I know it deals with another issue, but it shows you how to create a generic intermediary serialization class that can then be "bolted on" to allow a serilization process to be encapsulated. You could create a similar class to deal with overriding the default process for null/zero-item collections.
I hope this helps.
You could always implement IXmlSerializer and perform the serialization manually.
See http://www.codeproject.com/KB/cs/IXmlSerializable.aspx for an example.

Categories