Jabrove
Jabrove

Reputation: 863

C# Newtonsoft Deserialize Custom Object with Claims?

I have the following simple POCO:

  public class ApiKey
  {
    public ApiKey(string key, string owner, List<Claim> claims = null)
    {
      Key = key;
      OwnerName = owner;
      Claims = claims ?? new List<Claim>();
    }

    public string Key { get; }
    public string OwnerName { get; }
    public IReadOnlyCollection<Claim> Claims { get; set; }
  }

I can create an instance of this object with one claim, and serialize it with Newtonsoft:

JsonConvert.SerializeObject(key)

And get a serialized ApiKey like this:

"{\"Key\":\"94a5b81f-9837-4c5f-9821-3ebaedc6435d\",\"OwnerName\":null,\"Claims\":[{\"Issuer\":\"LOCAL AUTHORITY\",\"OriginalIssuer\":\"LOCAL AUTHORITY\",\"Properties\":{},\"Subject\":null,\"Type\":\"AdminClaim\",\"Value\":\"AdminClaim\",\"ValueType\":\"http://www.w3.org/2001/XMLSchema#string\"}]}"

However, if try to deserialize that string with Newtonsoft like this:

JsonConvert.DeserializeObject<ApiKey>(serialized_key);

I get the following error:

Newtonsoft.Json.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. Path 'Claims[0].Issuer', line 1, position 83.
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)

When I expect to get back the original object I serialized in the first place. What am I missing to be able to deserialize this object?

Thanks!

EDIT: The Claim object is from System.Security.Claims.Claim.

EDIT 2: I want to be able to serialize/deserialize the entire ApiKey class, not just the claim part.

EDIT 3: I cannot modify the ApiKey class.

Upvotes: 4

Views: 6194

Answers (2)

codernr
codernr

Reputation: 121

You will have to write a custom converter, there is an example for Claim class in this answer: https://stackoverflow.com/a/28155770/6881299

Upvotes: 6

Roman Ryzhiy
Roman Ryzhiy

Reputation: 1646

The problem is that Claim class hasn't any public constructor. The easiest workaround is to create your own Claim class and deserialise into it:

class MyClaim : Claim {
    public MyClaim(string type, string value, string valueType, string issuer, string originalIssuer):
        base(type, value, valueType, issuer, originalIssuer){}
}

Claim claim = JsonConvert.DeserializeObject<MyClaim>(json);

Upvotes: 4

Related Questions