Json.Net Deserialize to JToken with Custom Contract Resolver - c#

JSON.Net works well if I give a custom generic type to Deserialize method. But, when I change the output object type as JToken, it does not finish the deserialization process through given serializer setting.
I must notify the deserializer that put this property into that model property (e.g. => the property will be deserialized: "date_add" will be: "DateAdd" in the model). I do not want to use attributes.
When I debug my code below, CustomContractResolver does not work even I put the breakpoint into there.
Here is my code:
var model = JsonConvert.DeserializeObject<JToken>(content,
new JsonSerializerSettings() {ContractResolver = new CustomContractResolver()});

Related

Using Newtonsoft.Json.JsonConverter in a multi-threaded-environment

Throughout my project I have a singleton service class that takes care of (de)serializing, with something like this:
_setting = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Objects,
Converters = new List<JsonConverter>() { new MyConverter() },
TraceWriter = new Iov.Common.Json.TraceWriter(),
Formatting = Formatting.Indented,
SerializationBinder = binder,
DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate,
};
The service will be used in a multi-threaded environment, i.e. several (de)serializing tasks will - at the same time - use the above JsonSerializerSettings with my custom JsonConverter.
Up to now the converter has been stateless, but for deserializing I'm considering tracking the state, i.e. current position within the JSON object, child/parent-relationships. The converter would need to store/cache its results (basically in the ReadJson override) in some kind of stack/list.
All (de)serialize calls are wrapped in the mentioned service's methods, so I could easily implement using a new instance of the JsonSerializerSettings with my custom JsonConverter for each call.
Assuming my initial assumption is correct that the JsonConverter is thread-agnostic and therefore multithreading-safe as long as its stateless, my question is: can I rely on the JsonConverter to always deserialize objects in the same order?
I know that the order in which members are populated is not defined (as the order in a Dictionary is not), but will it always deserialize "from leaf to branch"?

Serialization of ArgumentNullException to Json

When serializing a System.ArgumentNullException to JSON using JSON.NET, part of the message appears lost:
var json = JsonConvert.SerializeObject(new ArgumentNullException("argument", "Some Message"));
returns:
{
"ClassName":"System.ArgumentNullException",
"Message":"Some Message",
"Data":null,
"InnerException":null,
"HelpURL":null,
"StackTraceString":null,
"RemoteStackTraceString":null,
"RemoteStackIndex":0,
"ExceptionMethod":null,
"HResult":-2147467261,
"Source":null,
"WatsonBuckets":null
}
I expected the Message token to be:
"Some Message\r\nParameter name: argument"
As noted by codefuller, the ArgumentNullException implements ISerializable and is the culprit. I can disable this by using custom JsonSerializerSettings.
However, the application needs to serialize any objects, including objects with an ArgumentNullException property. I'd prefer to avoid ignoring ISerialiable unless it presents a problem.
Both of my solutions include a custom JsonConverter.
Solution 1: Centralized JsonSerializer
Create a static list of JsonConverters to add to JsonSerializer.Converters
Include an ExceptionConverter that handles ArgumentNullException explicitly
Everywhere I need to serialize, ensure my JsonSerializer includes these converters
Cons: other developers must rigorously ensure they are including these converters with any serialization they do.
Solution 2: Override ArgumentNullException
I can create a CustomArgumentNullException class, and tag it with a JsonConvert attribute to leverage my custom converter.
Cons: other developers must rigorously ensure they are raising a CustomArgumentNullException instead of an ArgumentNullExcpetion.
Wished-for Solution
I'd love to somehow tag the existing ArgumentNullException with a JsonConverter attribute pointing to my custom converter. Is there some way to achieve this in the Json.NET code base?
Exception classes implement ISerializable interface. By the default for such objects Json.Net uses ISerializable.GetObjectData() method for data serialization. In other words ArgumentNullException class controls by itself how its data will be serialized. And somewhere inside it has a logic that serializes only actual message that was passed to constructor without Parameter name: argument part.
You could change this Json.Net behavior and avoid using of GetObjectData() with following JsonSerializerSettings:
var settings = new JsonSerializerSettings()
{
ContractResolver = new DefaultContractResolver()
{
IgnoreSerializableInterface = true,
},
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var json = JsonConvert.SerializeObject(new ArgumentNullException("argument", "Some Message"), settings);
However in this case set of serialized fields will differ from original json. Check whether it actually suits your needs.

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.

JSon.Net how to have $type only for deserialization

I used the $type properties in Json for the deserialization of inherited objects (to choose the correct object type in which to deserialize at runtime)
I do this using :
config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings{ TypeNameHandling = TypeNameHandling.Objects}
this line is in the WebApiConfig file.
It works fine but I can't figure out how to restrict the $type only to the webservices who actually needs it (I only need it for one PUT and one POST).
The $type is messing up the API results for the other webservices and I can't find some TypeNameHandling configuration nor some serialization option to avoid this.
Does anyone knows how to do that?
Cheers!
To enable type name handling on a nested object, you can attach [JsonProperty(ItemTypeNameHandling = TypeNameHandling.Objects)] to the containing property, like so:
public class RootObject
{
[JsonProperty(ItemTypeNameHandling = TypeNameHandling.Objects)]
public object Data { get; set; }
}
There's no builtin way to enable type name handling on a specific type, and so there's no builtin way to enable type name handling on the root object. Instead, you could use the EnableJsonTypeNameHandlingConverter from SignalR Typenamehandling if you need to do this.
Thanks for the help dbc. I had other issues during deserialization (using a OData.Delta object and the solution you proposed didn't actually fit completely the need.
I overcame the issue thanks to this post : Custom Json.NET serializer settings per type
to have the $type customization only for a few webservices.

Deserialize JSON to C# collection

I am using Newtonsoft.Json to serialize/deserialize my C# object to/from JSON.
My C# object has a property of following type:
List<BaseClass> objects { get; set; }
This collection holds different child objects (e.g. - ChildClass1, ChildClass2).
Serializing to JSON works fine but while deserializing it creates objects of BaseClass in collection (which is obvious :)).
Is there a way I can create concrete child objects while deserializing?
I tried creating a custom converter by implementing CustomCreationConverter<BaseClass>. But the problem is overridden Create method gives me just the type and based on that I cannot decide which object to return (ChildClass1 or ChildClass2)
My JSON string has a Type property by which I can identify the child object to create.
Any help is highly appreciated.
You can use the TypeNameHandling option:
var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto }
JsonConvert.SerializeObject(myObject, Formatting.Indented, settings );
The TypeNameHandling option "Auto" ensures that type names are included in the serialized JSON
for subclasses. But watch out: these names become invalid when the classes or their namespaces are renamed!

Categories