How to pass parameter to constructor deserializing json
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);
}
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 B
s 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 B
s 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