Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically choose a constructor during deserialization?

Tags:

c#

json.net

I would like to deserialize a System.Security.Claims.Claim object serialized in the following way:

{     "Issuer" : "LOCAL AUTHORITY",     "OriginalIssuer" : "LOCAL AUTHORITY",     "Type" : "http://my.org/ws/2015/01/identity/claims/mytype",     "Value" : "myvalue",     "ValueType" : "http://www.w3.org/2001/XMLSchema#string" } 

What I get is a JsonSerializationException:

Unable to find a constructor to use for type System.Security.Claims.Claim. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute.

After some investigation I finally understand the meaning of one in the above message: The JSON deserializer cannot find the right constructor as there are - in the case of the Claim type - multiple constructors with arguments (although there exists a constructor with arguments matching exactly the above properties).

Is there a way to tell the deserializer which constructor to choose without adding the JsonConstructor attribute to that mscorlib type?

Daniel Halan has solved this issue with a patch to Json.NET a few years ago. Is there a way to solve this without modifying Json.NET these days?

like image 387
CodeFox Avatar asked Jan 26 '15 17:01

CodeFox


People also ask

Why constructor is not called during DeSerialization in Java?

The deserialization process does not use the object's constructor - the object is instantiated without a constructor and initialized using the serialized instance data.

Does constructor of class gets called during DeSerialization?

Constructors and deserialization When we de-serialize an object, the constructor of its class is never called. Consider the following example, here we have a class named student with two instance variables and a default constructor (initializing with two hardcoded values) and a parameterized constructor.

What is valid about constructor call during DeSerialization process in?

What Is valid about constructor call during DeSerialization process in java? b. if Externalizable has been implemented - constructor is called during DeSerialization process.

How does JSON DeSerialization work?

In Deserialization, it does the opposite of Serialization which means it converts JSON string to custom . Net object. In the following code, it creates a JavaScriptSerializer instance and calls Deserialize() by passing JSON data. It returns a custom object (BlogSites) from JSON data.


1 Answers

If it is not possible to add a [JsonConstructor] attribute to the target class (because you don't own the code), then the usual workaround is to create a custom JsonConverter as was suggested by @James Thorpe in the comments. It is pretty straightforward. You can load the JSON into a JObject, then pick the individual properties out of it to instantiate your Claim instance. Here is the code you would need:

class ClaimConverter : JsonConverter {     public override bool CanConvert(Type objectType)     {         return (objectType == typeof(System.Security.Claims.Claim));     }      public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)     {         JObject jo = JObject.Load(reader);         string type = (string)jo["Type"];         string value = (string)jo["Value"];         string valueType = (string)jo["ValueType"];         string issuer = (string)jo["Issuer"];         string originalIssuer = (string)jo["OriginalIssuer"];         return new Claim(type, value, valueType, issuer, originalIssuer);     }      public override bool CanWrite     {         get { return false; }     }      public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)     {         throw new NotImplementedException();     } } 

To use the converter, simply pass an instance of it to the JsonConvert.DeserializeObject<T>() method call:

Claim claim = JsonConvert.DeserializeObject<Claim>(json, new ClaimConverter()); 

Fiddle: https://dotnetfiddle.net/7LjgGR

like image 200
Brian Rogers Avatar answered Sep 24 '22 00:09

Brian Rogers