How to pass parameter to constructor deserializing json - c#

I have a small problem with passing some parent instance to a constructor when deserializing an object with Newtonsoft.Json.
Let's assume i have the following classes
public class A
{
public string Str1 { get; set; }
public IList<B> Bs { get; set; }
}
public class B
{
public B(A a)
{
// a should not be null!
Console.WriteLine(a.Str)
}
}
And now i serailze and than deserialize the object a like this:
A a = new A()
a.Bs = new List<B>()
a.Bs.Add(new B(a));
a.Bs.Add(new B(a));
a.Bs.Add(new B(a));
var json = JsonConvert.SerializeObject(a);
// Here i need to call the constructor of B when creating new instances
var newA = JsonConvert.DeserializeObject<A>(json);
The problem is, that when deserializing the object, null will be passed to the constructor of B. Does any one has solved this issue/problem before?
Thank you very much!

In your question and comments you've said that the class B does not have any public property for A. So, when you serialize B, then no A will be written to the JSON, because Json.Net only serializes the public information by default. Therefore, when deserializing, there will not be enough information to recreate B, because there is no A in the JSON. So, step one is making B's reference to A visible to Json.Net. If you don't want to make it public, that is fine, but you will at least need to mark the member with a [JsonProperty] attribute to allow Json.Net to "see" it.
public class B
{
[JsonProperty]
private A a;
public B(A a)
{
this.a = a; // be sure to set the A member in your constructor
}
}
Now if you do the above you will run into a second problem: your class structure has a reference loop (A has a list of Bs which each refer back to A), and the serializer will throw an exception by default in this case. The solution is to set the serializer's PreserveReferencesHandling setting to Objects (the default is None). This will not only allow the serializer to handle the reference loops during serialization, but will also preserve the original references during deserialization, so that all the Bs will refer to the same A instance. (This is accomplished via special $id and $ref properties that are written into the JSON.)
JsonSerializerSettings settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};
var json = JsonConvert.SerializeObject(a, settings);
var newA = JsonConvert.DeserializeObject<A>(json, settings);
Working example: https://dotnetfiddle.net/N0FUID

What I like to do it I have to pass objects in a constructor is to create the object first using my default constructor and then call populate object to set all properties that are not skipped as I decorated the properties with [JsonIgore]
var settings = new JsonSerializerSettings()
{
Error = HandleJsonDeserializationError,
PreserveReferencesHandling = PreserveReferencesHandling.Objects
}
var myObject = new ComplexObject(param1,param2);
JsonConvert.PopulateObject(json, myObject, settings);
You can continue populating objects and deal with any issues if you handle serialisation errors in the JsonSettings property. The signature is as follows:
static void HandleJsonDeserializationError(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs errorArgs)
{
var currentError = errorArgs.ErrorContext.Error.Message;
errorArgs.ErrorContext.Handled = true;
//loging framework logs the error, set brake point etc when debug.
Logger.Log(currentError, LogLevel.Exceptions);
}

Related

Deserializing Circular References by Two-Phase deserialization

I have a Serializer/Deserializer that use a references PreserveReferencesHandling = PreserveReferencesHandling.All.
The issue, is that I have circular references.
Here is a very simple example.
class Node
{
public Node(object value)
{
Value = value;
}
public object Value { get; set; }
public Node Left { get; set; }
public Node Right { get; set; }
}
My test scenario is:
var obj = new Node("o")
{
Left = new Node("oL"),
Right = new Node("oR")
};
obj.Right.Right = obj; // Circular reference!
When I deserialize, i have the following IReferenceResolver
private class InternalReferenceResolver : IReferenceResolver
{
private readonly Deserializer _par;
public InternalReferenceResolver(Deserializer par)
{
_par = par;
}
public object ResolveReference(object context, string reference)
{
object refObject;
if (!_par._processed.TryGetValue(reference, out refObject))
{
refObject = _par.DeserializeObject(reference);
}
return refObject;
}
public string GetReference(object context, object value)
{
throw new NotSupportedException("Only for Serialization");
}
public bool IsReferenced(object context, object value)
{
return false;
}
public void AddReference(object context, string reference, object value)
{
_par._processed.Add(reference, value);
}
}
As you can see, when JSON.NET inform me of a new ref->object (via AddReference()) I add it to a dictionary.
When JSON.NET request an object for a specific reference (via ResolveReference()) I recurse, and deserialize that reference.
The issue is, JSON.NET calls ResolveReference() for each of the object references, before it calls it's AddReference().
I would expect the flow of Deserialization to be:
Identify Object Type
Construct the object
AddReference(id, newObj)
Resolve References + Populate Properties
What I see happens is:
Identify Object Type
Resolve References
Construct the object
AddReference(id, newObj)
Populate Properties
My Questions:
Why is it made the latter, am i missing something with my suggested flow?
how can I overcome this issue, having a "Bare" object just for referencing and only then actually resolve the references ?
The Two-Phase deserialization you are seeing is arises because your Node class only has a parameterized constructor. As explained in Issue with serializing/deserializing object graph with self-referencing objects in combination with JSON constructor. #715:
JamesNK commented on Nov 28, 2015
Non-default constructors and preserving references don't work well together because the child values of a type have to be deserialized before the parent is created, so the reference resolves to null.
Thus, since Value is a mutable property anyway, you should add a parameterless constructor to Node:
class Node
{
public Node() : this(null) { }
public Node(object value)
{
Value = value;
}
// Remainder unchanged.
}
It can be non-public if you mark it with [JsonConstructor] or deserialize using the setting ConstructorHandling.AllowNonPublicDefaultConstructor. And if Value were immutable, you would need to make it privately settable and mark it with [JsonProperty]
[JsonProperty]
public object Value { get; private set; }
(Data contract attributes can be used in place of Json.NET attributes if you prefer.)
Notes:
Since your question lacks a complete and verifiable example, your code might encounter other problems that aren't fixed by adding a parameterless constructor.
For a related question, see Usage of non-default constructor breaks order of deserialization in Json.net.
For a related issue, see PreserveReferencesHandling.Objects deserialize does not work with non-default constructor #678.
Another thing, can I tell Json.NET to only handle the constructor parameters and leave the rest... ?
Not according to Issue 715. Since a JSON object is an unordered set of name/value pairs, Json.NET needs to parse the entire object to ensure it has loaded all the constructor parameters. As it is a single-pass serializer the non-constructor parameters will get loaded into... something... before the object can be constructed. Json.NET has chosen to deserialize them in one step to the final target member type rather than to an intermediate JToken and later the final member type. This can be see in JsonSerializerInternalReader.ResolvePropertyAndCreatorValues().
Well, I Found a solution for my problem:
The first Deserialization i perform, i use a custom IContractResolver that exclude all properties that are not relevant to the constructor...
at the second pass, I use Populate and use the default IContractResolver
private class InternalOnlyCtorContractResolver : IContractResolver
{
private readonly IContractResolver _base;
public InternalOnlyCtorContractResolver(IContractResolver _base)
{
this._base = _base;
}
public JsonContract ResolveContract(Type type)
{
var contract = _base.ResolveContract(type);
var objectContract = contract as JsonObjectContract;
if (objectContract != null)
{
var creatorParameters = new HashSet<string>(objectContract.CreatorParameters.Select(p => p.PropertyName));
var irrelevantProperties = objectContract.Properties
.Where(p => !creatorParameters.Contains(p.PropertyName))
.ToArray();
foreach (var irrelevantProperty in irrelevantProperties)
{
objectContract.Properties.Remove(irrelevantProperty);
}
//TODO Can be optimized better
}
return contract;
}
}
If for some reason, the Circular Reference is needed by the Constructor,
It still cause a loop, but it is kinda impossible to create without having a second constructor anyway.

Making a non-serializable vendor class serializable

I am using a class from a vendor's DLL that is not XML serializable because one of the class members is an Interface.
However, I do need to serialize an instance of the class.
How can I tell the XmlSerializer to ignore the interface and serialize everything else?
You can do 2 things:
1) Create a class with every thing you want, populate it with the your vendor class, then you serialize it.
Check adapter design pattern
2) Use Json.Net. Once I need to serialize the IPagedList that have metadata and I did this:
public static string SerializePagedList(IPagedList<T> pagedList)
{
string result = JsonConvert.SerializeObject(
// new anonymous class with everything I wanted
new
{
Items = pagedList,
MetaData = pagedList.GetMetaData()
},
new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
return result;
}
I hope that it helps.

Use JSON.net Binder/TypeNameHandling for nested types

Using JSON.net, I want to deserialize a list of types that inherit from an abstract class. I have used KnownTypesBinder (source) like
var jsonSettings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
jsonSettings.TypeNameHandling = TypeNameHandling.Auto;
jsonSettings.Binder = new KnownTypesBinder { KnownTypes = new List<Type> { ... } };
Now this works perfectly fine in the WEB API modelbinder; KnownTypesBinder.BindToType is being called an the object can be deserialized. In a different part of the web application I have to deserialize a JSON string, so I would like to re-use the same JsonFormatter. According to the docs, the following should work;
JsonConvert.DeserializeObject<T>(String, JsonSerializerSettings);
However when I do just that:
JsonConvert.DeserializeObject<A>(jsonString, GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings);
The following error is thrown:
JsonSerializationException. Could not create an instance of type C. Type is an interface or abstract class and cannot be instantiated.
My types look something like this;
class A {
public B B { get; set; }
}
class B {
public List<C> C { get; set; }
}
abstract class C { }
class C1: C { }
class C2: C { }
Also creating a new JsonSerializerSettings and setting Binder and TypeNameHandling makes no difference. I found that KnownTypesBinder.BindToType is not being called at all. Is there something in JSON.net that I'm missing?
Feeling stupid here. The discriminator used by JSON.net is called "$type". As I was using curl to send the POST payload, bash tried to resolve $type to an environment variable. As there was no such variable, the final JSON was simply {"": "C"} instead of {"$type": "C"}.

Deserializing object[] that contains primitive types and one class type

I have an object array that contains strings and longs and this class:
public class SimpleMailAddress
{
public string Address { get; set; }
public string Name { get; set; }
public static implicit operator MailAddress(SimpleMailAddress m)
{
return new MailAddress(m.Address, m.Name);
}
}
However, when deserializing the JSON array with Json.Net, I get an anonymous type that contains Address and Name instead of a SimpleMailAddress object.
I don't want to create a strongly-typed object to deserialize into because it will not be reused and I'd have to create a lot of objects for it. Is there a way to do this with Json.Net or any other library?
This is how I'm serializing/deserializing:
var json = JsonConvert.SerializeObject(myObject);
var myObject = JsonConvert.DeserializeObject<MailMessageRequest>(json);
And MailMessageRequest:
public class MailMessageRequest
{
public string Mailer { get; set; }
public string Method { get; set; }
public object[] Args { get; set; }
}
Json does not contain any inherit knowledge about your SimpleMailAddress class. So when you are telling it to deserialize, the fact that your Args property is of type Object, the deserializer is doing the best it can (by creating an anonymous type). It just sees data, it has no knowledge that you want a SimpleMailAddress object.
Json.net has a JObject class. Try using that instead of Object for your Args parameter if the actual contents of Args may change type.
Then, as needed, you can read the data from the JObject object.
If you don't care about the actual contents of Args, then leave it as Object and ignore it.
Edit: JSon.Net can embed type information during serialization that can be used during deserialization.
Leave your Args parameter as an Object. Then use the TypeNameHandling option of All during both serialization and deserialization.
var json = JsonConvert.SerializeObject(myObject, Formatting.None,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
var myObject = JsonConvert.DeserializeObject<MailMessageRequest>(json,
new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });
You should end up with your Args object as your desired SimpleMailAddress object.
The data contact serializers built into the.net framework have the concept of known types where you tell them what types to expect and it uses those during deserialization.
There is a built in Json data contract serializer but I'm not sure it will be compatible with your Json data, it may need to be serialized and deserialized via a datacontract serializer to work using this method.
Got it. I have to use these settings:
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full
};
var json = JsonConvert.SerializeObject(object, Formatting.None, settings);
var object = JsonConvert.DeserializeObject<MailMessageRequest>(message.Body, settings);

c# JavaScriptConverter - how to deserialize custom property?

I've got a class which has been serialized into JSON, and which I'm trying to deserialize into an object.
e.g.
public class ContentItemViewModel
{
public string CssClass { get; set; }
public MyCustomClass PropertyB { get; set; }
}
the simple property (CssClass) will deserialize with:
var contentItemViewModels = ser.Deserialize<ContentItemViewModel>(contentItems);
But PropertyB gets an error...
We added a JavaScriptConverter:
ser.RegisterConverters(new List<JavaScriptConverter>{ publishedStatusResolver});
But when we added 'MyCustomClass' as a 'SupportedType', the Deserialize method was never called. However when we have ContentItemViewModel as the SupportedType, then Deserialize is called.
We've got a current solution which looks something like this:
class ContentItemViewModelConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
var cssClass = GetString(dictionary, "cssClass"); //I'm ommitting the GetString method in this example...
var propertyB= GetString(dictionary, "propertyB");
return new ContentItemViewModel{ CssClass = cssClass ,
PropertyB = new MyCustomClass(propertyB)}
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
throw new Exception("Only does the Deserialize");
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new List<Type>
{
typeof(ContentItemViewModel)
};
}
}
}
But we'd prefer a simpler solution of only deserializing MyCustomClass, as there are a number of other fields which are on the ViewModel, and it seems a waste to have to edit this converter every time we change/add a property....
Is there a way to Deserialize JUST PropertyB of type MyCustomClass?
Thanks for your help!
Have you considered using DatacontractJsonSerializer
[DataContract]
public class MyCustomClass
{
[DataMember]
public string foobar { get; set; }
}
[DataContract]
public class ContentItemViewModel
{
[DataMember]
public string CssClass { get; set; }
[DataMember]
public MyCustomClass PropertyB { get; set; }
}
class Program
{
static void Main(string[] args)
{
ContentItemViewModel model = new ContentItemViewModel();
model.CssClass = "StackOver";
model.PropertyB = new MyCustomClass();
model.PropertyB.foobar = "Flow";
//Create a stream to serialize the object to.
MemoryStream ms = new MemoryStream();
// Serializer the User object to the stream.
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ContentItemViewModel));
ser.WriteObject(ms, model);
byte[] json = ms.ToArray();
ms.Close();
string s= Encoding.UTF8.GetString(json, 0, json.Length);
Console.ReadLine();
}
}
Add all possible classes to DatacontractJsonSerializer.KnownTypes if MyCustomClass has derivations.
For whatever it may be worth after all this time, but I stumbled over the same problem and the solution is that the Deserializer hasn't got a clue about the classes you are deserializing unless you give him the necessary information.
On the top level, it knows the type from the type parameter of Deserialize<>(). That's why your converter for ContentItemViewModel works. For nested objects, it needs __type properties and a JavaScriptTypeResolver.
var ser = new JavaScriptSerializer(new SimpleTypeResolver());
ser.RegisterConverters(myconverters);
MyClass myObject = new MyClass();
string json = ser.Serialize(myObject);
// set a breakpoint here to see what has happened
ser.Deserialize<MyClass>(json);
A TypeResolver adds a __type property to each serialized object. You can write a custom type resolver that uses short names. In this sample, I use the SimpleTypeResolver from .net that "simply" stores the fully qualified type name as __type. When deserializing, the JavaScriptDeserializer finds __type and asks the TypeResolver for the correct type. Then it knows a type and can call a registered JavaScriptConverter.Deserialize method.
Without a TypeResolver, objects are deserialized to a Dictionary because JavaScriptSerializer doesn't have any type information.
If you can't provide a __type property in your json string, I think you'll need to deserialize to Dictionary first and then add a "guessing-step" that interprets the fields to find the right type. Then, you can use the ConvertToType method of JavaScriptSerializer to copy the dictionary into the object's fields and properties.
If you need to use the JavaScriptSerializer that is provides by ASP.NET and can't create your own, consider this section from the .ctor help of JavaScriptSerializer:
The instance of JavaScriptSerializer that is used by the asynchronous communication layer for invoking Web services from client script uses a special type resolver. This type resolver restricts the types that can be deserialized to those defined in the Web service’s method signature, or the ones that have the GenerateScriptTypeAttribute applied. You cannot modify this built-in type resolver programmatically.
Perhaps the GenerateScriptType Attribute can help you. But I don't know what kind of __type Properties are be needed here.

Categories

Resources