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"?
Related
I have a project that needs to monitor a number of collections within a number of cosmosDB's with the CosmosDB Change Feed.
The signature for the ChangeFeedObserver is pretty explicit, to where I'm not clear on how I can pass in the object type that the ComosDb.Document (in json format) represents.
public Task ProcessChangesAsync(IChangeFeedObserverContext context, IReadOnlyList<Document> deltas, CancellationToken cancellationToken)
due to this, I have a series of Observers with only a single word thats different. The name of the class that gets passed to processing.
DocumentObserverHelper.Processing<MyType>(context, deltas, cancellationToken);
With the type, my helper is able to deserialize and process the document. Though now I have a number of observer classes.
eg:
MyType1Observer.cs, MyType2Observer.cs, MyType3Observer.cs, MyType4Observer.cs
All classes share the same base class, so I've been trying to deserialize them with a binder of types, but that from what I can tell requires a property naming the type.
JsonSerializerSettings jsettings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple,
SerializationBinder = this.knownTypesBinder,
};
BaseCosmosDBDocument baseCosmosDBDocument = (BaseCosmosDBDocument)JsonConvert.DeserializeObject(payload, jsettings);
This of course results in an exception of not being able to deserialize JsonObject to BaseCosmosDbDocument (or it's derived classes)
I'm looking to use a single Observer Class that can either be instantiate with the target class type or able to determine the target class type
Unable to figure this out, thinking about it, there's only an implicit contract between the observer jsons and the adls processing of those jsons. As a result I used a regex expression to isolate the Collection Name from the ChangeFeed Context as the data type signal. That signal was then used to route the files accordingly for processing
Regex rx = new Regex(#"\b(\w+$)");
var observerCollection = rx.Match(context.FeedResponse.ContentLocation);
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.
This project I'm working with used to have a new DbContext created per each repository method (which meant that every request had an arbitrary number of dbcontexts created) on each web request.
I've solved that to only have one context per request but some of the serialization goes haywire and gets an out of memory exception. Looking at the serialized data, Json.Net is completely ignoring the ReferenceLoopHandling.Ignore enum value for circular reference handling. Note that when I set it to ReferenceLoopHandling.Error, I will get an exception immediately on self-referencing object.
This happens with both Proxies and Lazy loading enabled and disabled.
Full list of settings used for JsonSerializer:
DateFormatHandling = DateFormatHandling.IsoDateFormat,
DateTimeZoneHandling = DateTimeZoneHandling.Local,
Formatting = Formatting.None,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
NullValueHandling = NullValueHandling.Include
Try setting SerializerSettings.PreserveReferencesHandling to PreserveReferencesHandling.Objects, so that references to existing objects are performed using references instead of re-serializing the object.
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()});
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!